diff mbox

tst-malloc-thread-exit: Improve scalability of thread creation

Message ID 567AA549.20403@redhat.com
State New
Headers show

Commit Message

Florian Weimer Dec. 23, 2015, 1:44 p.m. UTC
Previously, the thread could time out on large NUMA machines
where thread creation is particularly expensive because
outer and inner thread creation competed for resources, and
outer thread creation would still run when the timeout hits.

Florian
diff mbox

Patch

2015-12-23  Florian Weimer  <fweimer@redhat.com>

	Improve tst-malloc-thread-exit scalability.
	* malloc/tst-malloc-thread-exit.c (outer_barrier)
	(threads_created_mutex, threads_created): New variables.
	(outer_thread): Wait on outer_barrier.  Update threads_created.
	(do_test): Initialize outer_barrier and wait on it after outer
	thread creation.  Print diagnostics and the number of inner
	threads created.

diff --git a/malloc/tst-malloc-thread-exit.c b/malloc/tst-malloc-thread-exit.c
index da7297e..5fffc32 100644
--- a/malloc/tst-malloc-thread-exit.c
+++ b/malloc/tst-malloc-thread-exit.c
@@ -87,6 +87,16 @@  wait_first_thread (void * closure)
   return NULL;
 }
 
+/* Used to pause outer threads after initialization.  This ensures
+   that creation of outer threads does not compete for resources with
+   the actual testing with inner threads.  */
+static pthread_barrier_t outer_barrier;
+
+/* Total count of inner threads created.  Updated at the end of each
+   outer thread.  */
+static pthread_mutex_t threads_created_mutex = PTHREAD_MUTEX_INITIALIZER;
+static unsigned long long threads_created;
+
 static void *
 outer_thread (void *closure)
 {
@@ -97,6 +107,18 @@  outer_thread (void *closure)
       abort ();
     }
 
+  /* Wait until all outer threads have been created.  */
+  {
+    int ret = pthread_barrier_wait (&outer_barrier);
+    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+      {
+          errno = ret;
+          printf ("pthread_barrier_wait (&outer_barrier): %m\n");
+          abort ();
+      }
+  }
+
+  unsigned long long threads_created_local = 0;
   while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
     {
       pthread_barrier_t barrier;
@@ -121,6 +143,7 @@  outer_thread (void *closure)
               printf ("error: pthread_create: %m\n");
               abort ();
             }
+          ++threads_created_local;
         }
       ret = pthread_barrier_wait (&barrier);
       if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
@@ -150,6 +173,23 @@  outer_thread (void *closure)
 
   free (threads);
 
+  int ret = pthread_mutex_lock (&threads_created_mutex);
+  if (ret != 0)
+    {
+      ret = errno;
+      printf ("pthread_mutex_lock: %m\n");
+      abort ();
+    }
+
+  threads_created += threads_created_local;
+  ret = pthread_mutex_unlock (&threads_created_mutex);
+  if (ret != 0)
+    {
+      ret = errno;
+      printf ("pthread_mutex_unlock: %m\n");
+      abort ();
+    }
+
   return NULL;
 }
 
@@ -178,6 +218,18 @@  do_test (void)
       abort ();
     }
 
+  /* Initialize barrier to serialize outer thread creation.  */
+  {
+    int ret = pthread_barrier_init (&outer_barrier, NULL,
+                                    outer_thread_count + 1);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_init: %m\n");
+        abort ();
+      }
+  }
+
   for (long i = 0; i < outer_thread_count; ++i)
     {
       int ret = pthread_create (threads + i, NULL, outer_thread, NULL);
@@ -189,6 +241,21 @@  do_test (void)
         }
     }
 
+  printf ("info: %ld outer threads have been started\n", outer_thread_count);
+
+  {
+    int ret = pthread_barrier_wait (&outer_barrier);
+    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+      {
+          errno = ret;
+          printf ("pthread_barrier_wait (&outer_barrier): %m\n");
+          abort ();
+      }
+  }
+
+  printf ("info: %ld outer threads have completed initialization\n",
+          outer_thread_count);
+
   struct timespec ts = {timeout, 0};
   if (nanosleep (&ts, NULL))
     {
@@ -208,6 +275,20 @@  do_test (void)
           abort ();
         }
     }
+
+  printf ("info: total number of threads created: %llu\n",
+          threads_created);
+
+  {
+    int ret = pthread_barrier_destroy (&outer_barrier);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_destroy: %m\n");
+        abort ();
+      }
+  }
+
   free (threads);
 
   return 0;