libgomp.h (gomp_cpu_affinity, [...]): New extern decls.
authorJakub Jelinek <jakub@redhat.com>
Wed, 4 Apr 2007 15:44:20 +0000 (17:44 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 4 Apr 2007 15:44:20 +0000 (17:44 +0200)
* libgomp.h (gomp_cpu_affinity, gomp_cpu_affinity_len): New extern
decls.
(gomp_init_affinity, gomp_init_thread_affinity): New prototypes.
* env.c (gomp_cpu_affinity, gomp_cpu_affinity_len): New variables.
(parse_affinity): New function.
(initialize_env): Call it and gomp_init_affinity.
* team.c (gomp_team_start): If gomp_cpu_affinity != NULL,
create new pthread_attr_t and call gomp_init_thread_affinity
on it for each thread before passing the attribute to pthread_create.
* config/linux/affinity.c: New file.
* config/posix/affinity.c: New file.
* configure.ac (HAVE_PTHREAD_AFFINITY_NP): New test.
* configure: Rebuilt.
* config.h.in: Rebuilt.
* Makefile.am (libgomp_la_SOURCES): Add affinity.c.
* Makefile.in: Rebuilt.

From-SVN: r123494

libgomp/ChangeLog
libgomp/Makefile.am
libgomp/Makefile.in
libgomp/config.h.in
libgomp/config/linux/affinity.c [new file with mode: 0644]
libgomp/config/posix/affinity.c [new file with mode: 0644]
libgomp/configure
libgomp/configure.ac
libgomp/env.c
libgomp/libgomp.h
libgomp/team.c

index bcfa440..960c57c 100644 (file)
@@ -1,3 +1,22 @@
+2007-04-04  Jakub Jelinek  <jakub@redhat.com>
+
+       * libgomp.h (gomp_cpu_affinity, gomp_cpu_affinity_len): New extern
+       decls.
+       (gomp_init_affinity, gomp_init_thread_affinity): New prototypes.
+       * env.c (gomp_cpu_affinity, gomp_cpu_affinity_len): New variables.
+       (parse_affinity): New function.
+       (initialize_env): Call it and gomp_init_affinity.
+       * team.c (gomp_team_start): If gomp_cpu_affinity != NULL,
+       create new pthread_attr_t and call gomp_init_thread_affinity
+       on it for each thread before passing the attribute to pthread_create.
+       * config/linux/affinity.c: New file.
+       * config/posix/affinity.c: New file.
+       * configure.ac (HAVE_PTHREAD_AFFINITY_NP): New test.
+       * configure: Rebuilt.
+       * config.h.in: Rebuilt.
+       * Makefile.am (libgomp_la_SOURCES): Add affinity.c.
+       * Makefile.in: Rebuilt.
+
 2007-03-23  Andreas Tobler  <a.tobler@schweiz.org>
 
        * testsuite/lib/libgomp.exp (libgomp_init): Add -shared-libgcc for
index 8192aec..6963e10 100644 (file)
@@ -33,7 +33,7 @@ libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script)
 
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
        loop.c ordered.c parallel.c sections.c single.c team.c work.c \
-       lock.c mutex.c proc.c sem.c bar.c time.c fortran.c
+       lock.c mutex.c proc.c sem.c bar.c time.c fortran.c affinity.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h
index f11740c..f41ca17 100644 (file)
@@ -79,7 +79,7 @@ libgomp_la_LIBADD =
 am_libgomp_la_OBJECTS = alloc.lo barrier.lo critical.lo env.lo \
        error.lo iter.lo loop.lo ordered.lo parallel.lo sections.lo \
        single.lo team.lo work.lo lock.lo mutex.lo proc.lo sem.lo \
-       bar.lo time.lo fortran.lo
+       bar.lo time.lo fortran.lo affinity.lo
 libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -279,7 +279,7 @@ libgomp_version_info = -version-info $(libtool_VERSION)
 libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script)
 libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
        loop.c ordered.c parallel.c sections.c single.c team.c work.c \
-       lock.c mutex.c proc.c sem.c bar.c time.c fortran.c
+       lock.c mutex.c proc.c sem.c bar.c time.c fortran.c affinity.c
 
 nodist_noinst_HEADERS = libgomp_f.h
 nodist_libsubinclude_HEADERS = omp.h
@@ -406,6 +406,7 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bar.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/barrier.Plo@am__quote@
index 0f33b00..13cdf1b 100644 (file)
@@ -24,6 +24,9 @@
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
+/* Define if pthread_{,attr_}{g,s}etaffinity_np is supported. */
+#undef HAVE_PTHREAD_AFFINITY_NP
+
 /* Define to 1 if you have the <semaphore.h> header file. */
 #undef HAVE_SEMAPHORE_H
 
diff --git a/libgomp/config/linux/affinity.c b/libgomp/config/linux/affinity.c
new file mode 100644 (file)
index 0000000..8fcce5f
--- /dev/null
@@ -0,0 +1,107 @@
+/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License 
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This is a Linux specific implementation of a CPU affinity setting.  */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include "libgomp.h"
+#include <sched.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_PTHREAD_AFFINITY_NP
+
+static unsigned int affinity_counter;
+#ifndef HAVE_SYNC_BUILTINS
+static gomp_mutex_t affinity_lock;
+#endif
+
+void
+gomp_init_affinity (void)
+{
+  cpu_set_t cpuset;
+  size_t idx, widx;
+
+  if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset), &cpuset))
+    {
+      gomp_error ("could not get CPU affinity set");
+      free (gomp_cpu_affinity);
+      gomp_cpu_affinity = NULL;
+      gomp_cpu_affinity_len = 0;
+      return;
+    }
+
+  for (widx = idx = 0; idx < gomp_cpu_affinity_len; idx++)
+    if (gomp_cpu_affinity[idx] < CPU_SETSIZE
+        && CPU_ISSET (gomp_cpu_affinity[idx], &cpuset))
+      gomp_cpu_affinity[widx++] = gomp_cpu_affinity[idx];
+
+  if (widx == 0)
+    {
+      gomp_error ("no CPUs left for affinity setting");
+      free (gomp_cpu_affinity);
+      gomp_cpu_affinity = NULL;
+      gomp_cpu_affinity_len = 0;
+      return;
+    }
+
+  gomp_cpu_affinity_len = widx;
+  CPU_ZERO (&cpuset);
+  CPU_SET (gomp_cpu_affinity[0], &cpuset);
+  pthread_setaffinity_np (pthread_self (), sizeof (cpuset), &cpuset);
+  affinity_counter = 1;
+#ifndef HAVE_SYNC_BUILTINS
+  gomp_mutex_init (&affinity_lock);
+#endif
+}
+
+void
+gomp_init_thread_affinity (pthread_attr_t *attr)
+{
+  unsigned int cpu;
+  cpu_set_t cpuset;
+
+#ifdef HAVE_SYNC_BUILTINS
+  cpu = __sync_fetch_and_add (&affinity_counter, 1);
+#else
+  gomp_mutex_lock (&affinity_lock);
+  cpu = affinity_counter++;
+  gomp_mutex_unlock (&affinity_lock);
+#endif
+  cpu %= gomp_cpu_affinity_len;
+  CPU_ZERO (&cpuset);
+  CPU_SET (gomp_cpu_affinity[cpu], &cpuset);
+  pthread_attr_setaffinity_np (attr, sizeof (cpu_set_t), &cpuset);
+}
+
+#else
+
+#include "../posix/affinity.c"
+
+#endif
diff --git a/libgomp/config/posix/affinity.c b/libgomp/config/posix/affinity.c
new file mode 100644 (file)
index 0000000..67cb37a
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU OpenMP Library (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+   more details.
+
+   You should have received a copy of the GNU Lesser General Public License 
+   along with libgomp; see the file COPYING.LIB.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+/* As a special exception, if you link this library with other files, some
+   of which are compiled with GCC, to produce an executable, this library
+   does not by itself cause the resulting executable to be covered by the
+   GNU General Public License.  This exception does not however invalidate
+   any other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This is a generic stub implementation of a CPU affinity setting.  */
+
+#include "libgomp.h"
+
+void
+gomp_init_affinity (void)
+{
+}
+
+void
+gomp_init_thread_affinity (pthread_attr_t *attr)
+{
+  (void) attr;
+}
index 5cd8ef5..426c62f 100755 (executable)
@@ -8851,6 +8851,68 @@ rm -f conftest.err conftest.$ac_objext \
     ;;
 esac
 
+# Check for pthread_{,attr_}[sg]etaffinity_np.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#define _GNU_SOURCE
+   #include <pthread.h>
+int
+main ()
+{
+cpu_set_t cpuset;
+   pthread_attr_t attr;
+   pthread_getaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+   if (CPU_ISSET (0, &cpuset))
+     CPU_SET (1, &cpuset);
+   else
+     CPU_ZERO (&cpuset);
+   pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+   pthread_attr_init (&attr);
+   pthread_attr_getaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);
+   pthread_attr_setaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PTHREAD_AFFINITY_NP 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+
 # At least for glibc, clock_gettime is in librt.  But don't pull that
 # in if it still doesn't give us the function we want.
 if test $ac_cv_func_clock_gettime = no; then
index 4ee96e2..427c8f7 100644 (file)
@@ -236,6 +236,25 @@ If so, please configure with --disable-linux-futex])
     ;;
 esac
 
+# Check for pthread_{,attr_}[sg]etaffinity_np.
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+  [#define _GNU_SOURCE
+   #include <pthread.h>],
+  [cpu_set_t cpuset;
+   pthread_attr_t attr;
+   pthread_getaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+   if (CPU_ISSET (0, &cpuset))
+     CPU_SET (1, &cpuset);
+   else
+     CPU_ZERO (&cpuset);
+   pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+   pthread_attr_init (&attr);
+   pthread_attr_getaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);
+   pthread_attr_setaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);])],
+  AC_DEFINE(HAVE_PTHREAD_AFFINITY_NP, 1,
+[      Define if pthread_{,attr_}{g,s}etaffinity_np is supported.]))
+
 # At least for glibc, clock_gettime is in librt.  But don't pull that
 # in if it still doesn't give us the function we want.
 if test $ac_cv_func_clock_gettime = no; then
index f07b31b..4a07bfa 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -42,6 +42,8 @@ bool gomp_dyn_var = false;
 bool gomp_nest_var = false;
 enum gomp_schedule_type gomp_run_sched_var = GFS_DYNAMIC;
 unsigned long gomp_run_sched_chunk = 1;
+unsigned short *gomp_cpu_affinity;
+size_t gomp_cpu_affinity_len;
 
 /* Parse the OMP_SCHEDULE environment variable.  */
 
@@ -177,6 +179,97 @@ parse_boolean (const char *name, bool *value)
     gomp_error ("Invalid value for environment variable %s", name);
 }
 
+/* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
+   present and it was successfully parsed.  */
+
+static bool
+parse_affinity (void)
+{
+  char *env, *end;
+  unsigned long cpu_beg, cpu_end, cpu_stride;
+  unsigned short *cpus = NULL;
+  size_t allocated = 0, used = 0, needed;
+
+  env = getenv ("GOMP_CPU_AFFINITY");
+  if (env == NULL)
+    return false;
+
+  do
+    {
+      while (*env == ' ' || *env == '\t')
+       env++;
+
+      cpu_beg = strtoul (env, &end, 0);
+      cpu_end = cpu_beg;
+      cpu_stride = 1;
+      if (env == end || cpu_beg >= 65536)
+       goto invalid;
+
+      env = end;
+      if (*env == '-')
+       {
+         cpu_end = strtoul (++env, &end, 0);
+         if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
+           goto invalid;
+
+         env = end;
+         if (*env == ':')
+           {
+             cpu_stride = strtoul (++env, &end, 0);
+             if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
+               goto invalid;
+
+             env = end;
+           }
+       }
+
+      needed = (cpu_end - cpu_beg) / cpu_stride + 1;
+      if (used + needed >= allocated)
+       {
+         unsigned short *new_cpus;
+
+         if (allocated < 64)
+           allocated = 64;
+         if (allocated > needed)
+           allocated <<= 1;
+         else
+           allocated += 2 * needed;
+         new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
+         if (new_cpus == NULL)
+           {
+             free (cpus);
+             gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
+             return false;
+           }
+
+         cpus = new_cpus;
+       }
+
+      while (needed--)
+       {
+         cpus[used++] = cpu_beg;
+         cpu_beg += cpu_stride;
+       }
+
+      while (*env == ' ' || *env == '\t')
+       env++;
+
+      if (*env == ',')
+       env++;
+      else if (*env == '\0')
+       break;
+    }
+  while (1);
+
+  gomp_cpu_affinity = cpus;
+  gomp_cpu_affinity_len = used;
+  return true;
+
+ invalid:
+  gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
+  return false;
+}
+
 static void __attribute__((constructor))
 initialize_env (void)
 {
@@ -190,6 +283,8 @@ initialize_env (void)
   parse_boolean ("OMP_NESTED", &gomp_nest_var);
   if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var))
     gomp_init_num_threads ();
+  if (parse_affinity ())
+    gomp_init_affinity ();
 
   /* Not strictly environment related, but ordering constructors is tricky.  */
   pthread_attr_init (&gomp_thread_attr);
index 47e68e6..7075250 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -246,8 +246,18 @@ extern unsigned long gomp_run_sched_chunk;
 /* The attributes to be used during thread creation.  */
 extern pthread_attr_t gomp_thread_attr;
 
+/* Other variables.  */
+
+extern unsigned short *gomp_cpu_affinity;
+extern size_t gomp_cpu_affinity_len;
+
 /* Function prototypes.  */
 
+/* affinity.c */
+
+extern void gomp_init_affinity (void);
+extern void gomp_init_thread_affinity (pthread_attr_t *);
+
 /* alloc.c */
 
 extern void *gomp_malloc (size_t) __attribute__((malloc));
index 060f4ea..d114bb5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -183,6 +183,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
   struct gomp_team *team;
   bool nested;
   unsigned i, n, old_threads_used = 0;
+  pthread_attr_t thread_attr, *attr;
 
   thr = gomp_thread ();
   nested = thr->ts.team != NULL;
@@ -265,6 +266,17 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
        }
     }
 
+  attr = &gomp_thread_attr;
+  if (gomp_cpu_affinity != NULL)
+    {
+      size_t stacksize;
+      pthread_attr_init (&thread_attr);
+      pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
+      if (! pthread_attr_getstacksize (&thread_attr, &stacksize))
+       pthread_attr_setstacksize (&thread_attr, stacksize);
+      attr = &thread_attr;
+    }
+
   start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
                            * (nthreads-i));
 
@@ -283,12 +295,17 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
       start_data->fn_data = data;
       start_data->nested = nested;
 
-      err = pthread_create (&pt, &gomp_thread_attr,
-                           gomp_thread_start, start_data);
+      if (gomp_cpu_affinity != NULL)
+       gomp_init_thread_affinity (attr);
+
+      err = pthread_create (&pt, attr, gomp_thread_start, start_data);
       if (err != 0)
        gomp_fatal ("Thread creation failed: %s", strerror (err));
     }
 
+  if (gomp_cpu_affinity != NULL)
+    pthread_attr_destroy (&thread_attr);
+
  do_release:
   gomp_barrier_wait (nested ? &team->barrier : &gomp_threads_dock);