LLVM OpenMP* Runtime Library
kmp_dispatch.cpp
1 /*
2  * kmp_dispatch.cpp: dynamic scheduling - iteration initialization and dispatch.
3  */
4 
5 //===----------------------------------------------------------------------===//
6 //
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
10 //
11 //===----------------------------------------------------------------------===//
12 
13 /* Dynamic scheduling initialization and dispatch.
14  *
15  * NOTE: __kmp_nth is a constant inside of any dispatch loop, however
16  * it may change values between parallel regions. __kmp_max_nth
17  * is the largest value __kmp_nth may take, 1 is the smallest.
18  */
19 
20 #include "kmp.h"
21 #include "kmp_error.h"
22 #include "kmp_i18n.h"
23 #include "kmp_itt.h"
24 #include "kmp_stats.h"
25 #include "kmp_str.h"
26 #if KMP_USE_X87CONTROL
27 #include <float.h>
28 #endif
29 #include "kmp_lock.h"
30 #include "kmp_dispatch.h"
31 #if KMP_USE_HIER_SCHED
32 #include "kmp_dispatch_hier.h"
33 #endif
34 
35 #if OMPT_SUPPORT
36 #include "ompt-specific.h"
37 #endif
38 
39 /* ------------------------------------------------------------------------ */
40 /* ------------------------------------------------------------------------ */
41 
42 void __kmp_dispatch_deo_error(int *gtid_ref, int *cid_ref, ident_t *loc_ref) {
43  kmp_info_t *th;
44 
45  KMP_DEBUG_ASSERT(gtid_ref);
46 
47  if (__kmp_env_consistency_check) {
48  th = __kmp_threads[*gtid_ref];
49  if (th->th.th_root->r.r_active &&
50  (th->th.th_dispatch->th_dispatch_pr_current->pushed_ws != ct_none)) {
51 #if KMP_USE_DYNAMIC_LOCK
52  __kmp_push_sync(*gtid_ref, ct_ordered_in_pdo, loc_ref, NULL, 0);
53 #else
54  __kmp_push_sync(*gtid_ref, ct_ordered_in_pdo, loc_ref, NULL);
55 #endif
56  }
57  }
58 }
59 
60 void __kmp_dispatch_dxo_error(int *gtid_ref, int *cid_ref, ident_t *loc_ref) {
61  kmp_info_t *th;
62 
63  if (__kmp_env_consistency_check) {
64  th = __kmp_threads[*gtid_ref];
65  if (th->th.th_dispatch->th_dispatch_pr_current->pushed_ws != ct_none) {
66  __kmp_pop_sync(*gtid_ref, ct_ordered_in_pdo, loc_ref);
67  }
68  }
69 }
70 
71 // Returns either SCHEDULE_MONOTONIC or SCHEDULE_NONMONOTONIC
72 static inline int __kmp_get_monotonicity(enum sched_type schedule,
73  bool use_hier = false) {
74  // Pick up the nonmonotonic/monotonic bits from the scheduling type
75  int monotonicity;
76  // default to monotonic
77  monotonicity = SCHEDULE_MONOTONIC;
78  if (SCHEDULE_HAS_NONMONOTONIC(schedule))
79  monotonicity = SCHEDULE_NONMONOTONIC;
80  else if (SCHEDULE_HAS_MONOTONIC(schedule))
81  monotonicity = SCHEDULE_MONOTONIC;
82  return monotonicity;
83 }
84 
85 // Initialize a dispatch_private_info_template<T> buffer for a particular
86 // type of schedule,chunk. The loop description is found in lb (lower bound),
87 // ub (upper bound), and st (stride). nproc is the number of threads relevant
88 // to the scheduling (often the number of threads in a team, but not always if
89 // hierarchical scheduling is used). tid is the id of the thread calling
90 // the function within the group of nproc threads. It will have a value
91 // between 0 and nproc - 1. This is often just the thread id within a team, but
92 // is not necessarily the case when using hierarchical scheduling.
93 // loc is the source file location of the corresponding loop
94 // gtid is the global thread id
95 template <typename T>
96 void __kmp_dispatch_init_algorithm(ident_t *loc, int gtid,
97  dispatch_private_info_template<T> *pr,
98  enum sched_type schedule, T lb, T ub,
99  typename traits_t<T>::signed_t st,
100 #if USE_ITT_BUILD
101  kmp_uint64 *cur_chunk,
102 #endif
103  typename traits_t<T>::signed_t chunk,
104  T nproc, T tid) {
105  typedef typename traits_t<T>::unsigned_t UT;
106  typedef typename traits_t<T>::floating_t DBL;
107 
108  int active;
109  T tc;
110  kmp_info_t *th;
111  kmp_team_t *team;
112  int monotonicity;
113  bool use_hier;
114 
115 #ifdef KMP_DEBUG
116  typedef typename traits_t<T>::signed_t ST;
117  {
118  char *buff;
119  // create format specifiers before the debug output
120  buff = __kmp_str_format("__kmp_dispatch_init_algorithm: T#%%d called "
121  "pr:%%p lb:%%%s ub:%%%s st:%%%s "
122  "schedule:%%d chunk:%%%s nproc:%%%s tid:%%%s\n",
123  traits_t<T>::spec, traits_t<T>::spec,
124  traits_t<ST>::spec, traits_t<ST>::spec,
125  traits_t<T>::spec, traits_t<T>::spec);
126  KD_TRACE(10, (buff, gtid, pr, lb, ub, st, schedule, chunk, nproc, tid));
127  __kmp_str_free(&buff);
128  }
129 #endif
130  /* setup data */
131  th = __kmp_threads[gtid];
132  team = th->th.th_team;
133  active = !team->t.t_serialized;
134 
135 #if USE_ITT_BUILD
136  int itt_need_metadata_reporting =
137  __itt_metadata_add_ptr && __kmp_forkjoin_frames_mode == 3 &&
138  KMP_MASTER_GTID(gtid) && th->th.th_teams_microtask == NULL &&
139  team->t.t_active_level == 1;
140 #endif
141 
142 #if KMP_USE_HIER_SCHED
143  use_hier = pr->flags.use_hier;
144 #else
145  use_hier = false;
146 #endif
147 
148  /* Pick up the nonmonotonic/monotonic bits from the scheduling type */
149  monotonicity = __kmp_get_monotonicity(schedule, use_hier);
150  schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
151 
152  /* Pick up the nomerge/ordered bits from the scheduling type */
153  if ((schedule >= kmp_nm_lower) && (schedule < kmp_nm_upper)) {
154  pr->flags.nomerge = TRUE;
155  schedule =
156  (enum sched_type)(((int)schedule) - (kmp_nm_lower - kmp_sch_lower));
157  } else {
158  pr->flags.nomerge = FALSE;
159  }
160  pr->type_size = traits_t<T>::type_size; // remember the size of variables
161  if (kmp_ord_lower & schedule) {
162  pr->flags.ordered = TRUE;
163  schedule =
164  (enum sched_type)(((int)schedule) - (kmp_ord_lower - kmp_sch_lower));
165  } else {
166  pr->flags.ordered = FALSE;
167  }
168  // Ordered overrides nonmonotonic
169  if (pr->flags.ordered) {
170  monotonicity = SCHEDULE_MONOTONIC;
171  }
172 
173  if (schedule == kmp_sch_static) {
174  schedule = __kmp_static;
175  } else {
176  if (schedule == kmp_sch_runtime) {
177  // Use the scheduling specified by OMP_SCHEDULE (or __kmp_sch_default if
178  // not specified)
179  schedule = team->t.t_sched.r_sched_type;
180  monotonicity = __kmp_get_monotonicity(schedule, use_hier);
181  schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
182  // Detail the schedule if needed (global controls are differentiated
183  // appropriately)
184  if (schedule == kmp_sch_guided_chunked) {
185  schedule = __kmp_guided;
186  } else if (schedule == kmp_sch_static) {
187  schedule = __kmp_static;
188  }
189  // Use the chunk size specified by OMP_SCHEDULE (or default if not
190  // specified)
191  chunk = team->t.t_sched.chunk;
192 #if USE_ITT_BUILD
193  if (cur_chunk)
194  *cur_chunk = chunk;
195 #endif
196 #ifdef KMP_DEBUG
197  {
198  char *buff;
199  // create format specifiers before the debug output
200  buff = __kmp_str_format("__kmp_dispatch_init_algorithm: T#%%d new: "
201  "schedule:%%d chunk:%%%s\n",
202  traits_t<ST>::spec);
203  KD_TRACE(10, (buff, gtid, schedule, chunk));
204  __kmp_str_free(&buff);
205  }
206 #endif
207  } else {
208  if (schedule == kmp_sch_guided_chunked) {
209  schedule = __kmp_guided;
210  }
211  if (chunk <= 0) {
212  chunk = KMP_DEFAULT_CHUNK;
213  }
214  }
215 
216  if (schedule == kmp_sch_auto) {
217  // mapping and differentiation: in the __kmp_do_serial_initialize()
218  schedule = __kmp_auto;
219 #ifdef KMP_DEBUG
220  {
221  char *buff;
222  // create format specifiers before the debug output
223  buff = __kmp_str_format(
224  "__kmp_dispatch_init_algorithm: kmp_sch_auto: T#%%d new: "
225  "schedule:%%d chunk:%%%s\n",
226  traits_t<ST>::spec);
227  KD_TRACE(10, (buff, gtid, schedule, chunk));
228  __kmp_str_free(&buff);
229  }
230 #endif
231  }
232 #if KMP_STATIC_STEAL_ENABLED
233  // map nonmonotonic:dynamic to static steal
234  if (schedule == kmp_sch_dynamic_chunked) {
235  if (monotonicity == SCHEDULE_NONMONOTONIC)
236  schedule = kmp_sch_static_steal;
237  }
238 #endif
239  /* guided analytical not safe for too many threads */
240  if (schedule == kmp_sch_guided_analytical_chunked && nproc > 1 << 20) {
241  schedule = kmp_sch_guided_iterative_chunked;
242  KMP_WARNING(DispatchManyThreads);
243  }
244  if (schedule == kmp_sch_runtime_simd) {
245  // compiler provides simd_width in the chunk parameter
246  schedule = team->t.t_sched.r_sched_type;
247  monotonicity = __kmp_get_monotonicity(schedule, use_hier);
248  schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
249  // Detail the schedule if needed (global controls are differentiated
250  // appropriately)
251  if (schedule == kmp_sch_static || schedule == kmp_sch_auto ||
252  schedule == __kmp_static) {
253  schedule = kmp_sch_static_balanced_chunked;
254  } else {
255  if (schedule == kmp_sch_guided_chunked || schedule == __kmp_guided) {
256  schedule = kmp_sch_guided_simd;
257  }
258  chunk = team->t.t_sched.chunk * chunk;
259  }
260 #if USE_ITT_BUILD
261  if (cur_chunk)
262  *cur_chunk = chunk;
263 #endif
264 #ifdef KMP_DEBUG
265  {
266  char *buff;
267  // create format specifiers before the debug output
268  buff = __kmp_str_format(
269  "__kmp_dispatch_init_algorithm: T#%%d new: schedule:%%d"
270  " chunk:%%%s\n",
271  traits_t<ST>::spec);
272  KD_TRACE(10, (buff, gtid, schedule, chunk));
273  __kmp_str_free(&buff);
274  }
275 #endif
276  }
277  pr->u.p.parm1 = chunk;
278  }
279  KMP_ASSERT2((kmp_sch_lower < schedule && schedule < kmp_sch_upper),
280  "unknown scheduling type");
281 
282  pr->u.p.count = 0;
283 
284  if (__kmp_env_consistency_check) {
285  if (st == 0) {
286  __kmp_error_construct(kmp_i18n_msg_CnsLoopIncrZeroProhibited,
287  (pr->flags.ordered ? ct_pdo_ordered : ct_pdo), loc);
288  }
289  }
290  // compute trip count
291  if (st == 1) { // most common case
292  if (ub >= lb) {
293  tc = ub - lb + 1;
294  } else { // ub < lb
295  tc = 0; // zero-trip
296  }
297  } else if (st < 0) {
298  if (lb >= ub) {
299  // AC: cast to unsigned is needed for loops like (i=2B; i>-2B; i-=1B),
300  // where the division needs to be unsigned regardless of the result type
301  tc = (UT)(lb - ub) / (-st) + 1;
302  } else { // lb < ub
303  tc = 0; // zero-trip
304  }
305  } else { // st > 0
306  if (ub >= lb) {
307  // AC: cast to unsigned is needed for loops like (i=-2B; i<2B; i+=1B),
308  // where the division needs to be unsigned regardless of the result type
309  tc = (UT)(ub - lb) / st + 1;
310  } else { // ub < lb
311  tc = 0; // zero-trip
312  }
313  }
314 
315 #if KMP_STATS_ENABLED
316  if (KMP_MASTER_GTID(gtid)) {
317  KMP_COUNT_VALUE(OMP_loop_dynamic_total_iterations, tc);
318  }
319 #endif
320 
321  pr->u.p.lb = lb;
322  pr->u.p.ub = ub;
323  pr->u.p.st = st;
324  pr->u.p.tc = tc;
325 
326 #if KMP_OS_WINDOWS
327  pr->u.p.last_upper = ub + st;
328 #endif /* KMP_OS_WINDOWS */
329 
330  /* NOTE: only the active parallel region(s) has active ordered sections */
331 
332  if (active) {
333  if (pr->flags.ordered) {
334  pr->ordered_bumped = 0;
335  pr->u.p.ordered_lower = 1;
336  pr->u.p.ordered_upper = 0;
337  }
338  }
339 
340  switch (schedule) {
341 #if (KMP_STATIC_STEAL_ENABLED)
342  case kmp_sch_static_steal: {
343  T ntc, init;
344 
345  KD_TRACE(100,
346  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_steal case\n",
347  gtid));
348 
349  ntc = (tc % chunk ? 1 : 0) + tc / chunk;
350  if (nproc > 1 && ntc >= nproc) {
351  KMP_COUNT_BLOCK(OMP_LOOP_STATIC_STEAL);
352  T id = tid;
353  T small_chunk, extras;
354 
355  small_chunk = ntc / nproc;
356  extras = ntc % nproc;
357 
358  init = id * small_chunk + (id < extras ? id : extras);
359  pr->u.p.count = init;
360  pr->u.p.ub = init + small_chunk + (id < extras ? 1 : 0);
361 
362  pr->u.p.parm2 = lb;
363  // parm3 is the number of times to attempt stealing which is
364  // proportional to the number of chunks per thread up until
365  // the maximum value of nproc.
366  pr->u.p.parm3 = KMP_MIN(small_chunk + extras, nproc);
367  pr->u.p.parm4 = (id + 1) % nproc; // remember neighbour tid
368  pr->u.p.st = st;
369  if (traits_t<T>::type_size > 4) {
370  // AC: TODO: check if 16-byte CAS available and use it to
371  // improve performance (probably wait for explicit request
372  // before spending time on this).
373  // For now use dynamically allocated per-thread lock,
374  // free memory in __kmp_dispatch_next when status==0.
375  KMP_DEBUG_ASSERT(th->th.th_dispatch->th_steal_lock == NULL);
376  th->th.th_dispatch->th_steal_lock =
377  (kmp_lock_t *)__kmp_allocate(sizeof(kmp_lock_t));
378  __kmp_init_lock(th->th.th_dispatch->th_steal_lock);
379  }
380  break;
381  } else {
382  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d falling-through to "
383  "kmp_sch_static_balanced\n",
384  gtid));
385  schedule = kmp_sch_static_balanced;
386  /* too few iterations: fall-through to kmp_sch_static_balanced */
387  } // if
388  /* FALL-THROUGH to static balanced */
389  KMP_FALLTHROUGH();
390  } // case
391 #endif
392  case kmp_sch_static_balanced: {
393  T init, limit;
394 
395  KD_TRACE(
396  100,
397  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_balanced case\n",
398  gtid));
399 
400  if (nproc > 1) {
401  T id = tid;
402 
403  if (tc < nproc) {
404  if (id < tc) {
405  init = id;
406  limit = id;
407  pr->u.p.parm1 = (id == tc - 1); /* parm1 stores *plastiter */
408  } else {
409  pr->u.p.count = 1; /* means no more chunks to execute */
410  pr->u.p.parm1 = FALSE;
411  break;
412  }
413  } else {
414  T small_chunk = tc / nproc;
415  T extras = tc % nproc;
416  init = id * small_chunk + (id < extras ? id : extras);
417  limit = init + small_chunk - (id < extras ? 0 : 1);
418  pr->u.p.parm1 = (id == nproc - 1);
419  }
420  } else {
421  if (tc > 0) {
422  init = 0;
423  limit = tc - 1;
424  pr->u.p.parm1 = TRUE;
425  } else {
426  // zero trip count
427  pr->u.p.count = 1; /* means no more chunks to execute */
428  pr->u.p.parm1 = FALSE;
429  break;
430  }
431  }
432 #if USE_ITT_BUILD
433  // Calculate chunk for metadata report
434  if (itt_need_metadata_reporting)
435  if (cur_chunk)
436  *cur_chunk = limit - init + 1;
437 #endif
438  if (st == 1) {
439  pr->u.p.lb = lb + init;
440  pr->u.p.ub = lb + limit;
441  } else {
442  // calculated upper bound, "ub" is user-defined upper bound
443  T ub_tmp = lb + limit * st;
444  pr->u.p.lb = lb + init * st;
445  // adjust upper bound to "ub" if needed, so that MS lastprivate will match
446  // it exactly
447  if (st > 0) {
448  pr->u.p.ub = (ub_tmp + st > ub ? ub : ub_tmp);
449  } else {
450  pr->u.p.ub = (ub_tmp + st < ub ? ub : ub_tmp);
451  }
452  }
453  if (pr->flags.ordered) {
454  pr->u.p.ordered_lower = init;
455  pr->u.p.ordered_upper = limit;
456  }
457  break;
458  } // case
459  case kmp_sch_static_balanced_chunked: {
460  // similar to balanced, but chunk adjusted to multiple of simd width
461  T nth = nproc;
462  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d runtime(simd:static)"
463  " -> falling-through to static_greedy\n",
464  gtid));
465  schedule = kmp_sch_static_greedy;
466  if (nth > 1)
467  pr->u.p.parm1 = ((tc + nth - 1) / nth + chunk - 1) & ~(chunk - 1);
468  else
469  pr->u.p.parm1 = tc;
470  break;
471  } // case
472  case kmp_sch_guided_simd:
473  case kmp_sch_guided_iterative_chunked: {
474  KD_TRACE(
475  100,
476  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_guided_iterative_chunked"
477  " case\n",
478  gtid));
479 
480  if (nproc > 1) {
481  if ((2L * chunk + 1) * nproc >= tc) {
482  /* chunk size too large, switch to dynamic */
483  schedule = kmp_sch_dynamic_chunked;
484  } else {
485  // when remaining iters become less than parm2 - switch to dynamic
486  pr->u.p.parm2 = guided_int_param * nproc * (chunk + 1);
487  *(double *)&pr->u.p.parm3 =
488  guided_flt_param / nproc; // may occupy parm3 and parm4
489  }
490  } else {
491  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d falling-through to "
492  "kmp_sch_static_greedy\n",
493  gtid));
494  schedule = kmp_sch_static_greedy;
495  /* team->t.t_nproc == 1: fall-through to kmp_sch_static_greedy */
496  KD_TRACE(
497  100,
498  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_greedy case\n",
499  gtid));
500  pr->u.p.parm1 = tc;
501  } // if
502  } // case
503  break;
504  case kmp_sch_guided_analytical_chunked: {
505  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d "
506  "kmp_sch_guided_analytical_chunked case\n",
507  gtid));
508 
509  if (nproc > 1) {
510  if ((2L * chunk + 1) * nproc >= tc) {
511  /* chunk size too large, switch to dynamic */
512  schedule = kmp_sch_dynamic_chunked;
513  } else {
514  /* commonly used term: (2 nproc - 1)/(2 nproc) */
515  DBL x;
516 
517 #if KMP_USE_X87CONTROL
518  /* Linux* OS already has 64-bit computation by default for long double,
519  and on Windows* OS on Intel(R) 64, /Qlong_double doesn't work. On
520  Windows* OS on IA-32 architecture, we need to set precision to 64-bit
521  instead of the default 53-bit. Even though long double doesn't work
522  on Windows* OS on Intel(R) 64, the resulting lack of precision is not
523  expected to impact the correctness of the algorithm, but this has not
524  been mathematically proven. */
525  // save original FPCW and set precision to 64-bit, as
526  // Windows* OS on IA-32 architecture defaults to 53-bit
527  unsigned int oldFpcw = _control87(0, 0);
528  _control87(_PC_64, _MCW_PC); // 0,0x30000
529 #endif
530  /* value used for comparison in solver for cross-over point */
531  long double target = ((long double)chunk * 2 + 1) * nproc / tc;
532 
533  /* crossover point--chunk indexes equal to or greater than
534  this point switch to dynamic-style scheduling */
535  UT cross;
536 
537  /* commonly used term: (2 nproc - 1)/(2 nproc) */
538  x = (long double)1.0 - (long double)0.5 / nproc;
539 
540 #ifdef KMP_DEBUG
541  { // test natural alignment
542  struct _test_a {
543  char a;
544  union {
545  char b;
546  DBL d;
547  };
548  } t;
549  ptrdiff_t natural_alignment =
550  (ptrdiff_t)&t.b - (ptrdiff_t)&t - (ptrdiff_t)1;
551  //__kmp_warn( " %llx %llx %lld", (long long)&t.d, (long long)&t, (long
552  // long)natural_alignment );
553  KMP_DEBUG_ASSERT(
554  (((ptrdiff_t)&pr->u.p.parm3) & (natural_alignment)) == 0);
555  }
556 #endif // KMP_DEBUG
557 
558  /* save the term in thread private dispatch structure */
559  *(DBL *)&pr->u.p.parm3 = x;
560 
561  /* solve for the crossover point to the nearest integer i for which C_i
562  <= chunk */
563  {
564  UT left, right, mid;
565  long double p;
566 
567  /* estimate initial upper and lower bound */
568 
569  /* doesn't matter what value right is as long as it is positive, but
570  it affects performance of the solver */
571  right = 229;
572  p = __kmp_pow<UT>(x, right);
573  if (p > target) {
574  do {
575  p *= p;
576  right <<= 1;
577  } while (p > target && right < (1 << 27));
578  /* lower bound is previous (failed) estimate of upper bound */
579  left = right >> 1;
580  } else {
581  left = 0;
582  }
583 
584  /* bisection root-finding method */
585  while (left + 1 < right) {
586  mid = (left + right) / 2;
587  if (__kmp_pow<UT>(x, mid) > target) {
588  left = mid;
589  } else {
590  right = mid;
591  }
592  } // while
593  cross = right;
594  }
595  /* assert sanity of computed crossover point */
596  KMP_ASSERT(cross && __kmp_pow<UT>(x, cross - 1) > target &&
597  __kmp_pow<UT>(x, cross) <= target);
598 
599  /* save the crossover point in thread private dispatch structure */
600  pr->u.p.parm2 = cross;
601 
602 // C75803
603 #if ((KMP_OS_LINUX || KMP_OS_WINDOWS) && KMP_ARCH_X86) && (!defined(KMP_I8))
604 #define GUIDED_ANALYTICAL_WORKAROUND (*(DBL *)&pr->u.p.parm3)
605 #else
606 #define GUIDED_ANALYTICAL_WORKAROUND (x)
607 #endif
608  /* dynamic-style scheduling offset */
609  pr->u.p.count = tc - __kmp_dispatch_guided_remaining(
610  tc, GUIDED_ANALYTICAL_WORKAROUND, cross) -
611  cross * chunk;
612 #if KMP_USE_X87CONTROL
613  // restore FPCW
614  _control87(oldFpcw, _MCW_PC);
615 #endif
616  } // if
617  } else {
618  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d falling-through to "
619  "kmp_sch_static_greedy\n",
620  gtid));
621  schedule = kmp_sch_static_greedy;
622  /* team->t.t_nproc == 1: fall-through to kmp_sch_static_greedy */
623  pr->u.p.parm1 = tc;
624  } // if
625  } // case
626  break;
627  case kmp_sch_static_greedy:
628  KD_TRACE(
629  100,
630  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_greedy case\n",
631  gtid));
632  pr->u.p.parm1 = (nproc > 1) ? (tc + nproc - 1) / nproc : tc;
633  break;
634  case kmp_sch_static_chunked:
635  case kmp_sch_dynamic_chunked:
636  if (pr->u.p.parm1 <= 0) {
637  pr->u.p.parm1 = KMP_DEFAULT_CHUNK;
638  }
639  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d "
640  "kmp_sch_static_chunked/kmp_sch_dynamic_chunked cases\n",
641  gtid));
642  break;
643  case kmp_sch_trapezoidal: {
644  /* TSS: trapezoid self-scheduling, minimum chunk_size = parm1 */
645 
646  T parm1, parm2, parm3, parm4;
647  KD_TRACE(100,
648  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_trapezoidal case\n",
649  gtid));
650 
651  parm1 = chunk;
652 
653  /* F : size of the first cycle */
654  parm2 = (tc / (2 * nproc));
655 
656  if (parm2 < 1) {
657  parm2 = 1;
658  }
659 
660  /* L : size of the last cycle. Make sure the last cycle is not larger
661  than the first cycle. */
662  if (parm1 < 1) {
663  parm1 = 1;
664  } else if (parm1 > parm2) {
665  parm1 = parm2;
666  }
667 
668  /* N : number of cycles */
669  parm3 = (parm2 + parm1);
670  parm3 = (2 * tc + parm3 - 1) / parm3;
671 
672  if (parm3 < 2) {
673  parm3 = 2;
674  }
675 
676  /* sigma : decreasing incr of the trapezoid */
677  parm4 = (parm3 - 1);
678  parm4 = (parm2 - parm1) / parm4;
679 
680  // pointless check, because parm4 >= 0 always
681  // if ( parm4 < 0 ) {
682  // parm4 = 0;
683  //}
684 
685  pr->u.p.parm1 = parm1;
686  pr->u.p.parm2 = parm2;
687  pr->u.p.parm3 = parm3;
688  pr->u.p.parm4 = parm4;
689  } // case
690  break;
691 
692  default: {
693  __kmp_fatal(KMP_MSG(UnknownSchedTypeDetected), // Primary message
694  KMP_HNT(GetNewerLibrary), // Hint
695  __kmp_msg_null // Variadic argument list terminator
696  );
697  } break;
698  } // switch
699  pr->schedule = schedule;
700 }
701 
702 #if KMP_USE_HIER_SCHED
703 template <typename T>
704 inline void __kmp_dispatch_init_hier_runtime(ident_t *loc, T lb, T ub,
705  typename traits_t<T>::signed_t st);
706 template <>
707 inline void
708 __kmp_dispatch_init_hier_runtime<kmp_int32>(ident_t *loc, kmp_int32 lb,
709  kmp_int32 ub, kmp_int32 st) {
710  __kmp_dispatch_init_hierarchy<kmp_int32>(
711  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
712  __kmp_hier_scheds.scheds, __kmp_hier_scheds.small_chunks, lb, ub, st);
713 }
714 template <>
715 inline void
716 __kmp_dispatch_init_hier_runtime<kmp_uint32>(ident_t *loc, kmp_uint32 lb,
717  kmp_uint32 ub, kmp_int32 st) {
718  __kmp_dispatch_init_hierarchy<kmp_uint32>(
719  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
720  __kmp_hier_scheds.scheds, __kmp_hier_scheds.small_chunks, lb, ub, st);
721 }
722 template <>
723 inline void
724 __kmp_dispatch_init_hier_runtime<kmp_int64>(ident_t *loc, kmp_int64 lb,
725  kmp_int64 ub, kmp_int64 st) {
726  __kmp_dispatch_init_hierarchy<kmp_int64>(
727  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
728  __kmp_hier_scheds.scheds, __kmp_hier_scheds.large_chunks, lb, ub, st);
729 }
730 template <>
731 inline void
732 __kmp_dispatch_init_hier_runtime<kmp_uint64>(ident_t *loc, kmp_uint64 lb,
733  kmp_uint64 ub, kmp_int64 st) {
734  __kmp_dispatch_init_hierarchy<kmp_uint64>(
735  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
736  __kmp_hier_scheds.scheds, __kmp_hier_scheds.large_chunks, lb, ub, st);
737 }
738 
739 // free all the hierarchy scheduling memory associated with the team
740 void __kmp_dispatch_free_hierarchies(kmp_team_t *team) {
741  int num_disp_buff = team->t.t_max_nproc > 1 ? __kmp_dispatch_num_buffers : 2;
742  for (int i = 0; i < num_disp_buff; ++i) {
743  // type does not matter here so use kmp_int32
744  auto sh =
745  reinterpret_cast<dispatch_shared_info_template<kmp_int32> volatile *>(
746  &team->t.t_disp_buffer[i]);
747  if (sh->hier) {
748  sh->hier->deallocate();
749  __kmp_free(sh->hier);
750  }
751  }
752 }
753 #endif
754 
755 // UT - unsigned flavor of T, ST - signed flavor of T,
756 // DBL - double if sizeof(T)==4, or long double if sizeof(T)==8
757 template <typename T>
758 static void
759 __kmp_dispatch_init(ident_t *loc, int gtid, enum sched_type schedule, T lb,
760  T ub, typename traits_t<T>::signed_t st,
761  typename traits_t<T>::signed_t chunk, int push_ws) {
762  typedef typename traits_t<T>::unsigned_t UT;
763 
764  int active;
765  kmp_info_t *th;
766  kmp_team_t *team;
767  kmp_uint32 my_buffer_index;
768  dispatch_private_info_template<T> *pr;
769  dispatch_shared_info_template<T> volatile *sh;
770 
771  KMP_BUILD_ASSERT(sizeof(dispatch_private_info_template<T>) ==
772  sizeof(dispatch_private_info));
773  KMP_BUILD_ASSERT(sizeof(dispatch_shared_info_template<UT>) ==
774  sizeof(dispatch_shared_info));
775 
776  if (!TCR_4(__kmp_init_parallel))
777  __kmp_parallel_initialize();
778 
779  __kmp_resume_if_soft_paused();
780 
781 #if INCLUDE_SSC_MARKS
782  SSC_MARK_DISPATCH_INIT();
783 #endif
784 #ifdef KMP_DEBUG
785  typedef typename traits_t<T>::signed_t ST;
786  {
787  char *buff;
788  // create format specifiers before the debug output
789  buff = __kmp_str_format("__kmp_dispatch_init: T#%%d called: schedule:%%d "
790  "chunk:%%%s lb:%%%s ub:%%%s st:%%%s\n",
791  traits_t<ST>::spec, traits_t<T>::spec,
792  traits_t<T>::spec, traits_t<ST>::spec);
793  KD_TRACE(10, (buff, gtid, schedule, chunk, lb, ub, st));
794  __kmp_str_free(&buff);
795  }
796 #endif
797  /* setup data */
798  th = __kmp_threads[gtid];
799  team = th->th.th_team;
800  active = !team->t.t_serialized;
801  th->th.th_ident = loc;
802 
803  // Any half-decent optimizer will remove this test when the blocks are empty
804  // since the macros expand to nothing
805  // when statistics are disabled.
806  if (schedule == __kmp_static) {
807  KMP_COUNT_BLOCK(OMP_LOOP_STATIC);
808  } else {
809  KMP_COUNT_BLOCK(OMP_LOOP_DYNAMIC);
810  }
811 
812 #if KMP_USE_HIER_SCHED
813  // Initialize the scheduling hierarchy if requested in OMP_SCHEDULE envirable
814  // Hierarchical scheduling does not work with ordered, so if ordered is
815  // detected, then revert back to threaded scheduling.
816  bool ordered;
817  enum sched_type my_sched = schedule;
818  my_buffer_index = th->th.th_dispatch->th_disp_index;
819  pr = reinterpret_cast<dispatch_private_info_template<T> *>(
820  &th->th.th_dispatch
821  ->th_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
822  my_sched = SCHEDULE_WITHOUT_MODIFIERS(my_sched);
823  if ((my_sched >= kmp_nm_lower) && (my_sched < kmp_nm_upper))
824  my_sched =
825  (enum sched_type)(((int)my_sched) - (kmp_nm_lower - kmp_sch_lower));
826  ordered = (kmp_ord_lower & my_sched);
827  if (pr->flags.use_hier) {
828  if (ordered) {
829  KD_TRACE(100, ("__kmp_dispatch_init: T#%d ordered loop detected. "
830  "Disabling hierarchical scheduling.\n",
831  gtid));
832  pr->flags.use_hier = FALSE;
833  }
834  }
835  if (schedule == kmp_sch_runtime && __kmp_hier_scheds.size > 0) {
836  // Don't use hierarchical for ordered parallel loops and don't
837  // use the runtime hierarchy if one was specified in the program
838  if (!ordered && !pr->flags.use_hier)
839  __kmp_dispatch_init_hier_runtime<T>(loc, lb, ub, st);
840  }
841 #endif // KMP_USE_HIER_SCHED
842 
843 #if USE_ITT_BUILD
844  kmp_uint64 cur_chunk = chunk;
845  int itt_need_metadata_reporting =
846  __itt_metadata_add_ptr && __kmp_forkjoin_frames_mode == 3 &&
847  KMP_MASTER_GTID(gtid) && th->th.th_teams_microtask == NULL &&
848  team->t.t_active_level == 1;
849 #endif
850  if (!active) {
851  pr = reinterpret_cast<dispatch_private_info_template<T> *>(
852  th->th.th_dispatch->th_disp_buffer); /* top of the stack */
853  } else {
854  KMP_DEBUG_ASSERT(th->th.th_dispatch ==
855  &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
856 
857  my_buffer_index = th->th.th_dispatch->th_disp_index++;
858 
859  /* What happens when number of threads changes, need to resize buffer? */
860  pr = reinterpret_cast<dispatch_private_info_template<T> *>(
861  &th->th.th_dispatch
862  ->th_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
863  sh = reinterpret_cast<dispatch_shared_info_template<T> volatile *>(
864  &team->t.t_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
865  KD_TRACE(10, ("__kmp_dispatch_init: T#%d my_buffer_index:%d\n", gtid,
866  my_buffer_index));
867  }
868 
869  __kmp_dispatch_init_algorithm(loc, gtid, pr, schedule, lb, ub, st,
870 #if USE_ITT_BUILD
871  &cur_chunk,
872 #endif
873  chunk, (T)th->th.th_team_nproc,
874  (T)th->th.th_info.ds.ds_tid);
875  if (active) {
876  if (pr->flags.ordered == 0) {
877  th->th.th_dispatch->th_deo_fcn = __kmp_dispatch_deo_error;
878  th->th.th_dispatch->th_dxo_fcn = __kmp_dispatch_dxo_error;
879  } else {
880  th->th.th_dispatch->th_deo_fcn = __kmp_dispatch_deo<UT>;
881  th->th.th_dispatch->th_dxo_fcn = __kmp_dispatch_dxo<UT>;
882  }
883  }
884 
885  if (active) {
886  /* The name of this buffer should be my_buffer_index when it's free to use
887  * it */
888 
889  KD_TRACE(100, ("__kmp_dispatch_init: T#%d before wait: my_buffer_index:%d "
890  "sh->buffer_index:%d\n",
891  gtid, my_buffer_index, sh->buffer_index));
892  __kmp_wait<kmp_uint32>(&sh->buffer_index, my_buffer_index,
893  __kmp_eq<kmp_uint32> USE_ITT_BUILD_ARG(NULL));
894  // Note: KMP_WAIT() cannot be used there: buffer index and
895  // my_buffer_index are *always* 32-bit integers.
896  KMP_MB(); /* is this necessary? */
897  KD_TRACE(100, ("__kmp_dispatch_init: T#%d after wait: my_buffer_index:%d "
898  "sh->buffer_index:%d\n",
899  gtid, my_buffer_index, sh->buffer_index));
900 
901  th->th.th_dispatch->th_dispatch_pr_current = (dispatch_private_info_t *)pr;
902  th->th.th_dispatch->th_dispatch_sh_current =
903  CCAST(dispatch_shared_info_t *, (volatile dispatch_shared_info_t *)sh);
904 #if USE_ITT_BUILD
905  if (pr->flags.ordered) {
906  __kmp_itt_ordered_init(gtid);
907  }
908  // Report loop metadata
909  if (itt_need_metadata_reporting) {
910  // Only report metadata by master of active team at level 1
911  kmp_uint64 schedtype = 0;
912  switch (schedule) {
913  case kmp_sch_static_chunked:
914  case kmp_sch_static_balanced: // Chunk is calculated in the switch above
915  break;
916  case kmp_sch_static_greedy:
917  cur_chunk = pr->u.p.parm1;
918  break;
919  case kmp_sch_dynamic_chunked:
920  schedtype = 1;
921  break;
922  case kmp_sch_guided_iterative_chunked:
923  case kmp_sch_guided_analytical_chunked:
924  case kmp_sch_guided_simd:
925  schedtype = 2;
926  break;
927  default:
928  // Should we put this case under "static"?
929  // case kmp_sch_static_steal:
930  schedtype = 3;
931  break;
932  }
933  __kmp_itt_metadata_loop(loc, schedtype, pr->u.p.tc, cur_chunk);
934  }
935 #if KMP_USE_HIER_SCHED
936  if (pr->flags.use_hier) {
937  pr->u.p.count = 0;
938  pr->u.p.ub = pr->u.p.lb = pr->u.p.st = pr->u.p.tc = 0;
939  }
940 #endif // KMP_USER_HIER_SCHED
941 #endif /* USE_ITT_BUILD */
942  }
943 
944 #ifdef KMP_DEBUG
945  {
946  char *buff;
947  // create format specifiers before the debug output
948  buff = __kmp_str_format(
949  "__kmp_dispatch_init: T#%%d returning: schedule:%%d ordered:%%%s "
950  "lb:%%%s ub:%%%s"
951  " st:%%%s tc:%%%s count:%%%s\n\tordered_lower:%%%s ordered_upper:%%%s"
952  " parm1:%%%s parm2:%%%s parm3:%%%s parm4:%%%s\n",
953  traits_t<UT>::spec, traits_t<T>::spec, traits_t<T>::spec,
954  traits_t<ST>::spec, traits_t<UT>::spec, traits_t<UT>::spec,
955  traits_t<UT>::spec, traits_t<UT>::spec, traits_t<T>::spec,
956  traits_t<T>::spec, traits_t<T>::spec, traits_t<T>::spec);
957  KD_TRACE(10, (buff, gtid, pr->schedule, pr->flags.ordered, pr->u.p.lb,
958  pr->u.p.ub, pr->u.p.st, pr->u.p.tc, pr->u.p.count,
959  pr->u.p.ordered_lower, pr->u.p.ordered_upper, pr->u.p.parm1,
960  pr->u.p.parm2, pr->u.p.parm3, pr->u.p.parm4));
961  __kmp_str_free(&buff);
962  }
963 #endif
964 #if (KMP_STATIC_STEAL_ENABLED)
965  // It cannot be guaranteed that after execution of a loop with some other
966  // schedule kind all the parm3 variables will contain the same value. Even if
967  // all parm3 will be the same, it still exists a bad case like using 0 and 1
968  // rather than program life-time increment. So the dedicated variable is
969  // required. The 'static_steal_counter' is used.
970  if (schedule == kmp_sch_static_steal) {
971  // Other threads will inspect this variable when searching for a victim.
972  // This is a flag showing that other threads may steal from this thread
973  // since then.
974  volatile T *p = &pr->u.p.static_steal_counter;
975  *p = *p + 1;
976  }
977 #endif // ( KMP_STATIC_STEAL_ENABLED )
978 
979 #if OMPT_SUPPORT && OMPT_OPTIONAL
980  if (ompt_enabled.ompt_callback_work) {
981  ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
982  ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
983  ompt_callbacks.ompt_callback(ompt_callback_work)(
984  ompt_work_loop, ompt_scope_begin, &(team_info->parallel_data),
985  &(task_info->task_data), pr->u.p.tc, OMPT_LOAD_RETURN_ADDRESS(gtid));
986  }
987 #endif
988  KMP_PUSH_PARTITIONED_TIMER(OMP_loop_dynamic);
989 }
990 
991 /* For ordered loops, either __kmp_dispatch_finish() should be called after
992  * every iteration, or __kmp_dispatch_finish_chunk() should be called after
993  * every chunk of iterations. If the ordered section(s) were not executed
994  * for this iteration (or every iteration in this chunk), we need to set the
995  * ordered iteration counters so that the next thread can proceed. */
996 template <typename UT>
997 static void __kmp_dispatch_finish(int gtid, ident_t *loc) {
998  typedef typename traits_t<UT>::signed_t ST;
999  kmp_info_t *th = __kmp_threads[gtid];
1000 
1001  KD_TRACE(100, ("__kmp_dispatch_finish: T#%d called\n", gtid));
1002  if (!th->th.th_team->t.t_serialized) {
1003 
1004  dispatch_private_info_template<UT> *pr =
1005  reinterpret_cast<dispatch_private_info_template<UT> *>(
1006  th->th.th_dispatch->th_dispatch_pr_current);
1007  dispatch_shared_info_template<UT> volatile *sh =
1008  reinterpret_cast<dispatch_shared_info_template<UT> volatile *>(
1009  th->th.th_dispatch->th_dispatch_sh_current);
1010  KMP_DEBUG_ASSERT(pr);
1011  KMP_DEBUG_ASSERT(sh);
1012  KMP_DEBUG_ASSERT(th->th.th_dispatch ==
1013  &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
1014 
1015  if (pr->ordered_bumped) {
1016  KD_TRACE(
1017  1000,
1018  ("__kmp_dispatch_finish: T#%d resetting ordered_bumped to zero\n",
1019  gtid));
1020  pr->ordered_bumped = 0;
1021  } else {
1022  UT lower = pr->u.p.ordered_lower;
1023 
1024 #ifdef KMP_DEBUG
1025  {
1026  char *buff;
1027  // create format specifiers before the debug output
1028  buff = __kmp_str_format("__kmp_dispatch_finish: T#%%d before wait: "
1029  "ordered_iteration:%%%s lower:%%%s\n",
1030  traits_t<UT>::spec, traits_t<UT>::spec);
1031  KD_TRACE(1000, (buff, gtid, sh->u.s.ordered_iteration, lower));
1032  __kmp_str_free(&buff);
1033  }
1034 #endif
1035 
1036  __kmp_wait<UT>(&sh->u.s.ordered_iteration, lower,
1037  __kmp_ge<UT> USE_ITT_BUILD_ARG(NULL));
1038  KMP_MB(); /* is this necessary? */
1039 #ifdef KMP_DEBUG
1040  {
1041  char *buff;
1042  // create format specifiers before the debug output
1043  buff = __kmp_str_format("__kmp_dispatch_finish: T#%%d after wait: "
1044  "ordered_iteration:%%%s lower:%%%s\n",
1045  traits_t<UT>::spec, traits_t<UT>::spec);
1046  KD_TRACE(1000, (buff, gtid, sh->u.s.ordered_iteration, lower));
1047  __kmp_str_free(&buff);
1048  }
1049 #endif
1050 
1051  test_then_inc<ST>((volatile ST *)&sh->u.s.ordered_iteration);
1052  } // if
1053  } // if
1054  KD_TRACE(100, ("__kmp_dispatch_finish: T#%d returned\n", gtid));
1055 }
1056 
1057 #ifdef KMP_GOMP_COMPAT
1058 
1059 template <typename UT>
1060 static void __kmp_dispatch_finish_chunk(int gtid, ident_t *loc) {
1061  typedef typename traits_t<UT>::signed_t ST;
1062  kmp_info_t *th = __kmp_threads[gtid];
1063 
1064  KD_TRACE(100, ("__kmp_dispatch_finish_chunk: T#%d called\n", gtid));
1065  if (!th->th.th_team->t.t_serialized) {
1066  // int cid;
1067  dispatch_private_info_template<UT> *pr =
1068  reinterpret_cast<dispatch_private_info_template<UT> *>(
1069  th->th.th_dispatch->th_dispatch_pr_current);
1070  dispatch_shared_info_template<UT> volatile *sh =
1071  reinterpret_cast<dispatch_shared_info_template<UT> volatile *>(
1072  th->th.th_dispatch->th_dispatch_sh_current);
1073  KMP_DEBUG_ASSERT(pr);
1074  KMP_DEBUG_ASSERT(sh);
1075  KMP_DEBUG_ASSERT(th->th.th_dispatch ==
1076  &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
1077 
1078  // for (cid = 0; cid < KMP_MAX_ORDERED; ++cid) {
1079  UT lower = pr->u.p.ordered_lower;
1080  UT upper = pr->u.p.ordered_upper;
1081  UT inc = upper - lower + 1;
1082 
1083  if (pr->ordered_bumped == inc) {
1084  KD_TRACE(
1085  1000,
1086  ("__kmp_dispatch_finish: T#%d resetting ordered_bumped to zero\n",
1087  gtid));
1088  pr->ordered_bumped = 0;
1089  } else {
1090  inc -= pr->ordered_bumped;
1091 
1092 #ifdef KMP_DEBUG
1093  {
1094  char *buff;
1095  // create format specifiers before the debug output
1096  buff = __kmp_str_format(
1097  "__kmp_dispatch_finish_chunk: T#%%d before wait: "
1098  "ordered_iteration:%%%s lower:%%%s upper:%%%s\n",
1099  traits_t<UT>::spec, traits_t<UT>::spec, traits_t<UT>::spec);
1100  KD_TRACE(1000, (buff, gtid, sh->u.s.ordered_iteration, lower, upper));
1101  __kmp_str_free(&buff);
1102  }
1103 #endif
1104 
1105  __kmp_wait<UT>(&sh->u.s.ordered_iteration, lower,
1106  __kmp_ge<UT> USE_ITT_BUILD_ARG(NULL));
1107 
1108  KMP_MB(); /* is this necessary? */
1109  KD_TRACE(1000, ("__kmp_dispatch_finish_chunk: T#%d resetting "
1110  "ordered_bumped to zero\n",
1111  gtid));
1112  pr->ordered_bumped = 0;
1114 #ifdef KMP_DEBUG
1115  {
1116  char *buff;
1117  // create format specifiers before the debug output
1118  buff = __kmp_str_format(
1119  "__kmp_dispatch_finish_chunk: T#%%d after wait: "
1120  "ordered_iteration:%%%s inc:%%%s lower:%%%s upper:%%%s\n",
1121  traits_t<UT>::spec, traits_t<UT>::spec, traits_t<UT>::spec,
1122  traits_t<UT>::spec);
1123  KD_TRACE(1000,
1124  (buff, gtid, sh->u.s.ordered_iteration, inc, lower, upper));
1125  __kmp_str_free(&buff);
1126  }
1127 #endif
1128 
1129  test_then_add<ST>((volatile ST *)&sh->u.s.ordered_iteration,