xref: /dflybsd-src/contrib/gcc-4.7/libgomp/parallel.c (revision 94b98a915ba84699b2a2adab9146fbc2cf617459)
1*629ff9f7SJohn Marino /* Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
2*629ff9f7SJohn Marino    Contributed by Richard Henderson <rth@redhat.com>.
3*629ff9f7SJohn Marino 
4*629ff9f7SJohn Marino    This file is part of the GNU OpenMP Library (libgomp).
5*629ff9f7SJohn Marino 
6*629ff9f7SJohn Marino    Libgomp is free software; you can redistribute it and/or modify it
7*629ff9f7SJohn Marino    under the terms of the GNU General Public License as published by
8*629ff9f7SJohn Marino    the Free Software Foundation; either version 3, or (at your option)
9*629ff9f7SJohn Marino    any later version.
10*629ff9f7SJohn Marino 
11*629ff9f7SJohn Marino    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12*629ff9f7SJohn Marino    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13*629ff9f7SJohn Marino    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14*629ff9f7SJohn Marino    more details.
15*629ff9f7SJohn Marino 
16*629ff9f7SJohn Marino    Under Section 7 of GPL version 3, you are granted additional
17*629ff9f7SJohn Marino    permissions described in the GCC Runtime Library Exception, version
18*629ff9f7SJohn Marino    3.1, as published by the Free Software Foundation.
19*629ff9f7SJohn Marino 
20*629ff9f7SJohn Marino    You should have received a copy of the GNU General Public License and
21*629ff9f7SJohn Marino    a copy of the GCC Runtime Library Exception along with this program;
22*629ff9f7SJohn Marino    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23*629ff9f7SJohn Marino    <http://www.gnu.org/licenses/>.  */
24*629ff9f7SJohn Marino 
25*629ff9f7SJohn Marino /* This file handles the (bare) PARALLEL construct.  */
26*629ff9f7SJohn Marino 
27*629ff9f7SJohn Marino #include "libgomp.h"
28*629ff9f7SJohn Marino #include <limits.h>
29*629ff9f7SJohn Marino 
30*629ff9f7SJohn Marino 
31*629ff9f7SJohn Marino /* Determine the number of threads to be launched for a PARALLEL construct.
32*629ff9f7SJohn Marino    This algorithm is explicitly described in OpenMP 3.0 section 2.4.1.
33*629ff9f7SJohn Marino    SPECIFIED is a combination of the NUM_THREADS clause and the IF clause.
34*629ff9f7SJohn Marino    If the IF clause is false, SPECIFIED is forced to 1.  When NUM_THREADS
35*629ff9f7SJohn Marino    is not present, SPECIFIED is 0.  */
36*629ff9f7SJohn Marino 
37*629ff9f7SJohn Marino unsigned
gomp_resolve_num_threads(unsigned specified,unsigned count)38*629ff9f7SJohn Marino gomp_resolve_num_threads (unsigned specified, unsigned count)
39*629ff9f7SJohn Marino {
40*629ff9f7SJohn Marino   struct gomp_thread *thread = gomp_thread();
41*629ff9f7SJohn Marino   struct gomp_task_icv *icv;
42*629ff9f7SJohn Marino   unsigned threads_requested, max_num_threads, num_threads;
43*629ff9f7SJohn Marino   unsigned long remaining;
44*629ff9f7SJohn Marino 
45*629ff9f7SJohn Marino   icv = gomp_icv (false);
46*629ff9f7SJohn Marino 
47*629ff9f7SJohn Marino   if (specified == 1)
48*629ff9f7SJohn Marino     return 1;
49*629ff9f7SJohn Marino   else if (thread->ts.active_level >= 1 && !icv->nest_var)
50*629ff9f7SJohn Marino     return 1;
51*629ff9f7SJohn Marino   else if (thread->ts.active_level >= gomp_max_active_levels_var)
52*629ff9f7SJohn Marino     return 1;
53*629ff9f7SJohn Marino 
54*629ff9f7SJohn Marino   /* If NUM_THREADS not specified, use nthreads_var.  */
55*629ff9f7SJohn Marino   if (specified == 0)
56*629ff9f7SJohn Marino     threads_requested = icv->nthreads_var;
57*629ff9f7SJohn Marino   else
58*629ff9f7SJohn Marino     threads_requested = specified;
59*629ff9f7SJohn Marino 
60*629ff9f7SJohn Marino   max_num_threads = threads_requested;
61*629ff9f7SJohn Marino 
62*629ff9f7SJohn Marino   /* If dynamic threads are enabled, bound the number of threads
63*629ff9f7SJohn Marino      that we launch.  */
64*629ff9f7SJohn Marino   if (icv->dyn_var)
65*629ff9f7SJohn Marino     {
66*629ff9f7SJohn Marino       unsigned dyn = gomp_dynamic_max_threads ();
67*629ff9f7SJohn Marino       if (dyn < max_num_threads)
68*629ff9f7SJohn Marino 	max_num_threads = dyn;
69*629ff9f7SJohn Marino 
70*629ff9f7SJohn Marino       /* Optimization for parallel sections.  */
71*629ff9f7SJohn Marino       if (count && count < max_num_threads)
72*629ff9f7SJohn Marino 	max_num_threads = count;
73*629ff9f7SJohn Marino     }
74*629ff9f7SJohn Marino 
75*629ff9f7SJohn Marino   /* ULONG_MAX stands for infinity.  */
76*629ff9f7SJohn Marino   if (__builtin_expect (gomp_thread_limit_var == ULONG_MAX, 1)
77*629ff9f7SJohn Marino       || max_num_threads == 1)
78*629ff9f7SJohn Marino     return max_num_threads;
79*629ff9f7SJohn Marino 
80*629ff9f7SJohn Marino #ifdef HAVE_SYNC_BUILTINS
81*629ff9f7SJohn Marino   do
82*629ff9f7SJohn Marino     {
83*629ff9f7SJohn Marino       remaining = gomp_remaining_threads_count;
84*629ff9f7SJohn Marino       num_threads = max_num_threads;
85*629ff9f7SJohn Marino       if (num_threads > remaining)
86*629ff9f7SJohn Marino 	num_threads = remaining + 1;
87*629ff9f7SJohn Marino     }
88*629ff9f7SJohn Marino   while (__sync_val_compare_and_swap (&gomp_remaining_threads_count,
89*629ff9f7SJohn Marino 				      remaining, remaining - num_threads + 1)
90*629ff9f7SJohn Marino 	 != remaining);
91*629ff9f7SJohn Marino #else
92*629ff9f7SJohn Marino   gomp_mutex_lock (&gomp_remaining_threads_lock);
93*629ff9f7SJohn Marino   num_threads = max_num_threads;
94*629ff9f7SJohn Marino   remaining = gomp_remaining_threads_count;
95*629ff9f7SJohn Marino   if (num_threads > remaining)
96*629ff9f7SJohn Marino     num_threads = remaining + 1;
97*629ff9f7SJohn Marino   gomp_remaining_threads_count -= num_threads - 1;
98*629ff9f7SJohn Marino   gomp_mutex_unlock (&gomp_remaining_threads_lock);
99*629ff9f7SJohn Marino #endif
100*629ff9f7SJohn Marino 
101*629ff9f7SJohn Marino   return num_threads;
102*629ff9f7SJohn Marino }
103*629ff9f7SJohn Marino 
104*629ff9f7SJohn Marino void
GOMP_parallel_start(void (* fn)(void *),void * data,unsigned num_threads)105*629ff9f7SJohn Marino GOMP_parallel_start (void (*fn) (void *), void *data, unsigned num_threads)
106*629ff9f7SJohn Marino {
107*629ff9f7SJohn Marino   num_threads = gomp_resolve_num_threads (num_threads, 0);
108*629ff9f7SJohn Marino   gomp_team_start (fn, data, num_threads, gomp_new_team (num_threads));
109*629ff9f7SJohn Marino }
110*629ff9f7SJohn Marino 
111*629ff9f7SJohn Marino void
GOMP_parallel_end(void)112*629ff9f7SJohn Marino GOMP_parallel_end (void)
113*629ff9f7SJohn Marino {
114*629ff9f7SJohn Marino   if (__builtin_expect (gomp_thread_limit_var != ULONG_MAX, 0))
115*629ff9f7SJohn Marino     {
116*629ff9f7SJohn Marino       struct gomp_thread *thr = gomp_thread ();
117*629ff9f7SJohn Marino       struct gomp_team *team = thr->ts.team;
118*629ff9f7SJohn Marino       if (team && team->nthreads > 1)
119*629ff9f7SJohn Marino 	{
120*629ff9f7SJohn Marino #ifdef HAVE_SYNC_BUILTINS
121*629ff9f7SJohn Marino 	  __sync_fetch_and_add (&gomp_remaining_threads_count,
122*629ff9f7SJohn Marino 				1UL - team->nthreads);
123*629ff9f7SJohn Marino #else
124*629ff9f7SJohn Marino 	  gomp_mutex_lock (&gomp_remaining_threads_lock);
125*629ff9f7SJohn Marino 	  gomp_remaining_threads_count -= team->nthreads - 1;
126*629ff9f7SJohn Marino 	  gomp_mutex_unlock (&gomp_remaining_threads_lock);
127*629ff9f7SJohn Marino #endif
128*629ff9f7SJohn Marino 	}
129*629ff9f7SJohn Marino     }
130*629ff9f7SJohn Marino   gomp_team_end ();
131*629ff9f7SJohn Marino }
132*629ff9f7SJohn Marino 
133*629ff9f7SJohn Marino 
134*629ff9f7SJohn Marino /* The public OpenMP API for thread and team related inquiries.  */
135*629ff9f7SJohn Marino 
136*629ff9f7SJohn Marino int
omp_get_num_threads(void)137*629ff9f7SJohn Marino omp_get_num_threads (void)
138*629ff9f7SJohn Marino {
139*629ff9f7SJohn Marino   struct gomp_team *team = gomp_thread ()->ts.team;
140*629ff9f7SJohn Marino   return team ? team->nthreads : 1;
141*629ff9f7SJohn Marino }
142*629ff9f7SJohn Marino 
143*629ff9f7SJohn Marino int
omp_get_thread_num(void)144*629ff9f7SJohn Marino omp_get_thread_num (void)
145*629ff9f7SJohn Marino {
146*629ff9f7SJohn Marino   return gomp_thread ()->ts.team_id;
147*629ff9f7SJohn Marino }
148*629ff9f7SJohn Marino 
149*629ff9f7SJohn Marino /* This wasn't right for OpenMP 2.5.  Active region used to be non-zero
150*629ff9f7SJohn Marino    when the IF clause doesn't evaluate to false, starting with OpenMP 3.0
151*629ff9f7SJohn Marino    it is non-zero with more than one thread in the team.  */
152*629ff9f7SJohn Marino 
153*629ff9f7SJohn Marino int
omp_in_parallel(void)154*629ff9f7SJohn Marino omp_in_parallel (void)
155*629ff9f7SJohn Marino {
156*629ff9f7SJohn Marino   return gomp_thread ()->ts.active_level > 0;
157*629ff9f7SJohn Marino }
158*629ff9f7SJohn Marino 
159*629ff9f7SJohn Marino int
omp_get_level(void)160*629ff9f7SJohn Marino omp_get_level (void)
161*629ff9f7SJohn Marino {
162*629ff9f7SJohn Marino   return gomp_thread ()->ts.level;
163*629ff9f7SJohn Marino }
164*629ff9f7SJohn Marino 
165*629ff9f7SJohn Marino int
omp_get_ancestor_thread_num(int level)166*629ff9f7SJohn Marino omp_get_ancestor_thread_num (int level)
167*629ff9f7SJohn Marino {
168*629ff9f7SJohn Marino   struct gomp_team_state *ts = &gomp_thread ()->ts;
169*629ff9f7SJohn Marino   if (level < 0 || level > ts->level)
170*629ff9f7SJohn Marino     return -1;
171*629ff9f7SJohn Marino   for (level = ts->level - level; level > 0; --level)
172*629ff9f7SJohn Marino     ts = &ts->team->prev_ts;
173*629ff9f7SJohn Marino   return ts->team_id;
174*629ff9f7SJohn Marino }
175*629ff9f7SJohn Marino 
176*629ff9f7SJohn Marino int
omp_get_team_size(int level)177*629ff9f7SJohn Marino omp_get_team_size (int level)
178*629ff9f7SJohn Marino {
179*629ff9f7SJohn Marino   struct gomp_team_state *ts = &gomp_thread ()->ts;
180*629ff9f7SJohn Marino   if (level < 0 || level > ts->level)
181*629ff9f7SJohn Marino     return -1;
182*629ff9f7SJohn Marino   for (level = ts->level - level; level > 0; --level)
183*629ff9f7SJohn Marino     ts = &ts->team->prev_ts;
184*629ff9f7SJohn Marino   if (ts->team == NULL)
185*629ff9f7SJohn Marino     return 1;
186*629ff9f7SJohn Marino   else
187*629ff9f7SJohn Marino     return ts->team->nthreads;
188*629ff9f7SJohn Marino }
189*629ff9f7SJohn Marino 
190*629ff9f7SJohn Marino int
omp_get_active_level(void)191*629ff9f7SJohn Marino omp_get_active_level (void)
192*629ff9f7SJohn Marino {
193*629ff9f7SJohn Marino   return gomp_thread ()->ts.active_level;
194*629ff9f7SJohn Marino }
195*629ff9f7SJohn Marino 
196*629ff9f7SJohn Marino ialias (omp_get_num_threads)
197*629ff9f7SJohn Marino ialias (omp_get_thread_num)
198*629ff9f7SJohn Marino ialias (omp_in_parallel)
199*629ff9f7SJohn Marino ialias (omp_get_level)
200*629ff9f7SJohn Marino ialias (omp_get_ancestor_thread_num)
201*629ff9f7SJohn Marino ialias (omp_get_team_size)
202*629ff9f7SJohn Marino ialias (omp_get_active_level)
203