This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gomp3] Use private futexes if possible


Hi!

All futexes used explicitly in libgomp are process private,
and when kernel supports it (2.6.22 and higher), using private futexes
gives measurable speedups, on the attached microbenchmark primarily
on the parallel bench, single bench and static bench.
Similar speedups can be seen on EPCC microbenchmark.
If the kernel doesn't support FUTEX_PRIVATE_FLAG, the futex syscalls
should return ENOSYS error and libgomp should fall back to normal
futexes.

OMP_SCHEDULE=static,1 GOMP_BLOCKTIME=infinity LD_LIBRARY_PATH=~/libgomp-vanilla/ ./micro
barrier bench 0.993256 seconds
parallel bench 0.693095 seconds
static bench 0.0363882 seconds
dynamic bench 0.182232 seconds
guided bench 0.000468774 seconds
runtime bench 0.0134134 seconds
single bench 1.47163 seconds
OMP_SCHEDULE=static,1 GOMP_BLOCKTIME=infinity LD_LIBRARY_PATH=~/libgomp-privatefutex/ ./micro
barrier bench 0.990152 seconds
parallel bench 0.563748 seconds
static bench 0.0314544 seconds
dynamic bench 0.182004 seconds
guided bench 0.000466495 seconds
runtime bench 0.0133739 seconds
single bench 1.09475 seconds

Regtested on x86_64-linux, i686-linux and ppc-linux.

2008-03-19  Jakub Jelinek  <jakub@redhat.com>

	* config/linux/wait.h: Include errno.h.
	(FUTEX_WAIT, FUTEX_WAKE, FUTEX_PRIVATE_FLAG): Define.
	(gomp_futex_wake, gomp_futex_wait): New extern decls.
	* config/linux/mutex.c (gomp_futex_wake, gomp_futex_wait): New
	variables.
	* config/linux/powerpc/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
	(sys_futex0): Return error code.
	(futex_wake, futex_wait): If ENOSYS was returned, clear
	FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
	* config/linux/alpha/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
	(futex_wake, futex_wait): If ENOSYS was returned, clear
	FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
	* config/linux/x86/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
	(sys_futex0): Return error code.
	(futex_wake, futex_wait): If ENOSYS was returned, clear
	FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
	* config/linux/s390/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
	(sys_futex0): Return error code.
	(futex_wake, futex_wait): If ENOSYS was returned, clear
	FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
	* config/linux/ia64/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
	(sys_futex0): Return error code.
	(futex_wake, futex_wait): If ENOSYS was returned, clear
	FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.
	* config/linux/sparc/futex.h (FUTEX_WAIT, FUTEX_WAKE): Remove.
	(sys_futex0): Return error code.
	(futex_wake, futex_wait): If ENOSYS was returned, clear
	FUTEX_PRIVATE_FLAG in gomp_futex_wa{ke,it} and retry.

--- libgomp/config/linux/powerpc/futex.h	(revision 133291)
+++ libgomp/config/linux/powerpc/futex.h	(working copy)
@@ -28,10 +28,8 @@
 /* Provide target-specific access to the futex system call.  */
 
 #include <sys/syscall.h>
-#define FUTEX_WAIT	0
-#define FUTEX_WAKE	1
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   register long int r0  __asm__ ("r0");
@@ -50,23 +48,38 @@ sys_futex0 (int *addr, int op, int val)
      doesn't.  It doesn't much matter for us.  In the interest of unity,
      go ahead and clobber it always.  */
 
-  __asm volatile ("sc"
+  __asm volatile ("sc; mfcr %0"
 		  : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6)
 		  : "r"(r0), "r"(r3), "r"(r4), "r"(r5), "r"(r6)
 		  : "r7", "r8", "r9", "r10", "r11", "r12",
 		    "cr0", "ctr", "memory");
+  if (__builtin_expect (r0 & (1 << 28), 0))
+    return r3;
+  return 0;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
 }
 
 static inline void
--- libgomp/config/linux/mutex.c	(revision 133291)
+++ libgomp/config/linux/mutex.c	(working copy)
@@ -31,6 +31,8 @@
 
 #include "wait.h"
 
+long int gomp_futex_wake = FUTEX_WAKE | FUTEX_PRIVATE_FLAG;
+long int gomp_futex_wait = FUTEX_WAIT | FUTEX_PRIVATE_FLAG;
 
 void
 gomp_mutex_lock_slow (gomp_mutex_t *mutex)
--- libgomp/config/linux/alpha/futex.h	(revision 133291)
+++ libgomp/config/linux/alpha/futex.h	(working copy)
@@ -30,8 +30,6 @@
 #ifndef SYS_futex
 #define SYS_futex               394
 #endif
-#define FUTEX_WAIT              0
-#define FUTEX_WAKE              1
 
 
 static inline void
@@ -45,7 +43,7 @@ futex_wait (int *addr, int val)
 
   sc_0 = SYS_futex;
   sc_16 = (long) addr;
-  sc_17 = FUTEX_WAIT;
+  sc_17 = gomp_futex_wait;
   sc_18 = val;
   sc_19 = 0;
   __asm volatile ("callsys"
@@ -53,6 +51,20 @@ futex_wait (int *addr, int val)
 		  : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18), "1"(sc_19)
 		  : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
 		    "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+  if (__builtin_expect (sc_19, 0) && sc_0 == ENOSYS)
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sc_0 = SYS_futex;
+      sc_17 &= ~FUTEX_PRIVATE_FLAG;
+      sc_19 = 0;
+      __asm volatile ("callsys"
+		      : "=r" (sc_0), "=r"(sc_19)
+		      : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18),
+			"1"(sc_19)
+		      : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+			"$22", "$23", "$24", "$25", "$27", "$28", "memory");
+    }
 }
 
 static inline void
@@ -66,13 +78,25 @@ futex_wake (int *addr, int count)
 
   sc_0 = SYS_futex;
   sc_16 = (long) addr;
-  sc_17 = FUTEX_WAKE;
+  sc_17 = gomp_futex_wake;
   sc_18 = count;
   __asm volatile ("callsys"
 		  : "=r" (sc_0), "=r"(sc_19)
 		  : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18)
 		  : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
 		    "$22", "$23", "$24", "$25", "$27", "$28", "memory");
+  if (__builtin_expect (sc_19, 0) && sc_0 == ENOSYS)
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sc_0 = SYS_futex;
+      sc_17 &= ~FUTEX_PRIVATE_FLAG;
+      __asm volatile ("callsys"
+		      : "=r" (sc_0), "=r"(sc_19)
+		      : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18)
+		      : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+			"$22", "$23", "$24", "$25", "$27", "$28", "memory");
+    }
 }
 
 static inline void
--- libgomp/config/linux/x86/futex.h	(revision 133291)
+++ libgomp/config/linux/x86/futex.h	(working copy)
@@ -27,9 +27,6 @@
 
 /* Provide target-specific access to the futex system call.  */
 
-#define FUTEX_WAIT	0
-#define FUTEX_WAKE	1
-
 #ifdef __LP64__
 # ifndef SYS_futex
 #  define SYS_futex	202
@@ -38,14 +35,26 @@
 static inline void
 futex_wait (int *addr, int val)
 {
-  register long r10 __asm__("%r10") = 0;
+  register long r10 __asm__("%r10");
   long res;
 
+  r10 = 0;
   __asm volatile ("syscall"
 		  : "=a" (res)
-		  : "0"(SYS_futex), "D" (addr), "S"(FUTEX_WAIT),
-		    "d"(val), "r"(r10)
+		  : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wait),
+		    "d" (val), "r" (r10)
 		  : "r11", "rcx", "memory");
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      r10 = 0;
+      __asm volatile ("syscall"
+		      : "=a" (res)
+		      : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wait),
+			"d" (val), "r" (r10)
+		      : "r11", "rcx", "memory");
+    }
 }
 
 static inline void
@@ -55,8 +64,19 @@ futex_wake (int *addr, int count)
 
   __asm volatile ("syscall"
 		  : "=a" (res)
-		  : "0"(SYS_futex), "D" (addr), "S"(FUTEX_WAKE), "d"(count)
+		  : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wake),
+		    "d" (count)
 		  : "r11", "rcx", "memory");
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      __asm volatile ("syscall"
+		      : "=a" (res)
+		      : "0" (SYS_futex), "D" (addr), "S" (gomp_futex_wake),
+			"d" (count)
+		      : "r11", "rcx", "memory");
+    }
 }
 #else
 # ifndef SYS_futex
@@ -65,7 +85,7 @@ futex_wake (int *addr, int count)
 
 # ifdef __PIC__
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   long res;
@@ -77,11 +97,12 @@ sys_futex0 (int *addr, int op, int val)
 		  : "0"(SYS_futex), "r" (addr), "c"(op),
 		    "d"(val), "S"(0)
 		  : "memory");
+  return res;
 }
 
 # else
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   long res;
@@ -91,6 +112,7 @@ sys_futex0 (int *addr, int op, int val)
 		  : "0"(SYS_futex), "b" (addr), "c"(op),
 		    "d"(val), "S"(0)
 		  : "memory");
+  return res;
 }
 
 # endif /* __PIC__ */
@@ -98,13 +120,25 @@ sys_futex0 (int *addr, int op, int val)
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long res = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long res = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (res == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
 }
 
 #endif /* __LP64__ */
--- libgomp/config/linux/wait.h	(revision 133291)
+++ libgomp/config/linux/wait.h	(working copy)
@@ -33,6 +33,18 @@
 #define GOMP_WAIT_H 1
 
 #include "libgomp.h"
+#include <errno.h>
+
+#define FUTEX_WAIT	0
+#define FUTEX_WAKE	1
+#define FUTEX_PRIVATE_FLAG	128L
+
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility push(hidden)
+#endif
+
+extern long int gomp_futex_wait, gomp_futex_wake;
+
 #include "futex.h"
 
 static inline void do_wait (int *addr, int val)
@@ -47,4 +59,8 @@ static inline void do_wait (int *addr, i
   futex_wait (addr, val);
 }
 
+#ifdef HAVE_ATTRIBUTE_VISIBILITY
+# pragma GCC visibility pop
+#endif
+
 #endif /* GOMP_WAIT_H */
--- libgomp/config/linux/s390/futex.h	(revision 133291)
+++ libgomp/config/linux/s390/futex.h	(working copy)
@@ -28,10 +28,8 @@
 /* Provide target-specific access to the futex system call.  */
 
 #include <sys/syscall.h>
-#define FUTEX_WAIT	0
-#define FUTEX_WAKE	1
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   register long int gpr2  __asm__ ("2");
@@ -49,18 +47,31 @@ sys_futex0 (int *addr, int op, int val)
 		  : "i" (SYS_futex),
 		    "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5)
 		  : "memory");
+  return gpr2;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == -ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
 }
 
 static inline void
--- libgomp/config/linux/ia64/futex.h	(revision 133291)
+++ libgomp/config/linux/ia64/futex.h	(working copy)
@@ -29,23 +29,24 @@
 
 #include <sys/syscall.h>
 
-#define FUTEX_WAIT	0
-#define FUTEX_WAKE	1
 
 
-static inline void
-sys_futex0(int *addr, int op, int val)
+static inline long
+sys_futex0(int *addr, long op, int val)
 {
   register long out0 asm ("out0") = (long) addr;
   register long out1 asm ("out1") = op;
   register long out2 asm ("out2") = val;
   register long out3 asm ("out3") = 0;
+  register long r8 asm ("r8");
+  register long r10 asm ("r10");
   register long r15 asm ("r15") = SYS_futex;
 
   __asm __volatile ("break 0x100000"
-	: "=r"(r15), "=r"(out0), "=r"(out1), "=r"(out2), "=r"(out3)
+	: "=r"(r15), "=r"(out0), "=r"(out1), "=r"(out2), "=r"(out3),
+	  "=r"(r8), "=r"(r10)
 	: "r"(r15), "r"(out0), "r"(out1), "r"(out2), "r"(out3)
-        : "memory", "r8", "r10", "out4", "out5", "out6", "out7",
+	: "memory", "out4", "out5", "out6", "out7",
 	  /* Non-stacked integer registers, minus r8, r10, r15.  */
 	  "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18",
 	  "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",
@@ -56,18 +57,31 @@ sys_futex0(int *addr, int op, int val)
 	  "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
 	  /* Branch registers.  */
 	  "b6");
+  return r8 & r10;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
 }
 
 static inline void
--- libgomp/config/linux/sparc/futex.h	(revision 133291)
+++ libgomp/config/linux/sparc/futex.h	(working copy)
@@ -28,10 +28,8 @@
 /* Provide target-specific access to the futex system call.  */
 
 #include <sys/syscall.h>
-#define FUTEX_WAIT	0
-#define FUTEX_WAKE	1
 
-static inline void
+static inline long
 sys_futex0 (int *addr, int op, int val)
 {
   register long int g1  __asm__ ("g1");
@@ -47,9 +45,9 @@ sys_futex0 (int *addr, int op, int val)
   o3 = 0;
 
 #ifdef __arch64__
-# define SYSCALL_STRING "ta\t0x6d"
+# define SYSCALL_STRING "ta\t0x6d; bcs,a,pt %%xcc, 1f; sub %%g0, %%o0, %%o0; 1:"
 #else
-# define SYSCALL_STRING "ta\t0x10"
+# define SYSCALL_STRING "ta\t0x10; bcs,a 1f; sub %%g0, %%o0, %%o0; 1:"
 #endif
 
   __asm volatile (SYSCALL_STRING
@@ -65,18 +63,31 @@ sys_futex0 (int *addr, int op, int val)
 		    "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
 #endif
 		    "cc", "memory");
+  return o0;
 }
 
 static inline void
 futex_wait (int *addr, int val)
 {
-  sys_futex0 (addr, FUTEX_WAIT, val);
+  long err = sys_futex0 (addr, gomp_futex_wait, val);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wait, val);
+    }
 }
 
 static inline void
 futex_wake (int *addr, int count)
 {
-  sys_futex0 (addr, FUTEX_WAKE, count);
+  long err = sys_futex0 (addr, gomp_futex_wake, count);
+  if (__builtin_expect (err == ENOSYS, 0))
+    {
+      gomp_futex_wait &= ~FUTEX_PRIVATE_FLAG;
+      gomp_futex_wake &= ~FUTEX_PRIVATE_FLAG;
+      sys_futex0 (addr, gomp_futex_wake, count);
+    }
 }
 
 static inline void

	Jakub

Attachment: micro.c
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]