diff options
-rw-r--r-- | libgomp/ChangeLog | 19 | ||||
-rw-r--r-- | libgomp/Makefile.am | 2 | ||||
-rw-r--r-- | libgomp/Makefile.in | 5 | ||||
-rw-r--r-- | libgomp/config.h.in | 3 | ||||
-rw-r--r-- | libgomp/config/linux/affinity.c | 107 | ||||
-rw-r--r-- | libgomp/config/posix/affinity.c | 41 | ||||
-rwxr-xr-x | libgomp/configure | 62 | ||||
-rw-r--r-- | libgomp/configure.ac | 19 | ||||
-rw-r--r-- | libgomp/env.c | 97 | ||||
-rw-r--r-- | libgomp/libgomp.h | 12 | ||||
-rw-r--r-- | libgomp/team.c | 23 |
11 files changed, 382 insertions, 8 deletions
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index bcfa440..960c57c 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -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 diff --git a/libgomp/Makefile.am b/libgomp/Makefile.am index 8192aec..6963e10 100644 --- a/libgomp/Makefile.am +++ b/libgomp/Makefile.am @@ -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 diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in index f11740c..f41ca17 100644 --- a/libgomp/Makefile.in +++ b/libgomp/Makefile.in @@ -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@ diff --git a/libgomp/config.h.in b/libgomp/config.h.in index 0f33b00..13cdf1b 100644 --- a/libgomp/config.h.in +++ b/libgomp/config.h.in @@ -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 index 0000000..8fcce5f --- /dev/null +++ b/libgomp/config/linux/affinity.c @@ -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 index 0000000..67cb37a --- /dev/null +++ b/libgomp/config/posix/affinity.c @@ -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; +} diff --git a/libgomp/configure b/libgomp/configure index 5cd8ef5..426c62f 100755 --- a/libgomp/configure +++ b/libgomp/configure @@ -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 diff --git a/libgomp/configure.ac b/libgomp/configure.ac index 4ee96e2..427c8f7c 100644 --- a/libgomp/configure.ac +++ b/libgomp/configure.ac @@ -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 diff --git a/libgomp/env.c b/libgomp/env.c index f07b31b..4a07bfa 100644 --- a/libgomp/env.c +++ b/libgomp/env.c @@ -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); diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 47e68e6..7075250 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -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)); diff --git a/libgomp/team.c b/libgomp/team.c index 060f4ea..d114bb5 100644 --- a/libgomp/team.c +++ b/libgomp/team.c @@ -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); |