From patchwork Tue Jul 28 11:04:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Huber X-Patchwork-Id: 501150 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id AE7CD140D19 for ; Tue, 28 Jul 2015 21:05:16 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=h8CR+dpw; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=hbL72fDFHYKGH4cLIXvLscL1gWmQkSSeHPnkfum4YSgtRMWPpNW8R q6TqoDzdRc2rBGXAMBp2YvjM60Gnv1ychbSCkYVBYq29xT5FvvPT5T0sJppWC+sC pRuCjMETNU0kmz1kY2QOnCTMA0DDaRxcmXi4HjavFqjiYGqn2zGI24= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=sKvYxuD7jeloqYPSGEoaDnpbq9g=; b=h8CR+dpw1PaPcF8N/BCl JQjizYNzId3BeXAOrF0+izMdcOVVJ9A0Kr4pUyhNf32/l4Olt4prpk3cDEch8M82 22VLbg4cenX1Io5oS63IiLZrtADeOpao9eX2cSUJYe02OaPGsrD7elJnLIWPBbuB +yO3sCFeeXyxpOupK7ZcrJc= Received: (qmail 890 invoked by alias); 28 Jul 2015 11:05:10 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 130148 invoked by uid 89); 28 Jul 2015 11:05:09 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.6 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RDNS_DYNAMIC autolearn=no version=3.3.2 X-HELO: mail.embedded-brains.de Received: from host-82-135-62-35.customer.m-online.net (HELO mail.embedded-brains.de) (82.135.62.35) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 28 Jul 2015 11:05:07 +0000 Received: from localhost (localhost.localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id C38662A194C for ; Tue, 28 Jul 2015 13:05:13 +0200 (CEST) Received: from mail.embedded-brains.de ([127.0.0.1]) by localhost (zimbra.eb.localhost [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id XQ5-A9IQVQCv; Tue, 28 Jul 2015 13:05:11 +0200 (CEST) Received: from localhost (localhost.localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id 889C02A1991; Tue, 28 Jul 2015 13:05:11 +0200 (CEST) Received: from mail.embedded-brains.de ([127.0.0.1]) by localhost (zimbra.eb.localhost [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id PUHFt3C7A2Fb; Tue, 28 Jul 2015 13:05:11 +0200 (CEST) Received: from huber-linux.eb.localhost (unknown [192.168.96.129]) by mail.embedded-brains.de (Postfix) with ESMTP id 66A602A194C; Tue, 28 Jul 2015 13:05:11 +0200 (CEST) From: Sebastian Huber To: gcc-patches@gcc.gnu.org Cc: Sebastian Huber Subject: [PATCH 2/3] [gomp] Thread pool management Date: Tue, 28 Jul 2015 13:04:58 +0200 Message-Id: <1438081499-9651-2-git-send-email-sebastian.huber@embedded-brains.de> In-Reply-To: <1438081499-9651-1-git-send-email-sebastian.huber@embedded-brains.de> References: <1438081499-9651-1-git-send-email-sebastian.huber@embedded-brains.de> X-IsSubscribed: yes 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 * 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 . (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 . + + 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 + . */ + +/* 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 + +/* 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 . + + 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 + . */ + +/* 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 +#include +#include + +/* 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 . + + 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 + . */ + +/* This file contains RTEMS specific routines related to counting + online processors and dynamic load balancing. */ + +#include "libgomp.h" +#include +#include +#include +#include +#include + +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 #include #include @@ -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); } }