loop_ull.c

Go to the documentation of this file.
00001 /* Copyright (C) 2005, 2008, 2009 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 LOOP (FOR/DO) construct.  */
00026 
00027 #include <limits.h>
00028 #include <stdlib.h>
00029 #include "libgomp.h"
00030 
00031 typedef unsigned long long gomp_ull;
00032 
00033 /* Initialize the given work share construct from the given arguments.  */
00034 
00035 static inline void
00036 gomp_loop_ull_init (struct gomp_work_share *ws, bool up, gomp_ull start,
00037             gomp_ull end, gomp_ull incr, enum gomp_schedule_type sched,
00038             gomp_ull chunk_size)
00039 {
00040   ws->sched = sched;
00041   ws->chunk_size_ull = chunk_size;
00042   /* Canonicalize loops that have zero iterations to ->next == ->end.  */
00043   ws->end_ull = ((up && start > end) || (!up && start < end))
00044         ? start : end;
00045   ws->incr_ull = incr;
00046   ws->next_ull = start;
00047   ws->mode = 0;
00048   if (sched == GFS_DYNAMIC)
00049     {
00050       ws->chunk_size_ull *= incr;
00051 
00052 #if defined HAVE_SYNC_BUILTINS && defined __LP64__
00053       {
00054     /* For dynamic scheduling prepare things to make each iteration
00055        faster.  */
00056     struct gomp_thread *thr = gomp_thread ();
00057     struct gomp_team *team = thr->ts.team;
00058     long nthreads = team ? team->nthreads : 1;
00059 
00060     if (__builtin_expect (up, 1))
00061       {
00062         /* Cheap overflow protection.  */
00063         if (__builtin_expect ((nthreads | ws->chunk_size_ull)
00064                   < 1ULL << (sizeof (gomp_ull)
00065                          * __CHAR_BIT__ / 2 - 1), 1))
00066           ws->mode = ws->end_ull < (__LONG_LONG_MAX__ * 2ULL + 1
00067                     - (nthreads + 1) * ws->chunk_size_ull);
00068       }
00069     /* Cheap overflow protection.  */
00070     else if (__builtin_expect ((nthreads | -ws->chunk_size_ull)
00071                    < 1ULL << (sizeof (gomp_ull)
00072                           * __CHAR_BIT__ / 2 - 1), 1))
00073       ws->mode = ws->end_ull > ((nthreads + 1) * -ws->chunk_size_ull
00074                     - (__LONG_LONG_MAX__ * 2ULL + 1));
00075       }
00076 #endif
00077     }
00078   if (!up)
00079     ws->mode |= 2;
00080 }
00081 
00082 /* The *_start routines are called when first encountering a loop construct
00083    that is not bound directly to a parallel construct.  The first thread
00084    that arrives will create the work-share construct; subsequent threads
00085    will see the construct exists and allocate work from it.
00086 
00087    START, END, INCR are the bounds of the loop; due to the restrictions of
00088    OpenMP, these values must be the same in every thread.  This is not
00089    verified (nor is it entirely verifiable, since START is not necessarily
00090    retained intact in the work-share data structure).  CHUNK_SIZE is the
00091    scheduling parameter; again this must be identical in all threads.
00092 
00093    Returns true if there's any work for this thread to perform.  If so,
00094    *ISTART and *IEND are filled with the bounds of the iteration block
00095    allocated to this thread.  Returns false if all work was assigned to
00096    other threads prior to this thread's arrival.  */
00097 
00098 static bool
00099 gomp_loop_ull_static_start (bool up, gomp_ull start, gomp_ull end,
00100                 gomp_ull incr, gomp_ull chunk_size,
00101                 gomp_ull *istart, gomp_ull *iend)
00102 {
00103   struct gomp_thread *thr = gomp_thread ();
00104 
00105   thr->ts.static_trip = 0;
00106   if (gomp_work_share_start (false))
00107     {
00108       gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
00109               GFS_STATIC, chunk_size);
00110       gomp_work_share_init_done ();
00111     }
00112 
00113   return !gomp_iter_ull_static_next (istart, iend);
00114 }
00115 
00116 static bool
00117 gomp_loop_ull_dynamic_start (bool up, gomp_ull start, gomp_ull end,
00118                  gomp_ull incr, gomp_ull chunk_size,
00119                  gomp_ull *istart, gomp_ull *iend)
00120 {
00121   struct gomp_thread *thr = gomp_thread ();
00122   bool ret;
00123 
00124   if (gomp_work_share_start (false))
00125     {
00126       gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
00127               GFS_DYNAMIC, chunk_size);
00128       gomp_work_share_init_done ();
00129     }
00130 
00131 #if defined HAVE_SYNC_BUILTINS && defined __LP64__
00132   ret = gomp_iter_ull_dynamic_next (istart, iend);
00133 #else
00134   gomp_mutex_lock (&thr->ts.work_share->lock);
00135   ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
00136   gomp_mutex_unlock (&thr->ts.work_share->lock);
00137 #endif
00138 
00139   return ret;
00140 }
00141 
00142 static bool
00143 gomp_loop_ull_guided_start (bool up, gomp_ull start, gomp_ull end,
00144                 gomp_ull incr, gomp_ull chunk_size,
00145                 gomp_ull *istart, gomp_ull *iend)
00146 {
00147   struct gomp_thread *thr = gomp_thread ();
00148   bool ret;
00149 
00150   if (gomp_work_share_start (false))
00151     {
00152       gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
00153               GFS_GUIDED, chunk_size);
00154       gomp_work_share_init_done ();
00155     }
00156 
00157 #if defined HAVE_SYNC_BUILTINS && defined __LP64__
00158   ret = gomp_iter_ull_guided_next (istart, iend);
00159 #else
00160   gomp_mutex_lock (&thr->ts.work_share->lock);
00161   ret = gomp_iter_ull_guided_next_locked (istart, iend);
00162   gomp_mutex_unlock (&thr->ts.work_share->lock);
00163 #endif
00164 
00165   return ret;
00166 }
00167 
00168 bool
00169 GOMP_loop_ull_runtime_start (bool up, gomp_ull start, gomp_ull end,
00170                  gomp_ull incr, gomp_ull *istart, gomp_ull *iend)
00171 {
00172   struct gomp_task_icv *icv = gomp_icv (false);
00173   switch (icv->run_sched_var)
00174     {
00175     case GFS_STATIC:
00176       return gomp_loop_ull_static_start (up, start, end, incr,
00177                      icv->run_sched_modifier,
00178                      istart, iend);
00179     case GFS_DYNAMIC:
00180       return gomp_loop_ull_dynamic_start (up, start, end, incr,
00181                       icv->run_sched_modifier,
00182                       istart, iend);
00183     case GFS_GUIDED:
00184       return gomp_loop_ull_guided_start (up, start, end, incr,
00185                      icv->run_sched_modifier,
00186                      istart, iend);
00187     case GFS_AUTO:
00188       /* For now map to schedule(static), later on we could play with feedback
00189      driven choice.  */
00190       return gomp_loop_ull_static_start (up, start, end, incr,
00191                      0, istart, iend);
00192     default:
00193       abort ();
00194     }
00195 }
00196 
00197 /* The *_ordered_*_start routines are similar.  The only difference is that
00198    this work-share construct is initialized to expect an ORDERED section.  */
00199 
00200 static bool
00201 gomp_loop_ull_ordered_static_start (bool up, gomp_ull start, gomp_ull end,
00202                     gomp_ull incr, gomp_ull chunk_size,
00203                     gomp_ull *istart, gomp_ull *iend)
00204 {
00205   struct gomp_thread *thr = gomp_thread ();
00206 
00207   thr->ts.static_trip = 0;
00208   if (gomp_work_share_start (true))
00209     {
00210       gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
00211               GFS_STATIC, chunk_size);
00212       gomp_ordered_static_init ();
00213       gomp_work_share_init_done ();
00214     }
00215 
00216   return !gomp_iter_ull_static_next (istart, iend);
00217 }
00218 
00219 static bool
00220 gomp_loop_ull_ordered_dynamic_start (bool up, gomp_ull start, gomp_ull end,
00221                      gomp_ull incr, gomp_ull chunk_size,
00222                      gomp_ull *istart, gomp_ull *iend)
00223 {
00224   struct gomp_thread *thr = gomp_thread ();
00225   bool ret;
00226 
00227   if (gomp_work_share_start (true))
00228     {
00229       gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
00230               GFS_DYNAMIC, chunk_size);
00231       gomp_mutex_lock (&thr->ts.work_share->lock);
00232       gomp_work_share_init_done ();
00233     }
00234   else
00235     gomp_mutex_lock (&thr->ts.work_share->lock);
00236 
00237   ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
00238   if (ret)
00239     gomp_ordered_first ();
00240   gomp_mutex_unlock (&thr->ts.work_share->lock);
00241 
00242   return ret;
00243 }
00244 
00245 static bool
00246 gomp_loop_ull_ordered_guided_start (bool up, gomp_ull start, gomp_ull end,
00247                     gomp_ull incr, gomp_ull chunk_size,
00248                     gomp_ull *istart, gomp_ull *iend)
00249 {
00250   struct gomp_thread *thr = gomp_thread ();
00251   bool ret;
00252 
00253   if (gomp_work_share_start (true))
00254     {
00255       gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
00256               GFS_GUIDED, chunk_size);
00257       gomp_mutex_lock (&thr->ts.work_share->lock);
00258       gomp_work_share_init_done ();
00259     }
00260   else
00261     gomp_mutex_lock (&thr->ts.work_share->lock);
00262 
00263   ret = gomp_iter_ull_guided_next_locked (istart, iend);
00264   if (ret)
00265     gomp_ordered_first ();
00266   gomp_mutex_unlock (&thr->ts.work_share->lock);
00267 
00268   return ret;
00269 }
00270 
00271 bool
00272 GOMP_loop_ull_ordered_runtime_start (bool up, gomp_ull start, gomp_ull end,
00273                      gomp_ull incr, gomp_ull *istart,
00274                      gomp_ull *iend)
00275 {
00276   struct gomp_task_icv *icv = gomp_icv (false);
00277   switch (icv->run_sched_var)
00278     {
00279     case GFS_STATIC:
00280       return gomp_loop_ull_ordered_static_start (up, start, end, incr,
00281                          icv->run_sched_modifier,
00282                          istart, iend);
00283     case GFS_DYNAMIC:
00284       return gomp_loop_ull_ordered_dynamic_start (up, start, end, incr,
00285                           icv->run_sched_modifier,
00286                           istart, iend);
00287     case GFS_GUIDED:
00288       return gomp_loop_ull_ordered_guided_start (up, start, end, incr,
00289                          icv->run_sched_modifier,
00290                          istart, iend);
00291     case GFS_AUTO:
00292       /* For now map to schedule(static), later on we could play with feedback
00293      driven choice.  */
00294       return gomp_loop_ull_ordered_static_start (up, start, end, incr,
00295                          0, istart, iend);
00296     default:
00297       abort ();
00298     }
00299 }
00300 
00301 /* The *_next routines are called when the thread completes processing of
00302    the iteration block currently assigned to it.  If the work-share
00303    construct is bound directly to a parallel construct, then the iteration
00304    bounds may have been set up before the parallel.  In which case, this
00305    may be the first iteration for the thread.
00306 
00307    Returns true if there is work remaining to be performed; *ISTART and
00308    *IEND are filled with a new iteration block.  Returns false if all work
00309    has been assigned.  */
00310 
00311 static bool
00312 gomp_loop_ull_static_next (gomp_ull *istart, gomp_ull *iend)
00313 {
00314   return !gomp_iter_ull_static_next (istart, iend);
00315 }
00316 
00317 static bool
00318 gomp_loop_ull_dynamic_next (gomp_ull *istart, gomp_ull *iend)
00319 {
00320   bool ret;
00321 
00322 #if defined HAVE_SYNC_BUILTINS && defined __LP64__
00323   ret = gomp_iter_ull_dynamic_next (istart, iend);
00324 #else
00325   struct gomp_thread *thr = gomp_thread ();
00326   gomp_mutex_lock (&thr->ts.work_share->lock);
00327   ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
00328   gomp_mutex_unlock (&thr->ts.work_share->lock);
00329 #endif
00330 
00331   return ret;
00332 }
00333 
00334 static bool
00335 gomp_loop_ull_guided_next (gomp_ull *istart, gomp_ull *iend)
00336 {
00337   bool ret;
00338 
00339 #if defined HAVE_SYNC_BUILTINS && defined __LP64__
00340   ret = gomp_iter_ull_guided_next (istart, iend);
00341 #else
00342   struct gomp_thread *thr = gomp_thread ();
00343   gomp_mutex_lock (&thr->ts.work_share->lock);
00344   ret = gomp_iter_ull_guided_next_locked (istart, iend);
00345   gomp_mutex_unlock (&thr->ts.work_share->lock);
00346 #endif
00347 
00348   return ret;
00349 }
00350 
00351 bool
00352 GOMP_loop_ull_runtime_next (gomp_ull *istart, gomp_ull *iend)
00353 {
00354   struct gomp_thread *thr = gomp_thread ();
00355 
00356   switch (thr->ts.work_share->sched)
00357     {
00358     case GFS_STATIC:
00359     case GFS_AUTO:
00360       return gomp_loop_ull_static_next (istart, iend);
00361     case GFS_DYNAMIC:
00362       return gomp_loop_ull_dynamic_next (istart, iend);
00363     case GFS_GUIDED:
00364       return gomp_loop_ull_guided_next (istart, iend);
00365     default:
00366       abort ();
00367     }
00368 }
00369 
00370 /* The *_ordered_*_next routines are called when the thread completes
00371    processing of the iteration block currently assigned to it.
00372 
00373    Returns true if there is work remaining to be performed; *ISTART and
00374    *IEND are filled with a new iteration block.  Returns false if all work
00375    has been assigned.  */
00376 
00377 static bool
00378 gomp_loop_ull_ordered_static_next (gomp_ull *istart, gomp_ull *iend)
00379 {
00380   struct gomp_thread *thr = gomp_thread ();
00381   int test;
00382 
00383   gomp_ordered_sync ();
00384   gomp_mutex_lock (&thr->ts.work_share->lock);
00385   test = gomp_iter_ull_static_next (istart, iend);
00386   if (test >= 0)
00387     gomp_ordered_static_next ();
00388   gomp_mutex_unlock (&thr->ts.work_share->lock);
00389 
00390   return test == 0;
00391 }
00392 
00393 static bool
00394 gomp_loop_ull_ordered_dynamic_next (gomp_ull *istart, gomp_ull *iend)
00395 {
00396   struct gomp_thread *thr = gomp_thread ();
00397   bool ret;
00398 
00399   gomp_ordered_sync ();
00400   gomp_mutex_lock (&thr->ts.work_share->lock);
00401   ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
00402   if (ret)
00403     gomp_ordered_next ();
00404   else
00405     gomp_ordered_last ();
00406   gomp_mutex_unlock (&thr->ts.work_share->lock);
00407 
00408   return ret;
00409 }
00410 
00411 static bool
00412 gomp_loop_ull_ordered_guided_next (gomp_ull *istart, gomp_ull *iend)
00413 {
00414   struct gomp_thread *thr = gomp_thread ();
00415   bool ret;
00416 
00417   gomp_ordered_sync ();
00418   gomp_mutex_lock (&thr->ts.work_share->lock);
00419   ret = gomp_iter_ull_guided_next_locked (istart, iend);
00420   if (ret)
00421     gomp_ordered_next ();
00422   else
00423     gomp_ordered_last ();
00424   gomp_mutex_unlock (&thr->ts.work_share->lock);
00425 
00426   return ret;
00427 }
00428 
00429 bool
00430 GOMP_loop_ull_ordered_runtime_next (gomp_ull *istart, gomp_ull *iend)
00431 {
00432   struct gomp_thread *thr = gomp_thread ();
00433 
00434   switch (thr->ts.work_share->sched)
00435     {
00436     case GFS_STATIC:
00437     case GFS_AUTO:
00438       return gomp_loop_ull_ordered_static_next (istart, iend);
00439     case GFS_DYNAMIC:
00440       return gomp_loop_ull_ordered_dynamic_next (istart, iend);
00441     case GFS_GUIDED:
00442       return gomp_loop_ull_ordered_guided_next (istart, iend);
00443     default:
00444       abort ();
00445     }
00446 }
00447 
00448 /* We use static functions above so that we're sure that the "runtime"
00449    function can defer to the proper routine without interposition.  We
00450    export the static function with a strong alias when possible, or with
00451    a wrapper function otherwise.  */
00452 
00453 #ifdef HAVE_ATTRIBUTE_ALIAS
00454 extern __typeof(gomp_loop_ull_static_start) GOMP_loop_ull_static_start
00455     __attribute__((alias ("gomp_loop_ull_static_start")));
00456 extern __typeof(gomp_loop_ull_dynamic_start) GOMP_loop_ull_dynamic_start
00457     __attribute__((alias ("gomp_loop_ull_dynamic_start")));
00458 extern __typeof(gomp_loop_ull_guided_start) GOMP_loop_ull_guided_start
00459     __attribute__((alias ("gomp_loop_ull_guided_start")));
00460 
00461 extern __typeof(gomp_loop_ull_ordered_static_start) GOMP_loop_ull_ordered_static_start
00462     __attribute__((alias ("gomp_loop_ull_ordered_static_start")));
00463 extern __typeof(gomp_loop_ull_ordered_dynamic_start) GOMP_loop_ull_ordered_dynamic_start
00464     __attribute__((alias ("gomp_loop_ull_ordered_dynamic_start")));
00465 extern __typeof(gomp_loop_ull_ordered_guided_start) GOMP_loop_ull_ordered_guided_start
00466     __attribute__((alias ("gomp_loop_ull_ordered_guided_start")));
00467 
00468 extern __typeof(gomp_loop_ull_static_next) GOMP_loop_ull_static_next
00469     __attribute__((alias ("gomp_loop_ull_static_next")));
00470 extern __typeof(gomp_loop_ull_dynamic_next) GOMP_loop_ull_dynamic_next
00471     __attribute__((alias ("gomp_loop_ull_dynamic_next")));
00472 extern __typeof(gomp_loop_ull_guided_next) GOMP_loop_ull_guided_next
00473     __attribute__((alias ("gomp_loop_ull_guided_next")));
00474 
00475 extern __typeof(gomp_loop_ull_ordered_static_next) GOMP_loop_ull_ordered_static_next
00476     __attribute__((alias ("gomp_loop_ull_ordered_static_next")));
00477 extern __typeof(gomp_loop_ull_ordered_dynamic_next) GOMP_loop_ull_ordered_dynamic_next
00478     __attribute__((alias ("gomp_loop_ull_ordered_dynamic_next")));
00479 extern __typeof(gomp_loop_ull_ordered_guided_next) GOMP_loop_ull_ordered_guided_next
00480     __attribute__((alias ("gomp_loop_ull_ordered_guided_next")));
00481 #else
00482 bool
00483 GOMP_loop_ull_static_start (bool up, gomp_ull start, gomp_ull end,
00484                 gomp_ull incr, gomp_ull chunk_size,
00485                 gomp_ull *istart, gomp_ull *iend)
00486 {
00487   return gomp_loop_ull_static_start (up, start, end, incr, chunk_size, istart,
00488                      iend);
00489 }
00490 
00491 bool
00492 GOMP_loop_ull_dynamic_start (bool up, gomp_ull start, gomp_ull end,
00493                  gomp_ull incr, gomp_ull chunk_size,
00494                  gomp_ull *istart, gomp_ull *iend)
00495 {
00496   return gomp_loop_ull_dynamic_start (up, start, end, incr, chunk_size, istart,
00497                       iend);
00498 }
00499 
00500 bool
00501 GOMP_loop_ull_guided_start (bool up, gomp_ull start, gomp_ull end,
00502                 gomp_ull incr, gomp_ull chunk_size,
00503                 gomp_ull *istart, gomp_ull *iend)
00504 {
00505   return gomp_loop_ull_guided_start (up, start, end, incr, chunk_size, istart,
00506                      iend);
00507 }
00508 
00509 bool
00510 GOMP_loop_ull_ordered_static_start (bool up, gomp_ull start, gomp_ull end,
00511                     gomp_ull incr, gomp_ull chunk_size,
00512                     gomp_ull *istart, gomp_ull *iend)
00513 {
00514   return gomp_loop_ull_ordered_static_start (up, start, end, incr, chunk_size,
00515                          istart, iend);
00516 }
00517 
00518 bool
00519 GOMP_loop_ull_ordered_dynamic_start (bool up, gomp_ull start, gomp_ull end,
00520                      gomp_ull incr, gomp_ull chunk_size,
00521                      gomp_ull *istart, gomp_ull *iend)
00522 {
00523   return gomp_loop_ull_ordered_dynamic_start (up, start, end, incr, chunk_size,
00524                           istart, iend);
00525 }
00526 
00527 bool
00528 GOMP_loop_ull_ordered_guided_start (bool up, gomp_ull start, gomp_ull end,
00529                     gomp_ull incr, gomp_ull chunk_size,
00530                     gomp_ull *istart, gomp_ull *iend)
00531 {
00532   return gomp_loop_ull_ordered_guided_start (up, start, end, incr, chunk_size,
00533                          istart, iend);
00534 }
00535 
00536 bool
00537 GOMP_loop_ull_static_next (gomp_ull *istart, gomp_ull *iend)
00538 {
00539   return gomp_loop_ull_static_next (istart, iend);
00540 }
00541 
00542 bool
00543 GOMP_loop_ull_dynamic_next (gomp_ull *istart, gomp_ull *iend)
00544 {
00545   return gomp_loop_ull_dynamic_next (istart, iend);
00546 }
00547 
00548 bool
00549 GOMP_loop_ull_guided_next (gomp_ull *istart, gomp_ull *iend)
00550 {
00551   return gomp_loop_ull_guided_next (istart, iend);
00552 }
00553 
00554 bool
00555 GOMP_loop_ull_ordered_static_next (gomp_ull *istart, gomp_ull *iend)
00556 {
00557   return gomp_loop_ull_ordered_static_next (istart, iend);
00558 }
00559 
00560 bool
00561 GOMP_loop_ull_ordered_dynamic_next (gomp_ull *istart, gomp_ull *iend)
00562 {
00563   return gomp_loop_ull_ordered_dynamic_next (istart, iend);
00564 }
00565 
00566 bool
00567 GOMP_loop_ull_ordered_guided_next (gomp_ull *istart, gomp_ull *iend)
00568 {
00569   return gomp_loop_ull_ordered_guided_next (istart, iend);
00570 }
00571 #endif

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