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]

[PATCH 2/3] [gomp] Thread pool management


In RTEMS we may have multiple scheduler instances with different
scheduling algorithms.  In addition we have a single process environment
so all threads run in one address space.  In order to support work
stealing applications it is important to limit the number of thread
pools used for OpenMP since otherwise we may end up in an explosion of
OpenMP worker threads.

libgomp/ChangeLog
2015-07-28  Sebastian Huber  <sebastian.huber@embedded-brains.de>

	* config/posix/pool.h: New.
	* config/rtems/pool.h: Likewise.
	* config/rtems/proc.c: Likewise.
	* libgomp.h (gomp_thread_destructor): Declare.
	* team.c: Include configuration provided <pool.h>.
	(gomp_get_thread_pool): Define in configuration.
	(gomp_team_end): Call configuration defined
	gomp_release_thread_pool().
---
 libgomp/config/posix/pool.h |  60 ++++++++++++++++++
 libgomp/config/rtems/pool.h | 128 ++++++++++++++++++++++++++++++++++++++
 libgomp/config/rtems/proc.c | 145 ++++++++++++++++++++++++++++++++++++++++++++
 libgomp/libgomp.h           |   2 +
 libgomp/team.c              |  22 +------
 5 files changed, 337 insertions(+), 20 deletions(-)
 create mode 100644 libgomp/config/posix/pool.h
 create mode 100644 libgomp/config/rtems/pool.h
 create mode 100644 libgomp/config/rtems/proc.c

diff --git a/libgomp/config/posix/pool.h b/libgomp/config/posix/pool.h
new file mode 100644
index 0000000..0d127a0
--- /dev/null
+++ b/libgomp/config/posix/pool.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Contributed by Sebastian Huber <sebastian.huber@embedded-brains.de>.
+
+   This file is part of the GNU Offloading and Multi Processing Library
+   (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, 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 General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This is the default implementation of the thread pool management
+   for libgomp.  This type is private to the library.  */
+
+#ifndef GOMP_POOL_H
+#define GOMP_POOL_H 1
+
+#include <libgomp.h>
+
+/* Get the thread pool, allocate and initialize it on demand.  */
+
+static inline struct gomp_thread_pool *
+gomp_get_thread_pool (struct gomp_thread *thr, unsigned nthreads)
+{
+  struct gomp_thread_pool *pool = thr->thread_pool;
+  if (__builtin_expect (pool == NULL, 0))
+    {
+      pool = gomp_malloc (sizeof (*pool));
+      pool->threads = NULL;
+      pool->threads_size = 0;
+      pool->threads_used = 0;
+      pool->last_team = NULL;
+      pool->threads_busy = nthreads;
+      thr->thread_pool = pool;
+      pthread_setspecific (gomp_thread_destructor, thr);
+    }
+  return pool;
+}
+
+static inline void
+gomp_release_thread_pool (struct gomp_thread_pool *pool)
+{
+  /* Do nothing in the default implementation.  */
+}
+
+#endif /* GOMP_POOL_H */
diff --git a/libgomp/config/rtems/pool.h b/libgomp/config/rtems/pool.h
new file mode 100644
index 0000000..5c989d0
--- /dev/null
+++ b/libgomp/config/rtems/pool.h
@@ -0,0 +1,128 @@
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Sebastian Huber <sebastian.huber@embedded-brains.de>.
+
+   This file is part of the GNU Offloading and Multi Processing Library
+   (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, 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 General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This is the RTEMS implementation of the thread pool management
+   for libgomp.  This type is private to the library.  */
+
+#ifndef GOMP_POOL_H
+#define GOMP_POOL_H 1
+
+#include <libgomp.h>
+#include <sys/lock.h>
+#include <string.h>
+
+/* For each scheduler instance there may be a thread pool reservoir
+   to limit the number of thread pools used by the OpenMP master threads of this
+   scheduler instance.  The reservoirs are configured via the
+   GOMP_RTEMS_THREAD_POOLS environment variable.  */
+struct gomp_thread_pool_reservoir {
+  gomp_sem_t available;
+  gomp_mutex_t lock;
+  size_t index;
+  struct gomp_thread_pool *pools[];
+};
+
+struct gomp_tls_rtems_data {
+  struct gomp_thread_pool_reservoir *thread_pool_reservoir;
+};
+
+extern struct gomp_thread_pool_reservoir **gomp_thread_pool_reservoirs;
+
+extern __thread struct gomp_tls_rtems_data gomp_tls_rtems_data;
+
+static inline struct gomp_thread_pool_reservoir *
+gomp_get_thread_pool_reservoir (void)
+{
+  struct gomp_thread_pool_reservoir *res =
+    gomp_tls_rtems_data.thread_pool_reservoir;
+
+  if (res == NULL && gomp_thread_pool_reservoirs != NULL)
+    {
+      struct gomp_thread *thr = gomp_thread ();
+      thr->thread_pool = gomp_malloc_cleared (sizeof (*thr->thread_pool));
+      res = gomp_thread_pool_reservoirs[_Sched_Index ()];
+      gomp_tls_rtems_data.thread_pool_reservoir = res;
+    }
+
+  return res;
+}
+
+static inline struct gomp_thread_pool *
+gomp_get_own_thread_pool (struct gomp_thread *thr, unsigned nthreads)
+{
+  struct gomp_thread_pool *pool = thr->thread_pool;
+  if (__builtin_expect (pool == NULL, 0))
+    {
+      pool = gomp_malloc_cleared (sizeof (*pool));
+      pool->threads_busy = nthreads;
+      thr->thread_pool = pool;
+    }
+  return pool;
+}
+
+static inline struct gomp_thread_pool *
+gomp_get_thread_pool (struct gomp_thread *thr, unsigned nthreads)
+{
+  struct gomp_thread_pool *pool;
+
+  if (__builtin_expect (thr->thread_pool == NULL, 0))
+    pthread_setspecific (gomp_thread_destructor, thr);
+
+  if (nthreads != 1)
+    {
+      struct gomp_thread_pool_reservoir *res =
+	gomp_get_thread_pool_reservoir ();
+      if (res != NULL)
+	{
+	  gomp_sem_wait (&res->available);
+	  gomp_mutex_lock (&res->lock);
+	  pool = res->pools[--res->index];
+	  gomp_mutex_unlock (&res->lock);
+	  pool->threads_busy = nthreads;
+	  thr->thread_pool = pool;
+	}
+      else
+	pool = gomp_get_own_thread_pool (thr, nthreads);
+    }
+  else
+    pool = NULL;
+  return pool;
+}
+
+static inline void
+gomp_release_thread_pool (struct gomp_thread_pool *pool)
+{
+  struct gomp_thread_pool_reservoir *res =
+    gomp_tls_rtems_data.thread_pool_reservoir;
+  if (res != NULL)
+    {
+      gomp_mutex_lock (&res->lock);
+      res->pools[res->index++] = pool;
+      gomp_mutex_unlock (&res->lock);
+      gomp_sem_post (&res->available);
+    }
+}
+
+#endif /* GOMP_POOL_H */
diff --git a/libgomp/config/rtems/proc.c b/libgomp/config/rtems/proc.c
new file mode 100644
index 0000000..9c36dcb
--- /dev/null
+++ b/libgomp/config/rtems/proc.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Sebastian Huber <sebastian.huber@embedded-brains.de>.
+
+   This file is part of the GNU Offloading and Multi Processing Library
+   (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, 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 General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file contains RTEMS specific routines related to counting
+   online processors and dynamic load balancing.  */
+
+#include "libgomp.h"
+#include <errno.h>
+#include <pool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct gomp_thread_pool_reservoir **gomp_thread_pool_reservoirs;
+
+__thread struct gomp_tls_rtems_data gomp_tls_rtems_data;
+
+static void
+allocate_thread_pool_reservoirs (void)
+{
+  struct gomp_thread_pool_reservoir **reservoirs;
+  size_t size = _Sched_Count () * sizeof (*reservoirs);
+  reservoirs = gomp_malloc (size);
+  gomp_thread_pool_reservoirs = reservoirs;
+  memset (reservoirs, 0, size);
+}
+
+static void
+allocate_thread_pool_reservoir (unsigned long count, unsigned long scheduler)
+{
+  struct gomp_thread_pool_reservoir *res;
+  struct gomp_thread_pool *pools;
+  unsigned long i;
+  size_t size;
+
+  res = gomp_thread_pool_reservoirs[scheduler];
+  if (res != NULL)
+    gomp_fatal ("Multiple thread pool reservoir initialization");
+  size = sizeof (*res) + count * (sizeof(pools) + sizeof(*pools));
+  pools = gomp_malloc (size);
+  memset (pools, 0, size);
+  res = (struct gomp_thread_pool_reservoir *) (pools + count);
+  res->index = count;
+  gomp_sem_init (&res->available, count);
+  gomp_mutex_init (&res->lock);
+  for (i = 0; i < count; ++i)
+    res->pools[i] = &pools[i];
+  gomp_thread_pool_reservoirs[scheduler] = res;
+}
+
+static char *
+parse_thread_pools (char *env, unsigned long *count, unsigned long *scheduler)
+{
+  size_t len;
+  int i;
+
+  if (*env == ':')
+    ++env;
+
+  errno = 0;
+  *count = strtoul (env, &env, 10);
+  if (errno != 0)
+    gomp_fatal ("Invalid thread pool count");
+
+  if (*env != '@')
+    gomp_fatal ("Invalid thread pool scheduler prefix");
+  ++env;
+
+  len = 0;
+  while (env[len] != '\0' && env[len] != ':')
+    ++len;
+  i = _Sched_Name_to_index (env, len);
+  if (i < 0)
+    gomp_fatal ("Invalid thread pool scheduler");
+  *scheduler = i;
+  env += len;
+
+  return env;
+}
+
+static void
+init_thread_pool_reservoirs (void)
+{
+  char *env = getenv ("GOMP_RTEMS_THREAD_POOLS");
+  if (env != NULL)
+    {
+      allocate_thread_pool_reservoirs ();
+      while (*env != '\0')
+	{
+	  unsigned long count;
+	  unsigned long scheduler;
+	  env = parse_thread_pools (env, &count, &scheduler);
+	  allocate_thread_pool_reservoir (count, scheduler);
+	}
+    }
+}
+
+void
+gomp_init_num_threads (void)
+{
+  gomp_global_icv.nthreads_var = omp_get_num_procs();
+  init_thread_pool_reservoirs ();
+}
+
+unsigned
+gomp_dynamic_max_threads (void)
+{
+  unsigned n_onln = (unsigned) omp_get_num_procs();
+  unsigned nthreads_var = gomp_icv (false)->nthreads_var;
+
+  if (n_onln > nthreads_var)
+    return nthreads_var;
+  else
+    return n_onln;
+}
+
+int
+omp_get_num_procs (void)
+{
+  return sysconf (_SC_NPROCESSORS_ONLN);
+}
+
+ialias (omp_get_num_procs)
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index ac40e2a..9b803d6 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -513,6 +513,8 @@ static inline struct gomp_task_icv *gomp_icv (bool write)
 /* The attributes to be used during thread creation.  */
 extern pthread_attr_t gomp_thread_attr;
 
+extern pthread_key_t gomp_thread_destructor;
+
 /* Function prototypes.  */
 
 /* affinity.c */
diff --git a/libgomp/team.c b/libgomp/team.c
index 5c56182..5edae07 100644
--- a/libgomp/team.c
+++ b/libgomp/team.c
@@ -27,6 +27,7 @@
    creation and termination.  */
 
 #include "libgomp.h"
+#include <pool.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -134,26 +135,6 @@ gomp_thread_start (void *xdata)
   return NULL;
 }
 
-/* Get the thread pool, allocate and initialize it on demand.  */
-
-static struct gomp_thread_pool *
-gomp_get_thread_pool (struct gomp_thread *thr, unsigned nthreads)
-{
-  struct gomp_thread_pool *pool = thr->thread_pool;
-  if (__builtin_expect (pool == NULL, 0))
-    {
-      pool = gomp_malloc (sizeof (*pool));
-      pool->threads = NULL;
-      pool->threads_size = 0;
-      pool->threads_used = 0;
-      pool->last_team = NULL;
-      pool->threads_busy = nthreads;
-      thr->thread_pool = pool;
-      pthread_setspecific (gomp_thread_destructor, thr);
-    }
-  return pool;
-}
-
 static inline struct gomp_team *
 get_last_team (unsigned nthreads)
 {
@@ -930,6 +911,7 @@ gomp_team_end (void)
       if (pool->last_team)
 	free_team (pool->last_team);
       pool->last_team = team;
+      gomp_release_thread_pool (pool);
     }
 }
 
-- 
1.8.4.5


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