libgomp: bring early CPU affinity support from FSF GCC-4_3 branch.

This is not likely to make it into a release and is basically disabled
but should still be useful for testing.

Obtained from: GCC pre-4.3 (rev. 123494, 125542; LGPLv2.1+)
This commit is contained in:
Pedro F. Giffuni 2015-04-27 21:27:51 +00:00
parent 3f6cf39fb2
commit 70364ab4ff
13 changed files with 391 additions and 9 deletions

View File

@ -0,0 +1,23 @@
2007-06-07 Jakub Jelinek <jakub@redhat.com> (r125542)
* team.c (gomp_team_start): Fix setting up thread_attr
stack size.
2007-04-04 Jakub Jelinek <jakub@redhat.com> (r123494)
* 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.

View 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

View 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@

View 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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -237,6 +237,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

View 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);

View 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));

View 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 (&gomp_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,18 @@ 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);

View File

@ -12,7 +12,7 @@ SHLIB_MAJOR= 1
SRCS= 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
bar.c time.c fortran.c affinity.c
SRCS+= gstdint.h libgomp_f.h omp.h omp_lib.h
INCS+= omp.h

View File

@ -26,6 +26,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* 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. */
#define HAVE_SEMAPHORE_H 1