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(ident_t *loc, enum sched_type schedule,
73  bool use_hier = false) {
74  // Pick up the nonmonotonic/monotonic bits from the scheduling type
75  // Nonmonotonic as default for dynamic schedule when no modifier is specified
76  int monotonicity = SCHEDULE_NONMONOTONIC;
77 
78  // Let default be monotonic for executables
79  // compiled with OpenMP* 4.5 or less compilers
80  if (loc != NULL && loc->get_openmp_version() < 50)
81  monotonicity = SCHEDULE_MONOTONIC;
82 
83  if (use_hier || __kmp_force_monotonic)
84  monotonicity = SCHEDULE_MONOTONIC;
85  else if (SCHEDULE_HAS_NONMONOTONIC(schedule))
86  monotonicity = SCHEDULE_NONMONOTONIC;
87  else if (SCHEDULE_HAS_MONOTONIC(schedule))
88  monotonicity = SCHEDULE_MONOTONIC;
89 
90  return monotonicity;
91 }
92 
93 #if KMP_STATIC_STEAL_ENABLED
94 enum { // values for steal_flag (possible states of private per-loop buffer)
95  UNUSED = 0,
96  CLAIMED = 1, // owner thread started initialization
97  READY = 2, // available for stealing
98  THIEF = 3 // finished by owner, or claimed by thief
99  // possible state changes:
100  // 0 -> 1 owner only, sync
101  // 0 -> 3 thief only, sync
102  // 1 -> 2 owner only, async
103  // 2 -> 3 owner only, async
104  // 3 -> 2 owner only, async
105  // 3 -> 0 last thread finishing the loop, async
106 };
107 #endif
108 
109 // Initialize a dispatch_private_info_template<T> buffer for a particular
110 // type of schedule,chunk. The loop description is found in lb (lower bound),
111 // ub (upper bound), and st (stride). nproc is the number of threads relevant
112 // to the scheduling (often the number of threads in a team, but not always if
113 // hierarchical scheduling is used). tid is the id of the thread calling
114 // the function within the group of nproc threads. It will have a value
115 // between 0 and nproc - 1. This is often just the thread id within a team, but
116 // is not necessarily the case when using hierarchical scheduling.
117 // loc is the source file location of the corresponding loop
118 // gtid is the global thread id
119 template <typename T>
120 void __kmp_dispatch_init_algorithm(ident_t *loc, int gtid,
121  dispatch_private_info_template<T> *pr,
122  enum sched_type schedule, T lb, T ub,
123  typename traits_t<T>::signed_t st,
124 #if USE_ITT_BUILD
125  kmp_uint64 *cur_chunk,
126 #endif
127  typename traits_t<T>::signed_t chunk,
128  T nproc, T tid) {
129  typedef typename traits_t<T>::unsigned_t UT;
130  typedef typename traits_t<T>::floating_t DBL;
131 
132  int active;
133  T tc;
134  kmp_info_t *th;
135  kmp_team_t *team;
136  int monotonicity;
137  bool use_hier;
138 
139 #ifdef KMP_DEBUG
140  typedef typename traits_t<T>::signed_t ST;
141  {
142  char *buff;
143  // create format specifiers before the debug output
144  buff = __kmp_str_format("__kmp_dispatch_init_algorithm: T#%%d called "
145  "pr:%%p lb:%%%s ub:%%%s st:%%%s "
146  "schedule:%%d chunk:%%%s nproc:%%%s tid:%%%s\n",
147  traits_t<T>::spec, traits_t<T>::spec,
148  traits_t<ST>::spec, traits_t<ST>::spec,
149  traits_t<T>::spec, traits_t<T>::spec);
150  KD_TRACE(10, (buff, gtid, pr, lb, ub, st, schedule, chunk, nproc, tid));
151  __kmp_str_free(&buff);
152  }
153 #endif
154  /* setup data */
155  th = __kmp_threads[gtid];
156  team = th->th.th_team;
157  active = !team->t.t_serialized;
158 
159 #if USE_ITT_BUILD
160  int itt_need_metadata_reporting =
161  __itt_metadata_add_ptr && __kmp_forkjoin_frames_mode == 3 &&
162  KMP_MASTER_GTID(gtid) && th->th.th_teams_microtask == NULL &&
163  team->t.t_active_level == 1;
164 #endif
165 
166 #if KMP_USE_HIER_SCHED
167  use_hier = pr->flags.use_hier;
168 #else
169  use_hier = false;
170 #endif
171 
172  /* Pick up the nonmonotonic/monotonic bits from the scheduling type */
173  monotonicity = __kmp_get_monotonicity(loc, schedule, use_hier);
174  schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
175 
176  /* Pick up the nomerge/ordered bits from the scheduling type */
177  if ((schedule >= kmp_nm_lower) && (schedule < kmp_nm_upper)) {
178  pr->flags.nomerge = TRUE;
179  schedule =
180  (enum sched_type)(((int)schedule) - (kmp_nm_lower - kmp_sch_lower));
181  } else {
182  pr->flags.nomerge = FALSE;
183  }
184  pr->type_size = traits_t<T>::type_size; // remember the size of variables
185  if (kmp_ord_lower & schedule) {
186  pr->flags.ordered = TRUE;
187  schedule =
188  (enum sched_type)(((int)schedule) - (kmp_ord_lower - kmp_sch_lower));
189  } else {
190  pr->flags.ordered = FALSE;
191  }
192  // Ordered overrides nonmonotonic
193  if (pr->flags.ordered) {
194  monotonicity = SCHEDULE_MONOTONIC;
195  }
196 
197  if (schedule == kmp_sch_static) {
198  schedule = __kmp_static;
199  } else {
200  if (schedule == kmp_sch_runtime) {
201  // Use the scheduling specified by OMP_SCHEDULE (or __kmp_sch_default if
202  // not specified)
203  schedule = team->t.t_sched.r_sched_type;
204  monotonicity = __kmp_get_monotonicity(loc, schedule, use_hier);
205  schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
206  if (pr->flags.ordered) // correct monotonicity for ordered loop if needed
207  monotonicity = SCHEDULE_MONOTONIC;
208  // Detail the schedule if needed (global controls are differentiated
209  // appropriately)
210  if (schedule == kmp_sch_guided_chunked) {
211  schedule = __kmp_guided;
212  } else if (schedule == kmp_sch_static) {
213  schedule = __kmp_static;
214  }
215  // Use the chunk size specified by OMP_SCHEDULE (or default if not
216  // specified)
217  chunk = team->t.t_sched.chunk;
218 #if USE_ITT_BUILD
219  if (cur_chunk)
220  *cur_chunk = chunk;
221 #endif
222 #ifdef KMP_DEBUG
223  {
224  char *buff;
225  // create format specifiers before the debug output
226  buff = __kmp_str_format("__kmp_dispatch_init_algorithm: T#%%d new: "
227  "schedule:%%d chunk:%%%s\n",
228  traits_t<ST>::spec);
229  KD_TRACE(10, (buff, gtid, schedule, chunk));
230  __kmp_str_free(&buff);
231  }
232 #endif
233  } else {
234  if (schedule == kmp_sch_guided_chunked) {
235  schedule = __kmp_guided;
236  }
237  if (chunk <= 0) {
238  chunk = KMP_DEFAULT_CHUNK;
239  }
240  }
241 
242  if (schedule == kmp_sch_auto) {
243  // mapping and differentiation: in the __kmp_do_serial_initialize()
244  schedule = __kmp_auto;
245 #ifdef KMP_DEBUG
246  {
247  char *buff;
248  // create format specifiers before the debug output
249  buff = __kmp_str_format(
250  "__kmp_dispatch_init_algorithm: kmp_sch_auto: T#%%d new: "
251  "schedule:%%d chunk:%%%s\n",
252  traits_t<ST>::spec);
253  KD_TRACE(10, (buff, gtid, schedule, chunk));
254  __kmp_str_free(&buff);
255  }
256 #endif
257  }
258 #if KMP_STATIC_STEAL_ENABLED
259  // map nonmonotonic:dynamic to static steal
260  if (schedule == kmp_sch_dynamic_chunked) {
261  if (monotonicity == SCHEDULE_NONMONOTONIC)
262  schedule = kmp_sch_static_steal;
263  }
264 #endif
265  /* guided analytical not safe for too many threads */
266  if (schedule == kmp_sch_guided_analytical_chunked && nproc > 1 << 20) {
267  schedule = kmp_sch_guided_iterative_chunked;
268  KMP_WARNING(DispatchManyThreads);
269  }
270  if (schedule == kmp_sch_runtime_simd) {
271  // compiler provides simd_width in the chunk parameter
272  schedule = team->t.t_sched.r_sched_type;
273  monotonicity = __kmp_get_monotonicity(loc, schedule, use_hier);
274  schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
275  // Detail the schedule if needed (global controls are differentiated
276  // appropriately)
277  if (schedule == kmp_sch_static || schedule == kmp_sch_auto ||
278  schedule == __kmp_static) {
279  schedule = kmp_sch_static_balanced_chunked;
280  } else {
281  if (schedule == kmp_sch_guided_chunked || schedule == __kmp_guided) {
282  schedule = kmp_sch_guided_simd;
283  }
284  chunk = team->t.t_sched.chunk * chunk;
285  }
286 #if USE_ITT_BUILD
287  if (cur_chunk)
288  *cur_chunk = chunk;
289 #endif
290 #ifdef KMP_DEBUG
291  {
292  char *buff;
293  // create format specifiers before the debug output
294  buff = __kmp_str_format(
295  "__kmp_dispatch_init_algorithm: T#%%d new: schedule:%%d"
296  " chunk:%%%s\n",
297  traits_t<ST>::spec);
298  KD_TRACE(10, (buff, gtid, schedule, chunk));
299  __kmp_str_free(&buff);
300  }
301 #endif
302  }
303  pr->u.p.parm1 = chunk;
304  }
305  KMP_ASSERT2((kmp_sch_lower < schedule && schedule < kmp_sch_upper),
306  "unknown scheduling type");
307 
308  pr->u.p.count = 0;
309 
310  if (__kmp_env_consistency_check) {
311  if (st == 0) {
312  __kmp_error_construct(kmp_i18n_msg_CnsLoopIncrZeroProhibited,
313  (pr->flags.ordered ? ct_pdo_ordered : ct_pdo), loc);
314  }
315  }
316  // compute trip count
317  if (st == 1) { // most common case
318  if (ub >= lb) {
319  tc = ub - lb + 1;
320  } else { // ub < lb
321  tc = 0; // zero-trip
322  }
323  } else if (st < 0) {
324  if (lb >= ub) {
325  // AC: cast to unsigned is needed for loops like (i=2B; i>-2B; i-=1B),
326  // where the division needs to be unsigned regardless of the result type
327  tc = (UT)(lb - ub) / (-st) + 1;
328  } else { // lb < ub
329  tc = 0; // zero-trip
330  }
331  } else { // st > 0
332  if (ub >= lb) {
333  // AC: cast to unsigned is needed for loops like (i=-2B; i<2B; i+=1B),
334  // where the division needs to be unsigned regardless of the result type
335  tc = (UT)(ub - lb) / st + 1;
336  } else { // ub < lb
337  tc = 0; // zero-trip
338  }
339  }
340 
341 #if KMP_STATS_ENABLED
342  if (KMP_MASTER_GTID(gtid)) {
343  KMP_COUNT_VALUE(OMP_loop_dynamic_total_iterations, tc);
344  }
345 #endif
346 
347  pr->u.p.lb = lb;
348  pr->u.p.ub = ub;
349  pr->u.p.st = st;
350  pr->u.p.tc = tc;
351 
352 #if KMP_OS_WINDOWS
353  pr->u.p.last_upper = ub + st;
354 #endif /* KMP_OS_WINDOWS */
355 
356  /* NOTE: only the active parallel region(s) has active ordered sections */
357 
358  if (active) {
359  if (pr->flags.ordered) {
360  pr->ordered_bumped = 0;
361  pr->u.p.ordered_lower = 1;
362  pr->u.p.ordered_upper = 0;
363  }
364  }
365 
366  switch (schedule) {
367 #if KMP_STATIC_STEAL_ENABLED
368  case kmp_sch_static_steal: {
369  T ntc, init;
370 
371  KD_TRACE(100,
372  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_steal case\n",
373  gtid));
374 
375  ntc = (tc % chunk ? 1 : 0) + tc / chunk;
376  if (nproc > 1 && ntc >= nproc) {
377  KMP_COUNT_BLOCK(OMP_LOOP_STATIC_STEAL);
378  T id = tid;
379  T small_chunk, extras;
380  kmp_uint32 old = UNUSED;
381  int claimed = pr->steal_flag.compare_exchange_strong(old, CLAIMED);
382  if (traits_t<T>::type_size > 4) {
383  // AC: TODO: check if 16-byte CAS available and use it to
384  // improve performance (probably wait for explicit request
385  // before spending time on this).
386  // For now use dynamically allocated per-private-buffer lock,
387  // free memory in __kmp_dispatch_next when status==0.
388  pr->u.p.steal_lock = (kmp_lock_t *)__kmp_allocate(sizeof(kmp_lock_t));
389  __kmp_init_lock(pr->u.p.steal_lock);
390  }
391  small_chunk = ntc / nproc;
392  extras = ntc % nproc;
393 
394  init = id * small_chunk + (id < extras ? id : extras);
395  pr->u.p.count = init;
396  if (claimed) { // are we succeeded in claiming own buffer?
397  pr->u.p.ub = init + small_chunk + (id < extras ? 1 : 0);
398  // Other threads will inspect steal_flag when searching for a victim.
399  // READY means other threads may steal from this thread from now on.
400  KMP_ATOMIC_ST_REL(&pr->steal_flag, READY);
401  } else {
402  // other thread has stolen whole our range
403  KMP_DEBUG_ASSERT(pr->steal_flag == THIEF);
404  pr->u.p.ub = init; // mark there is no iterations to work on
405  }
406  pr->u.p.parm2 = ntc; // save number of chunks
407  // parm3 is the number of times to attempt stealing which is
408  // nproc (just a heuristics, could be optimized later on).
409  pr->u.p.parm3 = nproc;
410  pr->u.p.parm4 = (id + 1) % nproc; // remember neighbour tid
411  break;
412  } else {
413  /* too few chunks: switching to kmp_sch_dynamic_chunked */
414  schedule = kmp_sch_dynamic_chunked;
415  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d switching to "
416  "kmp_sch_dynamic_chunked\n",
417  gtid));
418  goto dynamic_init;
419  break;
420  } // if
421  } // case
422 #endif
423  case kmp_sch_static_balanced: {
424  T init, limit;
425 
426  KD_TRACE(
427  100,
428  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_balanced case\n",
429  gtid));
430 
431  if (nproc > 1) {
432  T id = tid;
433 
434  if (tc < nproc) {
435  if (id < tc) {
436  init = id;
437  limit = id;
438  pr->u.p.parm1 = (id == tc - 1); /* parm1 stores *plastiter */
439  } else {
440  pr->u.p.count = 1; /* means no more chunks to execute */
441  pr->u.p.parm1 = FALSE;
442  break;
443  }
444  } else {
445  T small_chunk = tc / nproc;
446  T extras = tc % nproc;
447  init = id * small_chunk + (id < extras ? id : extras);
448  limit = init + small_chunk - (id < extras ? 0 : 1);
449  pr->u.p.parm1 = (id == nproc - 1);
450  }
451  } else {
452  if (tc > 0) {
453  init = 0;
454  limit = tc - 1;
455  pr->u.p.parm1 = TRUE;
456  } else {
457  // zero trip count
458  pr->u.p.count = 1; /* means no more chunks to execute */
459  pr->u.p.parm1 = FALSE;
460  break;
461  }
462  }
463 #if USE_ITT_BUILD
464  // Calculate chunk for metadata report
465  if (itt_need_metadata_reporting)
466  if (cur_chunk)
467  *cur_chunk = limit - init + 1;
468 #endif
469  if (st == 1) {
470  pr->u.p.lb = lb + init;
471  pr->u.p.ub = lb + limit;
472  } else {
473  // calculated upper bound, "ub" is user-defined upper bound
474  T ub_tmp = lb + limit * st;
475  pr->u.p.lb = lb + init * st;
476  // adjust upper bound to "ub" if needed, so that MS lastprivate will match
477  // it exactly
478  if (st > 0) {
479  pr->u.p.ub = (ub_tmp + st > ub ? ub : ub_tmp);
480  } else {
481  pr->u.p.ub = (ub_tmp + st < ub ? ub : ub_tmp);
482  }
483  }
484  if (pr->flags.ordered) {
485  pr->u.p.ordered_lower = init;
486  pr->u.p.ordered_upper = limit;
487  }
488  break;
489  } // case
490  case kmp_sch_static_balanced_chunked: {
491  // similar to balanced, but chunk adjusted to multiple of simd width
492  T nth = nproc;
493  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d runtime(simd:static)"
494  " -> falling-through to static_greedy\n",
495  gtid));
496  schedule = kmp_sch_static_greedy;
497  if (nth > 1)
498  pr->u.p.parm1 = ((tc + nth - 1) / nth + chunk - 1) & ~(chunk - 1);
499  else
500  pr->u.p.parm1 = tc;
501  break;
502  } // case
503  case kmp_sch_guided_simd:
504  case kmp_sch_guided_iterative_chunked: {
505  KD_TRACE(
506  100,
507  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_guided_iterative_chunked"
508  " case\n",
509  gtid));
510 
511  if (nproc > 1) {
512  if ((2L * chunk + 1) * nproc >= tc) {
513  /* chunk size too large, switch to dynamic */
514  schedule = kmp_sch_dynamic_chunked;
515  goto dynamic_init;
516  } else {
517  // when remaining iters become less than parm2 - switch to dynamic
518  pr->u.p.parm2 = guided_int_param * nproc * (chunk + 1);
519  *(double *)&pr->u.p.parm3 =
520  guided_flt_param / (double)nproc; // may occupy parm3 and parm4
521  }
522  } else {
523  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d falling-through to "
524  "kmp_sch_static_greedy\n",
525  gtid));
526  schedule = kmp_sch_static_greedy;
527  /* team->t.t_nproc == 1: fall-through to kmp_sch_static_greedy */
528  KD_TRACE(
529  100,
530  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_greedy case\n",
531  gtid));
532  pr->u.p.parm1 = tc;
533  } // if
534  } // case
535  break;
536  case kmp_sch_guided_analytical_chunked: {
537  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d "
538  "kmp_sch_guided_analytical_chunked case\n",
539  gtid));
540 
541  if (nproc > 1) {
542  if ((2L * chunk + 1) * nproc >= tc) {
543  /* chunk size too large, switch to dynamic */
544  schedule = kmp_sch_dynamic_chunked;
545  goto dynamic_init;
546  } else {
547  /* commonly used term: (2 nproc - 1)/(2 nproc) */
548  DBL x;
549 
550 #if KMP_USE_X87CONTROL
551  /* Linux* OS already has 64-bit computation by default for long double,
552  and on Windows* OS on Intel(R) 64, /Qlong_double doesn't work. On
553  Windows* OS on IA-32 architecture, we need to set precision to 64-bit
554  instead of the default 53-bit. Even though long double doesn't work
555  on Windows* OS on Intel(R) 64, the resulting lack of precision is not
556  expected to impact the correctness of the algorithm, but this has not
557  been mathematically proven. */
558  // save original FPCW and set precision to 64-bit, as
559  // Windows* OS on IA-32 architecture defaults to 53-bit
560  unsigned int oldFpcw = _control87(0, 0);
561  _control87(_PC_64, _MCW_PC); // 0,0x30000
562 #endif
563  /* value used for comparison in solver for cross-over point */
564  KMP_ASSERT(tc > 0);
565  long double target = ((long double)chunk * 2 + 1) * nproc / tc;
566 
567  /* crossover point--chunk indexes equal to or greater than
568  this point switch to dynamic-style scheduling */
569  UT cross;
570 
571  /* commonly used term: (2 nproc - 1)/(2 nproc) */
572  x = 1.0 - 0.5 / (double)nproc;
573 
574 #ifdef KMP_DEBUG
575  { // test natural alignment
576  struct _test_a {
577  char a;
578  union {
579  char b;
580  DBL d;
581  };
582  } t;
583  ptrdiff_t natural_alignment =
584  (ptrdiff_t)&t.b - (ptrdiff_t)&t - (ptrdiff_t)1;
585  //__kmp_warn( " %llx %llx %lld", (long long)&t.d, (long long)&t, (long
586  // long)natural_alignment );
587  KMP_DEBUG_ASSERT(
588  (((ptrdiff_t)&pr->u.p.parm3) & (natural_alignment)) == 0);
589  }
590 #endif // KMP_DEBUG
591 
592  /* save the term in thread private dispatch structure */
593  *(DBL *)&pr->u.p.parm3 = x;
594 
595  /* solve for the crossover point to the nearest integer i for which C_i
596  <= chunk */
597  {
598  UT left, right, mid;
599  long double p;
600 
601  /* estimate initial upper and lower bound */
602 
603  /* doesn't matter what value right is as long as it is positive, but
604  it affects performance of the solver */
605  right = 229;
606  p = __kmp_pow<UT>(x, right);
607  if (p > target) {
608  do {
609  p *= p;
610  right <<= 1;
611  } while (p > target && right < (1 << 27));
612  /* lower bound is previous (failed) estimate of upper bound */
613  left = right >> 1;
614  } else {
615  left = 0;
616  }
617 
618  /* bisection root-finding method */
619  while (left + 1 < right) {
620  mid = (left + right) / 2;
621  if (__kmp_pow<UT>(x, mid) > target) {
622  left = mid;
623  } else {
624  right = mid;
625  }
626  } // while
627  cross = right;
628  }
629  /* assert sanity of computed crossover point */
630  KMP_ASSERT(cross && __kmp_pow<UT>(x, cross - 1) > target &&
631  __kmp_pow<UT>(x, cross) <= target);
632 
633  /* save the crossover point in thread private dispatch structure */
634  pr->u.p.parm2 = cross;
635 
636 // C75803
637 #if ((KMP_OS_LINUX || KMP_OS_WINDOWS) && KMP_ARCH_X86) && (!defined(KMP_I8))
638 #define GUIDED_ANALYTICAL_WORKAROUND (*(DBL *)&pr->u.p.parm3)
639 #else
640 #define GUIDED_ANALYTICAL_WORKAROUND (x)
641 #endif
642  /* dynamic-style scheduling offset */
643  pr->u.p.count = tc -
644  __kmp_dispatch_guided_remaining(
645  tc, GUIDED_ANALYTICAL_WORKAROUND, cross) -
646  cross * chunk;
647 #if KMP_USE_X87CONTROL
648  // restore FPCW
649  _control87(oldFpcw, _MCW_PC);
650 #endif
651  } // if
652  } else {
653  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d falling-through to "
654  "kmp_sch_static_greedy\n",
655  gtid));
656  schedule = kmp_sch_static_greedy;
657  /* team->t.t_nproc == 1: fall-through to kmp_sch_static_greedy */
658  pr->u.p.parm1 = tc;
659  } // if
660  } // case
661  break;
662  case kmp_sch_static_greedy:
663  KD_TRACE(
664  100,
665  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_greedy case\n",
666  gtid));
667  pr->u.p.parm1 = (nproc > 1) ? (tc + nproc - 1) / nproc : tc;
668  break;
669  case kmp_sch_static_chunked:
670  case kmp_sch_dynamic_chunked:
671  dynamic_init:
672  if (tc == 0)
673  break;
674  if (pr->u.p.parm1 <= 0)
675  pr->u.p.parm1 = KMP_DEFAULT_CHUNK;
676  else if (pr->u.p.parm1 > tc)
677  pr->u.p.parm1 = tc;
678  // Store the total number of chunks to prevent integer overflow during
679  // bounds calculations in the get next chunk routine.
680  pr->u.p.parm2 = (tc / pr->u.p.parm1) + (tc % pr->u.p.parm1 ? 1 : 0);
681  KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d "
682  "kmp_sch_static_chunked/kmp_sch_dynamic_chunked cases\n",
683  gtid));
684  break;
685  case kmp_sch_trapezoidal: {
686  /* TSS: trapezoid self-scheduling, minimum chunk_size = parm1 */
687 
688  T parm1, parm2, parm3, parm4;
689  KD_TRACE(100,
690  ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_trapezoidal case\n",
691  gtid));
692 
693  parm1 = chunk;
694 
695  /* F : size of the first cycle */
696  parm2 = (tc / (2 * nproc));
697 
698  if (parm2 < 1) {
699  parm2 = 1;
700  }
701 
702  /* L : size of the last cycle. Make sure the last cycle is not larger
703  than the first cycle. */
704  if (parm1 < 1) {
705  parm1 = 1;
706  } else if (parm1 > parm2) {
707  parm1 = parm2;
708  }
709 
710  /* N : number of cycles */
711  parm3 = (parm2 + parm1);
712  parm3 = (2 * tc + parm3 - 1) / parm3;
713 
714  if (parm3 < 2) {
715  parm3 = 2;
716  }
717 
718  /* sigma : decreasing incr of the trapezoid */
719  parm4 = (parm3 - 1);
720  parm4 = (parm2 - parm1) / parm4;
721 
722  // pointless check, because parm4 >= 0 always
723  // if ( parm4 < 0 ) {
724  // parm4 = 0;
725  //}
726 
727  pr->u.p.parm1 = parm1;
728  pr->u.p.parm2 = parm2;
729  pr->u.p.parm3 = parm3;
730  pr->u.p.parm4 = parm4;
731  } // case
732  break;
733 
734  default: {
735  __kmp_fatal(KMP_MSG(UnknownSchedTypeDetected), // Primary message
736  KMP_HNT(GetNewerLibrary), // Hint
737  __kmp_msg_null // Variadic argument list terminator
738  );
739  } break;
740  } // switch
741  pr->schedule = schedule;
742 }
743 
744 #if KMP_USE_HIER_SCHED
745 template <typename T>
746 inline void __kmp_dispatch_init_hier_runtime(ident_t *loc, T lb, T ub,
747  typename traits_t<T>::signed_t st);
748 template <>
749 inline void
750 __kmp_dispatch_init_hier_runtime<kmp_int32>(ident_t *loc, kmp_int32 lb,
751  kmp_int32 ub, kmp_int32 st) {
752  __kmp_dispatch_init_hierarchy<kmp_int32>(
753  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
754  __kmp_hier_scheds.scheds, __kmp_hier_scheds.small_chunks, lb, ub, st);
755 }
756 template <>
757 inline void
758 __kmp_dispatch_init_hier_runtime<kmp_uint32>(ident_t *loc, kmp_uint32 lb,
759  kmp_uint32 ub, kmp_int32 st) {
760  __kmp_dispatch_init_hierarchy<kmp_uint32>(
761  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
762  __kmp_hier_scheds.scheds, __kmp_hier_scheds.small_chunks, lb, ub, st);
763 }
764 template <>
765 inline void
766 __kmp_dispatch_init_hier_runtime<kmp_int64>(ident_t *loc, kmp_int64 lb,
767  kmp_int64 ub, kmp_int64 st) {
768  __kmp_dispatch_init_hierarchy<kmp_int64>(
769  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
770  __kmp_hier_scheds.scheds, __kmp_hier_scheds.large_chunks, lb, ub, st);
771 }
772 template <>
773 inline void
774 __kmp_dispatch_init_hier_runtime<kmp_uint64>(ident_t *loc, kmp_uint64 lb,
775  kmp_uint64 ub, kmp_int64 st) {
776  __kmp_dispatch_init_hierarchy<kmp_uint64>(
777  loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
778  __kmp_hier_scheds.scheds, __kmp_hier_scheds.large_chunks, lb, ub, st);
779 }
780 
781 // free all the hierarchy scheduling memory associated with the team
782 void __kmp_dispatch_free_hierarchies(kmp_team_t *team) {
783  int num_disp_buff = team->t.t_max_nproc > 1 ? __kmp_dispatch_num_buffers : 2;
784  for (int i = 0; i < num_disp_buff; ++i) {
785  // type does not matter here so use kmp_int32
786  auto sh =
787  reinterpret_cast<dispatch_shared_info_template<kmp_int32> volatile *>(
788  &team->t.t_disp_buffer[i]);
789  if (sh->hier) {
790  sh->hier->deallocate();
791  __kmp_free(sh->hier);
792  }
793  }
794 }
795 #endif
796 
797 // UT - unsigned flavor of T, ST - signed flavor of T,
798 // DBL - double if sizeof(T)==4, or long double if sizeof(T)==8
799 template <typename T>
800 static void
801 __kmp_dispatch_init(ident_t *loc, int gtid, enum sched_type schedule, T lb,
802  T ub, typename traits_t<T>::signed_t st,
803  typename traits_t<T>::signed_t chunk, int push_ws) {
804  typedef typename traits_t<T>::unsigned_t UT;
805 
806  int active;
807  kmp_info_t *th;
808  kmp_team_t *team;
809  kmp_uint32 my_buffer_index;
810  dispatch_private_info_template<T> *pr;
811  dispatch_shared_info_template<T> volatile *sh;
812 
813  KMP_BUILD_ASSERT(sizeof(dispatch_private_info_template<T>) ==
814  sizeof(dispatch_private_info));
815  KMP_BUILD_ASSERT(sizeof(dispatch_shared_info_template<UT>) ==
816  sizeof(dispatch_shared_info));
817  __kmp_assert_valid_gtid(gtid);
818 
819  if (!TCR_4(__kmp_init_parallel))
820  __kmp_parallel_initialize();
821 
822  __kmp_resume_if_soft_paused();
823 
824 #if INCLUDE_SSC_MARKS
825  SSC_MARK_DISPATCH_INIT();
826 #endif
827 #ifdef KMP_DEBUG
828  typedef typename traits_t<T>::signed_t ST;
829  {
830  char *buff;
831  // create format specifiers before the debug output
832  buff = __kmp_str_format("__kmp_dispatch_init: T#%%d called: schedule:%%d "
833  "chunk:%%%s lb:%%%s ub:%%%s st:%%%s\n",
834  traits_t<ST>::spec, traits_t<T>::spec,
835  traits_t<T>::spec, traits_t<ST>::spec);
836  KD_TRACE(10, (buff, gtid, schedule, chunk, lb, ub, st));
837  __kmp_str_free(&buff);
838  }
839 #endif
840  /* setup data */
841  th = __kmp_threads[gtid];
842  team = th->th.th_team;
843  active = !team->t.t_serialized;
844  th->th.th_ident = loc;
845 
846  // Any half-decent optimizer will remove this test when the blocks are empty
847  // since the macros expand to nothing
848  // when statistics are disabled.
849  if (schedule == __kmp_static) {
850  KMP_COUNT_BLOCK(OMP_LOOP_STATIC);
851  } else {
852  KMP_COUNT_BLOCK(OMP_LOOP_DYNAMIC);
853  }
854 
855 #if KMP_USE_HIER_SCHED
856  // Initialize the scheduling hierarchy if requested in OMP_SCHEDULE envirable
857  // Hierarchical scheduling does not work with ordered, so if ordered is
858  // detected, then revert back to threaded scheduling.
859  bool ordered;
860  enum sched_type my_sched = schedule;
861  my_buffer_index = th->th.th_dispatch->th_disp_index;
862  pr = reinterpret_cast<dispatch_private_info_template<T> *>(
863  &th->th.th_dispatch
864  ->th_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
865  my_sched = SCHEDULE_WITHOUT_MODIFIERS(my_sched);
866  if ((my_sched >= kmp_nm_lower) && (my_sched