Set thread affinity with +RTS -qa (only on Linux so far)
authorSimon Marlow <marlowsd@gmail.com>
Wed, 18 Mar 2009 15:47:19 +0000 (15:47 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Wed, 18 Mar 2009 15:47:19 +0000 (15:47 +0000)
configure.ac
includes/OSThreads.h
includes/RtsFlags.h
rts/RtsFlags.c
rts/Schedule.c
rts/posix/OSThreads.c
rts/win32/OSThreads.c

index 85e0617..4067335 100644 (file)
@@ -1029,7 +1029,7 @@ dnl    off_t, because it will affect the result of that test.
 AC_SYS_LARGEFILE
 
 dnl ** check for specific header (.h) files that we are interested in
-AC_CHECK_HEADERS([bfd.h ctype.h dirent.h dlfcn.h errno.h fcntl.h grp.h limits.h locale.h nlist.h pthread.h pwd.h signal.h sys/mman.h sys/resource.h sys/time.h sys/timeb.h sys/timers.h sys/times.h sys/utsname.h sys/wait.h termios.h time.h utime.h windows.h winsock.h])
+AC_CHECK_HEADERS([bfd.h ctype.h dirent.h dlfcn.h errno.h fcntl.h grp.h limits.h locale.h nlist.h pthread.h pwd.h signal.h sys/mman.h sys/resource.h sys/time.h sys/timeb.h sys/timers.h sys/times.h sys/utsname.h sys/wait.h termios.h time.h utime.h windows.h winsock.h sched.h])
 
 dnl ** check if it is safe to include both <time.h> and <sys/time.h>
 AC_HEADER_TIME
@@ -1107,7 +1107,7 @@ fi
 
 dnl ** check for more functions
 dnl ** The following have been verified to be used in ghc/, but might be used somewhere else, too.
-AC_CHECK_FUNCS([getclock getrusage gettimeofday setitimer siginterrupt sysconf times ctime_r])
+AC_CHECK_FUNCS([getclock getrusage gettimeofday setitimer siginterrupt sysconf times ctime_r, sched_setaffinity])
 
 AC_TRY_RUN([
 #include <sys/types.h>
index 73ef4d2..f5c434f 100644 (file)
@@ -186,8 +186,8 @@ void  setThreadLocalVar (ThreadLocalKey *key, void *value);
 void  freeThreadLocalKey (ThreadLocalKey *key);
 
 // Processors and affinity
-nat getNumberOfProcessors (void);
-
+nat  getNumberOfProcessors (void);
+void setThreadAffinity     (nat n, nat m);
 #endif // !CMINUSMINUS
 
 #else
index 7709787..348a8f5 100644 (file)
@@ -192,6 +192,7 @@ struct PAR_FLAGS {
   rtsBool        parGcGen;       /* do parallel GC in this generation
                                   * and higher only */
   rtsBool        parGcLoadBalancing; /* do load-balancing in parallel GC */
+  rtsBool        setAffinity;    /* force thread affinity with CPUs */
 };
 #endif /* THREADED_RTS */
 
index 3fac86b..6a8c692 100644 (file)
@@ -233,6 +233,7 @@ void initRtsFlagsDefaults(void)
     RtsFlags.ParFlags.parGcEnabled      = 1;
     RtsFlags.ParFlags.parGcGen          = 1;
     RtsFlags.ParFlags.parGcLoadBalancing = 1;
+    RtsFlags.ParFlags.setAffinity       = 0;
 #endif
 
 #ifdef PAR
@@ -476,6 +477,8 @@ usage_text[] = {
 "  -N        Determine the number of processors to use automatically",
 "  -q1       Use one OS thread for GC (turns off parallel GC)",
 "  -qg<n>    Use parallel GC only for generations >= <n> (default: 1)",
+"  -qb       Disable load-balancing in the parallel GC",
+"  -qa       Use the OS to set thread affinity",
 "  -qm       Don't automatically migrate threads between CPUs",
 "  -qw       Migrate a thread to the current CPU when it is woken up",
 #endif
@@ -1233,6 +1236,9 @@ error = rtsTrue;
                    case 'b':
                        RtsFlags.ParFlags.parGcLoadBalancing = rtsFalse;
                        break;
+                   case 'a':
+                       RtsFlags.ParFlags.setAffinity = rtsTrue;
+                       break;
                    case 'm':
                        RtsFlags.ParFlags.migrate = rtsFalse;
                        break;
index 666b59e..636b517 100644 (file)
@@ -2125,6 +2125,10 @@ workerStart(Task *task)
     cap = task->cap;
     RELEASE_LOCK(&task->lock);
 
+    if (RtsFlags.ParFlags.setAffinity) {
+        setThreadAffinity(cap->no, n_capabilities);
+    }
+
     // set the thread-local pointer to the Task:
     taskEnter(task);
 
index 6eb2d2b..f15fc95 100644 (file)
@@ -7,8 +7,9 @@
  *
  * --------------------------------------------------------------------------*/
 
-#if defined(DEBUG) && defined(__linux__)
+#if defined(__linux__)
 /* We want GNU extensions in DEBUG mode for mutex error checking */
+/* We also want the affinity API, which requires _GNU_SOURCE */
 #define _GNU_SOURCE
 #endif
 
 #error pthreads.h is required for the threaded RTS on Posix platforms
 #endif
 
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+
 /*
  * This (allegedly) OS threads independent layer was initially
  * abstracted away from code that used Pthreads, so the functions
@@ -197,6 +202,26 @@ getNumberOfProcessors (void)
     return nproc;
 }
 
+// Schedules the thread to run on CPU n of m.  m may be less than the
+// number of physical CPUs, in which case, the thread will be allowed
+// to run on CPU n, n+m, n+2m etc.
+void
+setThreadAffinity (nat n, nat m)
+{
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_SETAFFINITY)
+    nat nproc;
+    cpu_set_t cs;
+    nat i;
+
+    nproc = getNumberOfProcessors();
+    CPU_ZERO(&cs);
+    for (i = n; i < nproc; i+=m) {
+        CPU_SET(n, &cs);
+    }
+    sched_setaffinity(0, sizeof(cpu_set_t), &cs);
+#endif
+}
+
 #else /* !defined(THREADED_RTS) */
 
 int
index 929b817..c18bab2 100644 (file)
@@ -246,6 +246,12 @@ getNumberOfProcessors (void)
     return nproc;
 }
 
+void
+setThreadAffinity (nat n STG_UNUSED, nat m STG_UNUSED)
+{
+    /* ToDo */
+}
+
 #else /* !defined(THREADED_RTS) */
 
 int