parallel.c

Go to the documentation of this file.
00001 /* Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
00002    Contributed by Richard Henderson <rth@redhat.com>.
00003 
00004    This file is part of the GNU OpenMP Library (libgomp).
00005 
00006    Libgomp is free software; you can redistribute it and/or modify it
00007    under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 3, or (at your option)
00009    any later version.
00010 
00011    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
00012    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00014    more details.
00015 
00016    Under Section 7 of GPL version 3, you are granted additional
00017    permissions described in the GCC Runtime Library Exception, version
00018    3.1, as published by the Free Software Foundation.
00019 
00020    You should have received a copy of the GNU General Public License and
00021    a copy of the GCC Runtime Library Exception along with this program;
00022    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023    <http://www.gnu.org/licenses/>.  */
00024 
00025 /* This file handles the (bare) PARALLEL construct.  */
00026 
00027 #include "libgomp.h"
00028 #include <limits.h>
00029 
00030 
00031 /* Determine the number of threads to be launched for a PARALLEL construct.
00032    This algorithm is explicitly described in OpenMP 3.0 section 2.4.1.
00033    SPECIFIED is a combination of the NUM_THREADS clause and the IF clause.
00034    If the IF clause is false, SPECIFIED is forced to 1.  When NUM_THREADS
00035    is not present, SPECIFIED is 0.  */
00036 
00037 unsigned
00038 gomp_resolve_num_threads (unsigned specified, unsigned count)
00039 {
00040   struct gomp_thread *thread = gomp_thread();
00041   struct gomp_task_icv *icv;
00042   unsigned threads_requested, max_num_threads, num_threads;
00043   unsigned long remaining;
00044 
00045   icv = gomp_icv (false);
00046 
00047   if (specified == 1)
00048     return 1;
00049   else if (thread->ts.active_level >= 1 && !icv->nest_var)
00050     return 1;
00051   else if (thread->ts.active_level >= gomp_max_active_levels_var)
00052     return 1;
00053 
00054   /* If NUM_THREADS not specified, use nthreads_var.  */
00055   if (specified == 0)
00056     threads_requested = icv->nthreads_var;
00057   else
00058     threads_requested = specified;
00059 
00060   max_num_threads = threads_requested;
00061 
00062   /* If dynamic threads are enabled, bound the number of threads
00063      that we launch.  */
00064   if (icv->dyn_var)
00065     {
00066       unsigned dyn = gomp_dynamic_max_threads ();
00067       if (dyn < max_num_threads)
00068     max_num_threads = dyn;
00069 
00070       /* Optimization for parallel sections.  */
00071       if (count && count < max_num_threads)
00072     max_num_threads = count;
00073     }
00074 
00075   /* ULONG_MAX stands for infinity.  */
00076   if (__builtin_expect (gomp_thread_limit_var == ULONG_MAX, 1)
00077       || max_num_threads == 1)
00078     return max_num_threads;
00079 
00080 #ifdef HAVE_SYNC_BUILTINS
00081   do
00082     {
00083       remaining = gomp_remaining_threads_count;
00084       num_threads = max_num_threads;
00085       if (num_threads > remaining)
00086     num_threads = remaining + 1;
00087     }
00088   while (__sync_val_compare_and_swap (&gomp_remaining_threads_count,
00089                       remaining, remaining - num_threads + 1)
00090      != remaining);
00091 #else
00092   gomp_mutex_lock (&gomp_remaining_threads_lock);
00093   num_threads = max_num_threads;
00094   remaining = gomp_remaining_threads_count;
00095   if (num_threads > remaining)
00096     num_threads = remaining + 1;
00097   gomp_remaining_threads_count -= num_threads - 1;
00098   gomp_mutex_unlock (&gomp_remaining_threads_lock);
00099 #endif
00100 
00101   return num_threads;
00102 }
00103 
00104 void
00105 GOMP_parallel_start (void (*fn) (void *), void *data, unsigned num_threads)
00106 {
00107   num_threads = gomp_resolve_num_threads (num_threads, 0);
00108   gomp_team_start (fn, data, num_threads, gomp_new_team (num_threads));
00109 }
00110 
00111 void
00112 GOMP_parallel_end (void)
00113 {
00114   if (__builtin_expect (gomp_thread_limit_var != ULONG_MAX, 0))
00115     {
00116       struct gomp_thread *thr = gomp_thread ();
00117       struct gomp_team *team = thr->ts.team;
00118       if (team && team->nthreads > 1)
00119     {
00120 #ifdef HAVE_SYNC_BUILTINS
00121       __sync_fetch_and_add (&gomp_remaining_threads_count,
00122                 1UL - team->nthreads);
00123 #else
00124       gomp_mutex_lock (&gomp_remaining_threads_lock);
00125       gomp_remaining_threads_count -= team->nthreads - 1;
00126       gomp_mutex_unlock (&gomp_remaining_threads_lock);
00127 #endif
00128     }
00129     }
00130   gomp_team_end ();
00131 }
00132 
00133 
00134 /* The public OpenMP API for thread and team related inquiries.  */
00135 
00136 int
00137 omp_get_num_threads (void)
00138 {
00139   struct gomp_team *team = gomp_thread ()->ts.team;
00140   return team ? team->nthreads : 1;
00141 }
00142 
00143 int
00144 omp_get_thread_num (void)
00145 {
00146   return gomp_thread ()->ts.team_id;
00147 }
00148 
00149 /* This wasn't right for OpenMP 2.5.  Active region used to be non-zero
00150    when the IF clause doesn't evaluate to false, starting with OpenMP 3.0
00151    it is non-zero with more than one thread in the team.  */
00152 
00153 int
00154 omp_in_parallel (void)
00155 {
00156   return gomp_thread ()->ts.active_level > 0;
00157 }
00158 
00159 int
00160 omp_get_level (void)
00161 {
00162   return gomp_thread ()->ts.level;
00163 }
00164 
00165 int
00166 omp_get_ancestor_thread_num (int level)
00167 {
00168   struct gomp_team_state *ts = &gomp_thread ()->ts;
00169   if (level < 0 || level > ts->level)
00170     return -1;
00171   for (level = ts->level - level; level > 0; --level)
00172     ts = &ts->team->prev_ts;
00173   return ts->team_id;
00174 }
00175 
00176 int
00177 omp_get_team_size (int level)
00178 {
00179   struct gomp_team_state *ts = &gomp_thread ()->ts;
00180   if (level < 0 || level > ts->level)
00181     return -1;
00182   for (level = ts->level - level; level > 0; --level)
00183     ts = &ts->team->prev_ts;
00184   if (ts->team == NULL)
00185     return 1;
00186   else
00187     return ts->team->nthreads;
00188 }
00189 
00190 int
00191 omp_get_active_level (void)
00192 {
00193   return gomp_thread ()->ts.active_level;
00194 }
00195 
00196 ialias (omp_get_num_threads)
00197 ialias (omp_get_thread_num)
00198 ialias (omp_in_parallel)
00199 ialias (omp_get_level)
00200 ialias (omp_get_ancestor_thread_num)
00201 ialias (omp_get_team_size)
00202 ialias (omp_get_active_level)

Generated on Fri Apr 5 05:38:10 2013 for Libgomp by  doxygen 1.4.7