Pádraig Brady wrote:
> There was a recent enough report on helgrind reporting issues with it:
> https://lists.gnu.org/archive/html/bug-gnulib/2015-07/msg00032.html

I would view this as a false positive. The test uses some 'volatile'
variables to communicate among threads, and 'valgrind --tool=helgrind'
does not know about it. There are no mentions of 'volatile' in the
helgrind documentation http://valgrind.org/docs/manual/hg-manual.html,
and there are similar reports at
https://sourceforge.net/p/valgrind/mailman/valgrind-users/thread/5038A955.6060108%40acm.org/#msg29721076

> I've seen this test take a minute or so on a 40 core system.

The running time is a different problem. I observe a long running time
with "#define EXPLICIT_YIELD 0". But the default is "#define EXPLICIT_YIELD 1".

When I use the attached patch to avoid the use of 'volatile' and replace it
by a lock, like explained in
http://stackoverflow.com/questions/10091112/using-a-global-variable-to-control-a-while-loop-in-a-separate-thread,
it does not change the run time that I observe on a 4-core system:

$ time ./test-lock 
Starting test_lock ... OK
Starting test_rwlock ... OK
Starting test_recursive_lock ... OK
Starting test_once ... OK

real    0m1.770s
user    0m1.240s
sys     0m10.268s

Can someone test how this looks like on a 40-core system?

Bruno
diff --git a/tests/test-lock.c b/tests/test-lock.c
index cb734b4..f4c14f2 100644
--- a/tests/test-lock.c
+++ b/tests/test-lock.c
@@ -50,6 +50,11 @@
    Uncomment this to see if the operating system has a fair scheduler.  */
 #define EXPLICIT_YIELD 1
 
+/* Whether to use 'volatile' on some variables that communicate information
+   between threads.  If set to zero, a lock is used to protect these variables,
+   rather than 'volatile'.  */
+#define USE_VOLATILE 0
+
 /* Whether to print debugging messages.  */
 #define ENABLE_DEBUGGING 0
 
@@ -170,12 +175,38 @@ lock_mutator_thread (void *arg)
   return NULL;
 }
 
+#if USE_VOLATILE
 static volatile int lock_checker_done;
+static int is_lock_checker_done()
+{
+  return lock_checker_done;
+}
+static void set_lock_checker_done()
+{
+  lock_checker_done = 1;
+}
+#else
+static int lock_checker_done;
+gl_lock_define_initialized(static, lock_checker_done_lock)
+static int is_lock_checker_done()
+{
+  gl_lock_lock (lock_checker_done_lock);
+  int result = lock_checker_done;
+  gl_lock_unlock (lock_checker_done_lock);
+  return result;
+}
+static void set_lock_checker_done()
+{
+  gl_lock_lock (lock_checker_done_lock);
+  lock_checker_done = 1;
+  gl_lock_unlock (lock_checker_done_lock);
+}
+#endif
 
 static void *
 lock_checker_thread (void *arg)
 {
-  while (!lock_checker_done)
+  while (! is_lock_checker_done ())
     {
       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
       gl_lock_lock (my_lock);
@@ -210,7 +241,7 @@ test_lock (void)
   /* Wait for the threads to terminate.  */
   for (i = 0; i < THREAD_COUNT; i++)
     gl_thread_join (threads[i], NULL);
-  lock_checker_done = 1;
+  set_lock_checker_done ();
   gl_thread_join (checkerthread, NULL);
   check_accounts ();
 }
@@ -254,12 +285,38 @@ rwlock_mutator_thread (void *arg)
   return NULL;
 }
 
+#if USE_VOLATILE
 static volatile int rwlock_checker_done;
+static int is_rwlock_checker_done()
+{
+  return rwlock_checker_done;
+}
+static void set_rwlock_checker_done()
+{
+  rwlock_checker_done = 1;
+}
+#else
+static int rwlock_checker_done;
+gl_lock_define_initialized(static, rwlock_checker_done_lock)
+static int is_rwlock_checker_done()
+{
+  gl_lock_lock (rwlock_checker_done_lock);
+  int result = rwlock_checker_done;
+  gl_lock_unlock (rwlock_checker_done_lock);
+  return result;
+}
+static void set_rwlock_checker_done()
+{
+  gl_lock_lock (rwlock_checker_done_lock);
+  rwlock_checker_done = 1;
+  gl_lock_unlock (rwlock_checker_done_lock);
+}
+#endif
 
 static void *
 rwlock_checker_thread (void *arg)
 {
-  while (!rwlock_checker_done)
+  while (! is_rwlock_checker_done ())
     {
       dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
       gl_rwlock_rdlock (my_rwlock);
@@ -295,7 +352,7 @@ test_rwlock (void)
   /* Wait for the threads to terminate.  */
   for (i = 0; i < THREAD_COUNT; i++)
     gl_thread_join (threads[i], NULL);
-  rwlock_checker_done = 1;
+  set_rwlock_checker_done ();
   for (i = 0; i < THREAD_COUNT; i++)
     gl_thread_join (checkerthreads[i], NULL);
   check_accounts ();
@@ -356,12 +413,38 @@ reclock_mutator_thread (void *arg)
   return NULL;
 }
 
+#if USE_VOLATILE
 static volatile int reclock_checker_done;
+static int is_reclock_checker_done()
+{
+  return reclock_checker_done;
+}
+static void set_reclock_checker_done()
+{
+  reclock_checker_done = 1;
+}
+#else
+static int reclock_checker_done;
+gl_lock_define_initialized(static, reclock_checker_done_lock)
+static int is_reclock_checker_done()
+{
+  gl_lock_lock (reclock_checker_done_lock);
+  int result = reclock_checker_done;
+  gl_lock_unlock (reclock_checker_done_lock);
+  return result;
+}
+static void set_reclock_checker_done()
+{
+  gl_lock_lock (reclock_checker_done_lock);
+  reclock_checker_done = 1;
+  gl_lock_unlock (reclock_checker_done_lock);
+}
+#endif
 
 static void *
 reclock_checker_thread (void *arg)
 {
-  while (!reclock_checker_done)
+  while (! is_reclock_checker_done ())
     {
       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
       gl_recursive_lock_lock (my_reclock);
@@ -396,7 +479,7 @@ test_recursive_lock (void)
   /* Wait for the threads to terminate.  */
   for (i = 0; i < THREAD_COUNT; i++)
     gl_thread_join (threads[i], NULL);
-  reclock_checker_done = 1;
+  set_reclock_checker_done ();
   gl_thread_join (checkerthread, NULL);
   check_accounts ();
 }

Reply via email to