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.
@@ -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;