From patchwork Tue Jul 7 12:17:57 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Huber X-Patchwork-Id: 492157 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 501E11402BB for ; Tue, 7 Jul 2015 22:18:12 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=eX5NgLT+; 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; q=dns; s=default; b=SRcCPXYC3ueU 7QnuoOu7WwsFdxpvasg68BgvtlQofWUUnhbrbm76ZyVy6hHY3A2x3kTIaYD7V5q8 SFNQc+Xy6KLZg7ts24mvIR6/mqGG2OBEaRieD6qPC57nxzq+EB+2gFJznYIHm6i/ iKgZcgYbYTZ3QvksRUsA18p9RsA3Pl4= 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; s=default; bh=0u4GU62gjv1dTHcfJw XO4ptAJ7M=; b=eX5NgLT+sKvh4oV+M5kXnAnkIlQEEhltp5zrusIoP33f4DuiRn uIX8CAr+kh1ZnXAV/Ld1daXnVbgWq4AbiD2WV+DVI1Lq/hZqnVt5y0yu0yZIuOzY 49Zm78zErhuJcLBnh7OLvd7jy/1uyLZWxbjpgTNIajdgIVMF7K50LPuXg= Received: (qmail 117297 invoked by alias); 7 Jul 2015 12:18:06 -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 117281 invoked by uid 89); 7 Jul 2015 12:18:05 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.9 required=5.0 tests=AWL, BAYES_50, 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, 07 Jul 2015 12:18:03 +0000 Received: from localhost (localhost.localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id 85E0F2A1989 for ; Tue, 7 Jul 2015 14:18:28 +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 jdKtoggra-x6; Tue, 7 Jul 2015 14:18:28 +0200 (CEST) Received: from localhost (localhost.localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id E70EB2A1611; Tue, 7 Jul 2015 14:18:27 +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 4T27e7WjADDN; Tue, 7 Jul 2015 14:18:27 +0200 (CEST) Received: from huber-linux.eb.localhost (unknown [192.168.96.129]) by mail.embedded-brains.de (Postfix) with ESMTP id C4EDA2A109C; Tue, 7 Jul 2015 14:18:27 +0200 (CEST) From: Sebastian Huber To: gcc-patches@gcc.gnu.org Cc: Sebastian Huber Subject: [PATCH] libgomp: Introduce gomp_thread::spare_team Date: Tue, 7 Jul 2015 14:17:57 +0200 Message-Id: <1436271477-16941-1-git-send-email-sebastian.huber@embedded-brains.de> X-IsSubscribed: yes Try to re-use the previous team to avoid the use of malloc() and free() in the normal case where number of threads is the same. Avoid superfluous destruction and initialization of team synchronization objects. Using the microbenchmark posted here https://gcc.gnu.org/ml/gcc-patches/2008-03/msg00930.html shows an improvement in the parallel bench test case (target x86_64-unknown-linux-gnu, median out of 9 test runs, iteration count increased to 200000). Before the patch: parallel bench 11.2284 seconds After the patch: parallel bench 10.7575 seconds libgomp/ChangeLog 2015-07-07 Sebastian Huber * libgomp.h (gomp_thread): Add spare_team field. * team.c (gomp_thread_start): Initialize spare team for non-TLS targets. (gomp_new_team): Use spare team if possible. (free_team): Destroy more team objects. (gomp_free_thread): Free spare team if necessary. (free_non_nested_team): New. (gomp_team_end): Move some team object destructions to free_team(). Use free_non_nested_team(). --- libgomp/libgomp.h | 3 +++ libgomp/team.c | 63 ++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 5ed0f78..563c1e2 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -448,6 +448,9 @@ struct gomp_thread /* User pthread thread pool */ struct gomp_thread_pool *thread_pool; + + /* Spare team ready for re-use in gomp_new_team() */ + struct gomp_team *spare_team; }; diff --git a/libgomp/team.c b/libgomp/team.c index b98b233..cc19eb0 100644 --- a/libgomp/team.c +++ b/libgomp/team.c @@ -77,6 +77,7 @@ gomp_thread_start (void *xdata) struct gomp_thread local_thr; thr = &local_thr; pthread_setspecific (gomp_tls_key, thr); + thr->spare_team = NULL; #endif gomp_sem_init (&thr->release, 0); @@ -140,19 +141,35 @@ gomp_thread_start (void *xdata) struct gomp_team * gomp_new_team (unsigned nthreads) { + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *spare_team = thr->spare_team; struct gomp_team *team; - size_t size; int i; - size = sizeof (*team) + nthreads * (sizeof (team->ordered_release[0]) - + sizeof (team->implicit_task[0])); - team = gomp_malloc (size); + if (spare_team && spare_team->nthreads == nthreads) + { + thr->spare_team = NULL; + team = spare_team; + } + else + { + size_t extra = sizeof (team->ordered_release[0]) + + sizeof (team->implicit_task[0]); + team = gomp_malloc (sizeof (*team) + nthreads * extra); + +#ifndef HAVE_SYNC_BUILTINS + gomp_mutex_init (&team->work_share_list_free_lock); +#endif + gomp_barrier_init (&team->barrier, nthreads); + gomp_sem_init (&team->master_release, 0); + gomp_mutex_init (&team->task_lock); + + team->nthreads = nthreads; + } team->work_share_chunk = 8; #ifdef HAVE_SYNC_BUILTINS team->single_count = 0; -#else - gomp_mutex_init (&team->work_share_list_free_lock); #endif team->work_shares_to_free = &team->work_shares[0]; gomp_init_work_share (&team->work_shares[0], false, nthreads); @@ -163,14 +180,9 @@ gomp_new_team (unsigned nthreads) team->work_shares[i].next_free = &team->work_shares[i + 1]; team->work_shares[i].next_free = NULL; - team->nthreads = nthreads; - gomp_barrier_init (&team->barrier, nthreads); - - gomp_sem_init (&team->master_release, 0); team->ordered_release = (void *) &team->implicit_task[nthreads]; team->ordered_release[0] = &team->master_release; - gomp_mutex_init (&team->task_lock); team->task_queue = NULL; team->task_count = 0; team->task_queued_count = 0; @@ -187,6 +199,10 @@ gomp_new_team (unsigned nthreads) static void free_team (struct gomp_team *team) { + gomp_sem_destroy (&team->master_release); +#ifndef HAVE_SYNC_BUILTINS + gomp_mutex_destroy (&team->work_share_list_free_lock); +#endif gomp_barrier_destroy (&team->barrier); gomp_mutex_destroy (&team->task_lock); free (team); @@ -225,6 +241,8 @@ gomp_free_thread (void *arg __attribute__((unused))) { struct gomp_thread *thr = gomp_thread (); struct gomp_thread_pool *pool = thr->thread_pool; + if (thr->spare_team) + free_team (thr->spare_team); if (pool) { if (pool->threads_used > 0) @@ -835,6 +853,18 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads, free (affinity_thr); } +static void +free_non_nested_team (struct gomp_team *team, struct gomp_thread *thr) +{ + struct gomp_thread_pool *pool = thr->thread_pool; + if (pool->last_team) + { + if (thr->spare_team) + free_team (thr->spare_team); + thr->spare_team = pool->last_team; + } + pool->last_team = team; +} /* Terminate the current team. This is only to be called by the master thread. We assume that we must wait for the other threads. */ @@ -894,21 +924,12 @@ gomp_team_end (void) } while (ws != NULL); } - gomp_sem_destroy (&team->master_release); -#ifndef HAVE_SYNC_BUILTINS - gomp_mutex_destroy (&team->work_share_list_free_lock); -#endif if (__builtin_expect (thr->ts.team != NULL, 0) || __builtin_expect (team->nthreads == 1, 0)) free_team (team); else - { - struct gomp_thread_pool *pool = thr->thread_pool; - if (pool->last_team) - free_team (pool->last_team); - pool->last_team = team; - } + free_non_nested_team (team, thr); }