* gnu/packages/patches/gettext-gnulib-multi-core.patch: New file. * gnu/packages/patches/gettext-multi-core.patch: New file. * gnu/packages/gettext.scm (gettext-minimal)[patches]: Add a reference to the two previous patches. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
		
			
				
	
	
		
			185 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
This patch fixes performance problems on multi-core machines
 | 
						|
as reported at <https://bugs.gnu.org/26441>.
 | 
						|
 | 
						|
See commit 1afbcb06fded2a427b761dd1615b1e48e1e853cc in Gettext
 | 
						|
by Bruno Haible <bruno@clisp.org>.
 | 
						|
 | 
						|
diff --git a/gettext-runtime/tests/test-lock.c b/gettext-runtime/tests/test-lock.c
 | 
						|
index d279d1d60..51cec3d6b 100644
 | 
						|
--- a/gettext-runtime/tests/test-lock.c
 | 
						|
+++ b/gettext-runtime/tests/test-lock.c
 | 
						|
@@ -1,5 +1,5 @@
 | 
						|
 /* Test of locking in multithreaded situations.
 | 
						|
-   Copyright (C) 2005, 2008-2016 Free Software Foundation, Inc.
 | 
						|
+   Copyright (C) 2005, 2008-2017 Free Software Foundation, Inc.
 | 
						|
 
 | 
						|
    This program is free software: you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU Lesser General Public License as published by
 | 
						|
@@ -50,6 +50,13 @@
 | 
						|
    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 0, a lock is used to protect these variables.
 | 
						|
+   If set to 1, 'volatile' is used; this is theoretically equivalent but can
 | 
						|
+   lead to much slower execution (e.g. 30x slower total run time on a 40-core
 | 
						|
+   machine.  */
 | 
						|
+#define USE_VOLATILE 0
 | 
						|
+
 | 
						|
 /* Whether to print debugging messages.  */
 | 
						|
 #define ENABLE_DEBUGGING 0
 | 
						|
 
 | 
						|
@@ -214,6 +221,51 @@ static inline void * gl_thread_self_pointer (void)
 | 
						|
 # define yield()
 | 
						|
 #endif
 | 
						|
 
 | 
						|
+#if USE_VOLATILE
 | 
						|
+struct atomic_int {
 | 
						|
+  volatile int value;
 | 
						|
+};
 | 
						|
+static void
 | 
						|
+init_atomic_int (struct atomic_int *ai)
 | 
						|
+{
 | 
						|
+}
 | 
						|
+static int
 | 
						|
+get_atomic_int_value (struct atomic_int *ai)
 | 
						|
+{
 | 
						|
+  return ai->value;
 | 
						|
+}
 | 
						|
+static void
 | 
						|
+set_atomic_int_value (struct atomic_int *ai, int new_value)
 | 
						|
+{
 | 
						|
+  ai->value = new_value;
 | 
						|
+}
 | 
						|
+#else
 | 
						|
+struct atomic_int {
 | 
						|
+  gl_lock_define (, lock)
 | 
						|
+  int value;
 | 
						|
+};
 | 
						|
+static void
 | 
						|
+init_atomic_int (struct atomic_int *ai)
 | 
						|
+{
 | 
						|
+  gl_lock_init (ai->lock);
 | 
						|
+}
 | 
						|
+static int
 | 
						|
+get_atomic_int_value (struct atomic_int *ai)
 | 
						|
+{
 | 
						|
+  gl_lock_lock (ai->lock);
 | 
						|
+  int ret = ai->value;
 | 
						|
+  gl_lock_unlock (ai->lock);
 | 
						|
+  return ret;
 | 
						|
+}
 | 
						|
+static void
 | 
						|
+set_atomic_int_value (struct atomic_int *ai, int new_value)
 | 
						|
+{
 | 
						|
+  gl_lock_lock (ai->lock);
 | 
						|
+  ai->value = new_value;
 | 
						|
+  gl_lock_unlock (ai->lock);
 | 
						|
+}
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 #define ACCOUNT_COUNT 4
 | 
						|
 
 | 
						|
 static int account[ACCOUNT_COUNT];
 | 
						|
@@ -281,12 +333,12 @@ lock_mutator_thread (void *arg)
 | 
						|
   return NULL;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static volatile int lock_checker_done;
 | 
						|
+static struct atomic_int lock_checker_done;
 | 
						|
 
 | 
						|
 static void *
 | 
						|
 lock_checker_thread (void *arg)
 | 
						|
 {
 | 
						|
-  while (!lock_checker_done)
 | 
						|
+  while (get_atomic_int_value (&lock_checker_done) == 0)
 | 
						|
     {
 | 
						|
       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
 | 
						|
       gl_lock_lock (my_lock);
 | 
						|
@@ -311,7 +363,8 @@ test_lock (void)
 | 
						|
   /* Initialization.  */
 | 
						|
   for (i = 0; i < ACCOUNT_COUNT; i++)
 | 
						|
     account[i] = 1000;
 | 
						|
-  lock_checker_done = 0;
 | 
						|
+  init_atomic_int (&lock_checker_done);
 | 
						|
+  set_atomic_int_value (&lock_checker_done, 0);
 | 
						|
 
 | 
						|
   /* Spawn the threads.  */
 | 
						|
   checkerthread = gl_thread_create (lock_checker_thread, NULL);
 | 
						|
@@ -321,7 +374,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_atomic_int_value (&lock_checker_done, 1);
 | 
						|
   gl_thread_join (checkerthread, NULL);
 | 
						|
   check_accounts ();
 | 
						|
 }
 | 
						|
@@ -365,12 +418,12 @@ rwlock_mutator_thread (void *arg)
 | 
						|
   return NULL;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static volatile int rwlock_checker_done;
 | 
						|
+static struct atomic_int rwlock_checker_done;
 | 
						|
 
 | 
						|
 static void *
 | 
						|
 rwlock_checker_thread (void *arg)
 | 
						|
 {
 | 
						|
-  while (!rwlock_checker_done)
 | 
						|
+  while (get_atomic_int_value (&rwlock_checker_done) == 0)
 | 
						|
     {
 | 
						|
       dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
 | 
						|
       gl_rwlock_rdlock (my_rwlock);
 | 
						|
@@ -395,7 +448,8 @@ test_rwlock (void)
 | 
						|
   /* Initialization.  */
 | 
						|
   for (i = 0; i < ACCOUNT_COUNT; i++)
 | 
						|
     account[i] = 1000;
 | 
						|
-  rwlock_checker_done = 0;
 | 
						|
+  init_atomic_int (&rwlock_checker_done);
 | 
						|
+  set_atomic_int_value (&rwlock_checker_done, 0);
 | 
						|
 
 | 
						|
   /* Spawn the threads.  */
 | 
						|
   for (i = 0; i < THREAD_COUNT; i++)
 | 
						|
@@ -406,7 +460,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_atomic_int_value (&rwlock_checker_done, 1);
 | 
						|
   for (i = 0; i < THREAD_COUNT; i++)
 | 
						|
     gl_thread_join (checkerthreads[i], NULL);
 | 
						|
   check_accounts ();
 | 
						|
@@ -467,12 +521,12 @@ reclock_mutator_thread (void *arg)
 | 
						|
   return NULL;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static volatile int reclock_checker_done;
 | 
						|
+static struct atomic_int reclock_checker_done;
 | 
						|
 
 | 
						|
 static void *
 | 
						|
 reclock_checker_thread (void *arg)
 | 
						|
 {
 | 
						|
-  while (!reclock_checker_done)
 | 
						|
+  while (get_atomic_int_value (&reclock_checker_done) == 0)
 | 
						|
     {
 | 
						|
       dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
 | 
						|
       gl_recursive_lock_lock (my_reclock);
 | 
						|
@@ -497,7 +551,8 @@ test_recursive_lock (void)
 | 
						|
   /* Initialization.  */
 | 
						|
   for (i = 0; i < ACCOUNT_COUNT; i++)
 | 
						|
     account[i] = 1000;
 | 
						|
-  reclock_checker_done = 0;
 | 
						|
+  init_atomic_int (&reclock_checker_done);
 | 
						|
+  set_atomic_int_value (&reclock_checker_done, 0);
 | 
						|
 
 | 
						|
   /* Spawn the threads.  */
 | 
						|
   checkerthread = gl_thread_create (reclock_checker_thread, NULL);
 | 
						|
@@ -507,7 +562,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_atomic_int_value (&reclock_checker_done, 1);
 | 
						|
   gl_thread_join (checkerthread, NULL);
 | 
						|
   check_accounts ();
 | 
						|
 }
 |