LLVM OpenMP* Runtime Library
Loading...
Searching...
No Matches
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
42void __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
60void __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
72static 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_WEIGHTED_ITERATIONS_SUPPORTED
94// Return floating point number rounded to two decimal points
95static inline float __kmp_round_2decimal_val(float num) {
96 return (float)(static_cast<int>(num * 100 + 0.5)) / 100;
97}
98static inline int __kmp_get_round_val(float num) {
99 return static_cast<int>(num < 0 ? num - 0.5 : num + 0.5);
100}
101#endif
102
103template <typename T>
104inline void
105__kmp_initialize_self_buffer(kmp_team_t *team, T id,
106 dispatch_private_info_template<T> *pr,
107 typename traits_t<T>::unsigned_t nchunks, T nproc,
108 typename traits_t<T>::unsigned_t &init,
109 T &small_chunk, T &extras, T &p_extra) {
110
111#if KMP_WEIGHTED_ITERATIONS_SUPPORTED
112 if (pr->flags.use_hybrid) {
113 kmp_info_t *th = __kmp_threads[__kmp_gtid_from_tid((int)id, team)];
114 kmp_hw_core_type_t type =
115 (kmp_hw_core_type_t)th->th.th_topology_attrs.core_type;
116 T pchunks = pr->u.p.pchunks;
117 T echunks = nchunks - pchunks;
118 T num_procs_with_pcore = pr->u.p.num_procs_with_pcore;
119 T num_procs_with_ecore = nproc - num_procs_with_pcore;
120 T first_thread_with_ecore = pr->u.p.first_thread_with_ecore;
121 T big_chunk =
122 pchunks / num_procs_with_pcore; // chunks per thread with p-core
123 small_chunk =
124 echunks / num_procs_with_ecore; // chunks per thread with e-core
125
126 extras =
127 (pchunks % num_procs_with_pcore) + (echunks % num_procs_with_ecore);
128
129 p_extra = (big_chunk - small_chunk);
130
131 if (type == KMP_HW_CORE_TYPE_CORE) {
132 if (id < first_thread_with_ecore) {
133 init = id * small_chunk + id * p_extra + (id < extras ? id : extras);
134 } else {
135 init = id * small_chunk + (id - num_procs_with_ecore) * p_extra +
136 (id < extras ? id : extras);
137 }
138 } else {
139 if (id == first_thread_with_ecore) {
140 init = id * small_chunk + id * p_extra + (id < extras ? id : extras);
141 } else {
142 init = id * small_chunk + first_thread_with_ecore * p_extra +
143 (id < extras ? id : extras);
144 }
145 }
146 p_extra = (type == KMP_HW_CORE_TYPE_CORE) ? p_extra : 0;
147 return;
148 }
149#endif
150
151 small_chunk = nchunks / nproc; // chunks per thread
152 extras = nchunks % nproc;
153 p_extra = 0;
154 init = id * small_chunk + (id < extras ? id : extras);
155}
156
157#if KMP_STATIC_STEAL_ENABLED
158enum { // values for steal_flag (possible states of private per-loop buffer)
159 UNUSED = 0,
160 CLAIMED = 1, // owner thread started initialization
161 READY = 2, // available for stealing
162 THIEF = 3 // finished by owner, or claimed by thief
163 // possible state changes:
164 // 0 -> 1 owner only, sync
165 // 0 -> 3 thief only, sync
166 // 1 -> 2 owner only, async
167 // 2 -> 3 owner only, async
168 // 3 -> 2 owner only, async
169 // 3 -> 0 last thread finishing the loop, async
170};
171#endif
172
173// Initialize a dispatch_private_info_template<T> buffer for a particular
174// type of schedule,chunk. The loop description is found in lb (lower bound),
175// ub (upper bound), and st (stride). nproc is the number of threads relevant
176// to the scheduling (often the number of threads in a team, but not always if
177// hierarchical scheduling is used). tid is the id of the thread calling
178// the function within the group of nproc threads. It will have a value
179// between 0 and nproc - 1. This is often just the thread id within a team, but
180// is not necessarily the case when using hierarchical scheduling.
181// loc is the source file location of the corresponding loop
182// gtid is the global thread id
183template <typename T>
184void __kmp_dispatch_init_algorithm(ident_t *loc, int gtid,
185 dispatch_private_info_template<T> *pr,
186 enum sched_type schedule, T lb, T ub,
187 typename traits_t<T>::signed_t st,
188#if USE_ITT_BUILD
189 kmp_uint64 *cur_chunk,
190#endif
191 typename traits_t<T>::signed_t chunk,
192 T nproc, T tid) {
193 typedef typename traits_t<T>::unsigned_t UT;
194 typedef typename traits_t<T>::floating_t DBL;
195
196 int active;
197 T tc;
198 kmp_info_t *th;
199 kmp_team_t *team;
200 int monotonicity;
201 bool use_hier;
202
203#ifdef KMP_DEBUG
204 typedef typename traits_t<T>::signed_t ST;
205 {
206 char *buff;
207 // create format specifiers before the debug output
208 buff = __kmp_str_format("__kmp_dispatch_init_algorithm: T#%%d called "
209 "pr:%%p lb:%%%s ub:%%%s st:%%%s "
210 "schedule:%%d chunk:%%%s nproc:%%%s tid:%%%s\n",
211 traits_t<T>::spec, traits_t<T>::spec,
212 traits_t<ST>::spec, traits_t<ST>::spec,
213 traits_t<T>::spec, traits_t<T>::spec);
214 KD_TRACE(10, (buff, gtid, pr, lb, ub, st, schedule, chunk, nproc, tid));
215 __kmp_str_free(&buff);
216 }
217#endif
218 /* setup data */
219 th = __kmp_threads[gtid];
220 team = th->th.th_team;
221 active = !team->t.t_serialized;
222
223#if USE_ITT_BUILD
224 int itt_need_metadata_reporting =
225 __itt_metadata_add_ptr && __kmp_forkjoin_frames_mode == 3 &&
226 KMP_MASTER_GTID(gtid) && th->th.th_teams_microtask == NULL &&
227 team->t.t_active_level == 1;
228#endif
229
230#if KMP_USE_HIER_SCHED
231 use_hier = pr->flags.use_hier;
232#else
233 use_hier = false;
234#endif
235
236 /* Pick up the nonmonotonic/monotonic bits from the scheduling type */
237 monotonicity = __kmp_get_monotonicity(loc, schedule, use_hier);
238 schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
239
240 /* Pick up the nomerge/ordered bits from the scheduling type */
241 if ((schedule >= kmp_nm_lower) && (schedule < kmp_nm_upper)) {
242 pr->flags.nomerge = TRUE;
243 schedule =
244 (enum sched_type)(((int)schedule) - (kmp_nm_lower - kmp_sch_lower));
245 } else {
246 pr->flags.nomerge = FALSE;
247 }
248 pr->type_size = traits_t<T>::type_size; // remember the size of variables
249 if (kmp_ord_lower & schedule) {
250 pr->flags.ordered = TRUE;
251 schedule =
252 (enum sched_type)(((int)schedule) - (kmp_ord_lower - kmp_sch_lower));
253 } else {
254 pr->flags.ordered = FALSE;
255 }
256 // Ordered overrides nonmonotonic
257 if (pr->flags.ordered) {
258 monotonicity = SCHEDULE_MONOTONIC;
259 }
260
261 if (schedule == kmp_sch_static) {
262 schedule = __kmp_static;
263 } else {
264 if (schedule == kmp_sch_runtime) {
265 // Use the scheduling specified by OMP_SCHEDULE (or __kmp_sch_default if
266 // not specified)
267 schedule = team->t.t_sched.r_sched_type;
268#if KMP_STATIC_STEAL_ENABLED
269 // Treat static_steal set by omp_set_schedule() like
270 // OMP_SCHEDULE=static_steal, i.e. as nonmonotonic dynamic
271 if (SCHEDULE_WITHOUT_MODIFIERS(schedule) == kmp_sch_static_steal)
272 schedule = (enum sched_type)(kmp_sch_dynamic_chunked |
274#endif
275 monotonicity = __kmp_get_monotonicity(loc, schedule, use_hier);
276 schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
277 if (pr->flags.ordered) // correct monotonicity for ordered loop if needed
278 monotonicity = SCHEDULE_MONOTONIC;
279 // Detail the schedule if needed (global controls are differentiated
280 // appropriately)
281 if (schedule == kmp_sch_guided_chunked) {
282 schedule = __kmp_guided;
283 } else if (schedule == kmp_sch_static) {
284 schedule = __kmp_static;
285 }
286 // Use the chunk size specified by OMP_SCHEDULE (or default if not
287 // specified)
288 chunk = team->t.t_sched.chunk;
289#if USE_ITT_BUILD
290 if (cur_chunk)
291 *cur_chunk = chunk;
292#endif
293#ifdef KMP_DEBUG
294 {
295 char *buff;
296 // create format specifiers before the debug output
297 buff = __kmp_str_format("__kmp_dispatch_init_algorithm: T#%%d new: "
298 "schedule:%%d chunk:%%%s\n",
299 traits_t<ST>::spec);
300 KD_TRACE(10, (buff, gtid, schedule, chunk));
301 __kmp_str_free(&buff);
302 }
303#endif
304 } else {
305 if (schedule == kmp_sch_guided_chunked) {
306 schedule = __kmp_guided;
307 }
308 if (chunk <= 0) {
309 chunk = KMP_DEFAULT_CHUNK;
310 }
311 }
312
313 if (schedule == kmp_sch_auto) {
314 // mapping and differentiation: in the __kmp_do_serial_initialize()
315 schedule = __kmp_auto;
316#ifdef KMP_DEBUG
317 {
318 char *buff;
319 // create format specifiers before the debug output
320 buff = __kmp_str_format(
321 "__kmp_dispatch_init_algorithm: kmp_sch_auto: T#%%d new: "
322 "schedule:%%d chunk:%%%s\n",
323 traits_t<ST>::spec);
324 KD_TRACE(10, (buff, gtid, schedule, chunk));
325 __kmp_str_free(&buff);
326 }
327#endif
328 }
329#if KMP_STATIC_STEAL_ENABLED
330 // map nonmonotonic:dynamic to static steal
331 if (schedule == kmp_sch_dynamic_chunked) {
332 if (monotonicity == SCHEDULE_NONMONOTONIC)
333 schedule = kmp_sch_static_steal;
334 }
335#endif
336 /* guided analytical not safe for too many threads */
337 if (schedule == kmp_sch_guided_analytical_chunked && nproc > 1 << 20) {
338 schedule = kmp_sch_guided_iterative_chunked;
339 KMP_WARNING(DispatchManyThreads);
340 }
341 if (schedule == kmp_sch_runtime_simd) {
342 // compiler provides simd_width in the chunk parameter
343 schedule = team->t.t_sched.r_sched_type;
344 monotonicity = __kmp_get_monotonicity(loc, schedule, use_hier);
345 schedule = SCHEDULE_WITHOUT_MODIFIERS(schedule);
346 // Detail the schedule if needed (global controls are differentiated
347 // appropriately)
348 if (schedule == kmp_sch_static || schedule == kmp_sch_auto ||
349 schedule == __kmp_static) {
350 schedule = kmp_sch_static_balanced_chunked;
351 } else {
352 if (schedule == kmp_sch_guided_chunked || schedule == __kmp_guided) {
353 schedule = kmp_sch_guided_simd;
354 }
355 chunk = team->t.t_sched.chunk * chunk;
356 }
357#if USE_ITT_BUILD
358 if (cur_chunk)
359 *cur_chunk = chunk;
360#endif
361#ifdef KMP_DEBUG
362 {
363 char *buff;
364 // create format specifiers before the debug output
365 buff = __kmp_str_format(
366 "__kmp_dispatch_init_algorithm: T#%%d new: schedule:%%d"
367 " chunk:%%%s\n",
368 traits_t<ST>::spec);
369 KD_TRACE(10, (buff, gtid, schedule, chunk));
370 __kmp_str_free(&buff);
371 }
372#endif
373 }
374 pr->u.p.parm1 = chunk;
375 }
376 KMP_ASSERT2((kmp_sch_lower < schedule && schedule < kmp_sch_upper),
377 "unknown scheduling type");
378
379 pr->u.p.count = 0;
380
381 if (__kmp_env_consistency_check) {
382 if (st == 0) {
383 __kmp_error_construct(kmp_i18n_msg_CnsLoopIncrZeroProhibited,
384 (pr->flags.ordered ? ct_pdo_ordered : ct_pdo), loc);
385 }
386 }
387 // compute trip count
388 if (st == 1) { // most common case
389 if (ub >= lb) {
390 tc = ub - lb + 1;
391 } else { // ub < lb
392 tc = 0; // zero-trip
393 }
394 } else if (st < 0) {
395 if (lb >= ub) {
396 // AC: cast to unsigned is needed for loops like (i=2B; i>-2B; i-=1B),
397 // where the division needs to be unsigned regardless of the result type
398 tc = (UT)(lb - ub) / (-st) + 1;
399 } else { // lb < ub
400 tc = 0; // zero-trip
401 }
402 } else { // st > 0
403 if (ub >= lb) {
404 // AC: cast to unsigned is needed for loops like (i=-2B; i<2B; i+=1B),
405 // where the division needs to be unsigned regardless of the result type
406 tc = (UT)(ub - lb) / st + 1;
407 } else { // ub < lb
408 tc = 0; // zero-trip
409 }
410 }
411
412#if KMP_STATS_ENABLED
413 if (KMP_MASTER_GTID(gtid)) {
414 KMP_COUNT_VALUE(OMP_loop_dynamic_total_iterations, tc);
415 }
416#endif
417
418 pr->u.p.lb = lb;
419 pr->u.p.ub = ub;
420 pr->u.p.st = st;
421 pr->u.p.tc = tc;
422
423#if KMP_OS_WINDOWS
424 pr->u.p.last_upper = ub + st;
425#endif /* KMP_OS_WINDOWS */
426
427 /* NOTE: only the active parallel region(s) has active ordered sections */
428
429 if (active) {
430 if (pr->flags.ordered) {
431 pr->ordered_bumped = 0;
432 pr->u.p.ordered_lower = 1;
433 pr->u.p.ordered_upper = 0;
434 }
435 }
436
437 switch (schedule) {
438#if KMP_STATIC_STEAL_ENABLED
439 case kmp_sch_static_steal: {
440 T ntc, init = 0;
441
442 KD_TRACE(100,
443 ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_steal case\n",
444 gtid));
445
446 ntc = (tc % chunk ? 1 : 0) + tc / chunk;
447 if (nproc > 1 && ntc >= nproc) {
448 KMP_COUNT_BLOCK(OMP_LOOP_STATIC_STEAL);
449 T id = tid;
450 T small_chunk, extras, p_extra = 0;
451 kmp_uint32 old = UNUSED;
452 int claimed = pr->steal_flag.compare_exchange_strong(old, CLAIMED);
453 if (traits_t<T>::type_size > 4) {
454 // AC: TODO: check if 16-byte CAS available and use it to
455 // improve performance (probably wait for explicit request
456 // before spending time on this).
457 // For now use dynamically allocated per-private-buffer lock,
458 // free memory in __kmp_dispatch_next when status==0.
459 pr->u.p.steal_lock = (kmp_lock_t *)__kmp_allocate(sizeof(kmp_lock_t));
460 __kmp_init_lock(pr->u.p.steal_lock);
461 }
462
463#if KMP_WEIGHTED_ITERATIONS_SUPPORTED
464 // Iterations are divided in a 60/40 skewed distribution among CORE and
465 // ATOM processors for hybrid systems
466 bool use_hybrid = false;
467 kmp_hw_core_type_t core_type = KMP_HW_CORE_TYPE_UNKNOWN;
468 T first_thread_with_ecore = 0;
469 T num_procs_with_pcore = 0;
470 T num_procs_with_ecore = 0;
471 T p_ntc = 0, e_ntc = 0;
472 if (__kmp_is_hybrid_cpu() && __kmp_affinity.type != affinity_none &&
473 __kmp_affinity.type != affinity_explicit) {
474 use_hybrid = true;
475 core_type = (kmp_hw_core_type_t)th->th.th_topology_attrs.core_type;
476 if (core_type != KMP_HW_CORE_TYPE_UNKNOWN &&
477 __kmp_first_osid_with_ecore > -1) {
478 for (int i = 0; i < team->t.t_nproc; ++i) {
479 kmp_hw_core_type_t type = (kmp_hw_core_type_t)team->t.t_threads[i]
480 ->th.th_topology_attrs.core_type;
481 int id = team->t.t_threads[i]->th.th_topology_ids.os_id;
482 if (id == __kmp_first_osid_with_ecore) {
483 first_thread_with_ecore =
484 team->t.t_threads[i]->th.th_info.ds.ds_tid;
485 }
486 if (type == KMP_HW_CORE_TYPE_CORE) {
487 num_procs_with_pcore++;
488 } else if (type == KMP_HW_CORE_TYPE_ATOM) {
489 num_procs_with_ecore++;
490 } else {
491 use_hybrid = false;
492 break;
493 }
494 }
495 }
496 if (num_procs_with_pcore > 0 && num_procs_with_ecore > 0) {
497 float multiplier = 60.0 / 40.0;
498 float p_ratio = (float)num_procs_with_pcore / nproc;
499 float e_ratio = (float)num_procs_with_ecore / nproc;
500 float e_multiplier =
501 (float)1 /
502 (((multiplier * num_procs_with_pcore) / nproc) + e_ratio);
503 float p_multiplier = multiplier * e_multiplier;
504 p_ntc = __kmp_get_round_val(ntc * p_ratio * p_multiplier);
505 if ((int)p_ntc > (int)(ntc * p_ratio * p_multiplier))
506 e_ntc =
507 (int)(__kmp_round_2decimal_val(ntc * e_ratio * e_multiplier));
508 else
509 e_ntc = __kmp_get_round_val(ntc * e_ratio * e_multiplier);
510 KMP_DEBUG_ASSERT(ntc == p_ntc + e_ntc);
511
512 // Use regular static steal if not enough chunks for skewed
513 // distribution
514 use_hybrid = (use_hybrid && (p_ntc >= num_procs_with_pcore &&
515 e_ntc >= num_procs_with_ecore)
516 ? true
517 : false);
518 } else {
519 use_hybrid = false;
520 }
521 }
522 pr->flags.use_hybrid = use_hybrid;
523 pr->u.p.pchunks = p_ntc;
524 pr->u.p.num_procs_with_pcore = num_procs_with_pcore;
525 pr->u.p.first_thread_with_ecore = first_thread_with_ecore;
526
527 if (use_hybrid) {
528 KMP_DEBUG_ASSERT(nproc == num_procs_with_pcore + num_procs_with_ecore);
529 T big_chunk = p_ntc / num_procs_with_pcore;
530 small_chunk = e_ntc / num_procs_with_ecore;
531
532 extras =
533 (p_ntc % num_procs_with_pcore) + (e_ntc % num_procs_with_ecore);
534
535 p_extra = (big_chunk - small_chunk);
536
537 if (core_type == KMP_HW_CORE_TYPE_CORE) {
538 if (id < first_thread_with_ecore) {
539 init =
540 id * small_chunk + id * p_extra + (id < extras ? id : extras);
541 } else {
542 init = id * small_chunk + (id - num_procs_with_ecore) * p_extra +
543 (id < extras ? id : extras);
544 }
545 } else {
546 if (id == first_thread_with_ecore) {
547 init =
548 id * small_chunk + id * p_extra + (id < extras ? id : extras);
549 } else {
550 init = id * small_chunk + first_thread_with_ecore * p_extra +
551 (id < extras ? id : extras);
552 }
553 }
554 p_extra = (core_type == KMP_HW_CORE_TYPE_CORE) ? p_extra : 0;
555 } else
556#endif
557 {
558 small_chunk = ntc / nproc;
559 extras = ntc % nproc;
560 init = id * small_chunk + (id < extras ? id : extras);
561 p_extra = 0;
562 }
563 pr->u.p.count = init;
564 if (claimed) { // are we succeeded in claiming own buffer?
565 pr->u.p.ub = init + small_chunk + p_extra + (id < extras ? 1 : 0);
566 // Other threads will inspect steal_flag when searching for a victim.
567 // READY means other threads may steal from this thread from now on.
568 KMP_ATOMIC_ST_REL(&pr->steal_flag, READY);
569 } else {
570 // other thread has stolen whole our range
571 KMP_DEBUG_ASSERT(pr->steal_flag == THIEF);
572 pr->u.p.ub = init; // mark there is no iterations to work on
573 }
574 pr->u.p.parm2 = ntc; // save number of chunks
575 // parm3 is the number of times to attempt stealing which is
576 // nproc (just a heuristics, could be optimized later on).
577 pr->u.p.parm3 = nproc;
578 pr->u.p.parm4 = (id + 1) % nproc; // remember neighbour tid
579 break;
580 } else {
581 /* too few chunks: switching to kmp_sch_dynamic_chunked */
582 schedule = kmp_sch_dynamic_chunked;
583 KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d switching to "
584 "kmp_sch_dynamic_chunked\n",
585 gtid));
586 goto dynamic_init;
587 break;
588 } // if
589 } // case
590#endif
591 case kmp_sch_static_balanced: {
592 T init, limit;
593
594 KD_TRACE(
595 100,
596 ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_balanced case\n",
597 gtid));
598
599 if (nproc > 1) {
600 T id = tid;
601
602 if (tc < nproc) {
603 if (id < tc) {
604 init = id;
605 limit = id;
606 pr->u.p.parm1 = (id == tc - 1); /* parm1 stores *plastiter */
607 } else {
608 pr->u.p.count = 1; /* means no more chunks to execute */
609 pr->u.p.parm1 = FALSE;
610 break;
611 }
612 } else {
613 T small_chunk = tc / nproc;
614 T extras = tc % nproc;
615 init = id * small_chunk + (id < extras ? id : extras);
616 limit = init + small_chunk - (id < extras ? 0 : 1);
617 pr->u.p.parm1 = (id == nproc - 1);
618 }
619 } else {
620 if (tc > 0) {
621 init = 0;
622 limit = tc - 1;
623 pr->u.p.parm1 = TRUE;
624 } else {
625 // zero trip count
626 pr->u.p.count = 1; /* means no more chunks to execute */
627 pr->u.p.parm1 = FALSE;
628 break;
629 }
630 }
631#if USE_ITT_BUILD
632 // Calculate chunk for metadata report
633 if (itt_need_metadata_reporting)
634 if (cur_chunk)
635 *cur_chunk = limit - init + 1;
636#endif
637 if (st == 1) {
638 pr->u.p.lb = lb + init;
639 pr->u.p.ub = lb + limit;
640 } else {
641 // calculated upper bound, "ub" is user-defined upper bound
642 T ub_tmp = lb + limit * st;
643 pr->u.p.lb = lb + init * st;
644 // adjust upper bound to "ub" if needed, so that MS lastprivate will match
645 // it exactly
646 if (st > 0) {
647 pr->u.p.ub = (ub_tmp + st > ub ? ub : ub_tmp);
648 } else {
649 pr->u.p.ub = (ub_tmp + st < ub ? ub : ub_tmp);
650 }
651 }
652 if (pr->flags.ordered) {
653 pr->u.p.ordered_lower = init;
654 pr->u.p.ordered_upper = limit;
655 }
656 break;
657 } // case
658 case kmp_sch_static_balanced_chunked: {
659 // similar to balanced, but chunk adjusted to multiple of simd width
660 T nth = nproc;
661 KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d runtime(simd:static)"
662 " -> falling-through to static_greedy\n",
663 gtid));
664 schedule = kmp_sch_static_greedy;
665 if (nth > 1)
666 pr->u.p.parm1 = ((tc + nth - 1) / nth + chunk - 1) & ~(chunk - 1);
667 else
668 pr->u.p.parm1 = tc;
669 break;
670 } // case
672 case kmp_sch_guided_iterative_chunked: {
673 KD_TRACE(
674 100,
675 ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_guided_iterative_chunked"
676 " case\n",
677 gtid));
678
679 if (nproc > 1) {
680 if ((2L * chunk + 1) * nproc >= tc) {
681 /* chunk size too large, switch to dynamic */
682 schedule = kmp_sch_dynamic_chunked;
683 goto dynamic_init;
684 } else {
685 // when remaining iters become less than parm2 - switch to dynamic
686 pr->u.p.parm2 = guided_int_param * nproc * (chunk + 1);
687 *(double *)&pr->u.p.parm3 =
688 guided_flt_param / (double)nproc; // may occupy parm3 and parm4
689 }
690 } else {
691 KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d falling-through to "
692 "kmp_sch_static_greedy\n",
693 gtid));
694 schedule = kmp_sch_static_greedy;
695 /* team->t.t_nproc == 1: fall-through to kmp_sch_static_greedy */
696 KD_TRACE(
697 100,
698 ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_greedy case\n",
699 gtid));
700 pr->u.p.parm1 = tc;
701 } // if
702 } // case
703 break;
704 case kmp_sch_guided_analytical_chunked: {
705 KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d "
706 "kmp_sch_guided_analytical_chunked case\n",
707 gtid));
708
709 if (nproc > 1) {
710 if ((2L * chunk + 1) * nproc >= tc) {
711 /* chunk size too large, switch to dynamic */
712 schedule = kmp_sch_dynamic_chunked;
713 goto dynamic_init;
714 } else {
715 /* commonly used term: (2 nproc - 1)/(2 nproc) */
716 DBL x;
717
718#if KMP_USE_X87CONTROL
719 /* Linux* OS already has 64-bit computation by default for long double,
720 and on Windows* OS on Intel(R) 64, /Qlong_double doesn't work. On
721 Windows* OS on IA-32 architecture, we need to set precision to 64-bit
722 instead of the default 53-bit. Even though long double doesn't work
723 on Windows* OS on Intel(R) 64, the resulting lack of precision is not
724 expected to impact the correctness of the algorithm, but this has not
725 been mathematically proven. */
726 // save original FPCW and set precision to 64-bit, as
727 // Windows* OS on IA-32 architecture defaults to 53-bit
728 unsigned int oldFpcw = _control87(0, 0);
729 _control87(_PC_64, _MCW_PC); // 0,0x30000
730#endif
731 /* value used for comparison in solver for cross-over point */
732 KMP_ASSERT(tc > 0);
733 long double target = ((long double)chunk * 2 + 1) * nproc / tc;
734
735 /* crossover point--chunk indexes equal to or greater than
736 this point switch to dynamic-style scheduling */
737 UT cross;
738
739 /* commonly used term: (2 nproc - 1)/(2 nproc) */
740 x = 1.0 - 0.5 / (double)nproc;
741
742#ifdef KMP_DEBUG
743 { // test natural alignment
744 struct _test_a {
745 char a;
746 union {
747 char b;
748 DBL d;
749 };
750 } t;
751 ptrdiff_t natural_alignment =
752 (ptrdiff_t)&t.b - (ptrdiff_t)&t - (ptrdiff_t)1;
753 //__kmp_warn( " %llx %llx %lld", (long long)&t.d, (long long)&t, (long
754 // long)natural_alignment );
755 KMP_DEBUG_ASSERT(
756 (((ptrdiff_t)&pr->u.p.parm3) & (natural_alignment)) == 0);
757 }
758#endif // KMP_DEBUG
759
760 /* save the term in thread private dispatch structure */
761 *(DBL *)&pr->u.p.parm3 = x;
762
763 /* solve for the crossover point to the nearest integer i for which C_i
764 <= chunk */
765 {
766 UT left, right, mid;
767 long double p;
768
769 /* estimate initial upper and lower bound */
770
771 /* doesn't matter what value right is as long as it is positive, but
772 it affects performance of the solver */
773 right = 229;
774 p = __kmp_pow<UT>(x, right);
775 if (p > target) {
776 do {
777 p *= p;
778 right <<= 1;
779 } while (p > target && right < (1 << 27));
780 /* lower bound is previous (failed) estimate of upper bound */
781 left = right >> 1;
782 } else {
783 left = 0;
784 }
785
786 /* bisection root-finding method */
787 while (left + 1 < right) {
788 mid = (left + right) / 2;
789 if (__kmp_pow<UT>(x, mid) > target) {
790 left = mid;
791 } else {
792 right = mid;
793 }
794 } // while
795 cross = right;
796 }
797 /* assert sanity of computed crossover point */
798 KMP_ASSERT(cross && __kmp_pow<UT>(x, cross - 1) > target &&
799 __kmp_pow<UT>(x, cross) <= target);
800
801 /* save the crossover point in thread private dispatch structure */
802 pr->u.p.parm2 = cross;
803
804// C75803
805#if ((KMP_OS_LINUX || KMP_OS_WINDOWS) && KMP_ARCH_X86) && (!defined(KMP_I8))
806#define GUIDED_ANALYTICAL_WORKAROUND (*(DBL *)&pr->u.p.parm3)
807#else
808#define GUIDED_ANALYTICAL_WORKAROUND (x)
809#endif
810 /* dynamic-style scheduling offset */
811 pr->u.p.count = tc -
812 __kmp_dispatch_guided_remaining(
813 tc, GUIDED_ANALYTICAL_WORKAROUND, cross) -
814 cross * chunk;
815#if KMP_USE_X87CONTROL
816 // restore FPCW
817 _control87(oldFpcw, _MCW_PC);
818#endif
819 } // if
820 } else {
821 KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d falling-through to "
822 "kmp_sch_static_greedy\n",
823 gtid));
824 schedule = kmp_sch_static_greedy;
825 /* team->t.t_nproc == 1: fall-through to kmp_sch_static_greedy */
826 pr->u.p.parm1 = tc;
827 } // if
828 } // case
829 break;
830 case kmp_sch_static_greedy:
831 KD_TRACE(
832 100,
833 ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_static_greedy case\n",
834 gtid));
835 pr->u.p.parm1 = (nproc > 1) ? (tc + nproc - 1) / nproc : tc;
836 break;
837 case kmp_sch_static_chunked:
838 case kmp_sch_dynamic_chunked:
839 dynamic_init:
840 if (tc == 0)
841 break;
842 if (pr->u.p.parm1 <= 0)
843 pr->u.p.parm1 = KMP_DEFAULT_CHUNK;
844 else if (pr->u.p.parm1 > tc)
845 pr->u.p.parm1 = tc;
846 // Store the total number of chunks to prevent integer overflow during
847 // bounds calculations in the get next chunk routine.
848 pr->u.p.parm2 = (tc / pr->u.p.parm1) + (tc % pr->u.p.parm1 ? 1 : 0);
849 KD_TRACE(100, ("__kmp_dispatch_init_algorithm: T#%d "
850 "kmp_sch_static_chunked/kmp_sch_dynamic_chunked cases\n",
851 gtid));
852 break;
853 case kmp_sch_trapezoidal: {
854 /* TSS: trapezoid self-scheduling, minimum chunk_size = parm1 */
855
856 T parm1, parm2, parm3, parm4;
857 KD_TRACE(100,
858 ("__kmp_dispatch_init_algorithm: T#%d kmp_sch_trapezoidal case\n",
859 gtid));
860
861 parm1 = chunk;
862
863 /* F : size of the first cycle */
864 parm2 = (tc / (2 * nproc));
865
866 if (parm2 < 1) {
867 parm2 = 1;
868 }
869
870 /* L : size of the last cycle. Make sure the last cycle is not larger
871 than the first cycle. */
872 if (parm1 < 1) {
873 parm1 = 1;
874 } else if (parm1 > parm2) {
875 parm1 = parm2;
876 }
877
878 /* N : number of cycles */
879 parm3 = (parm2 + parm1);
880 parm3 = (2 * tc + parm3 - 1) / parm3;
881
882 if (parm3 < 2) {
883 parm3 = 2;
884 }
885
886 /* sigma : decreasing incr of the trapezoid */
887 parm4 = (parm3 - 1);
888 parm4 = (parm2 - parm1) / parm4;
889
890 // pointless check, because parm4 >= 0 always
891 // if ( parm4 < 0 ) {
892 // parm4 = 0;
893 //}
894
895 pr->u.p.parm1 = parm1;
896 pr->u.p.parm2 = parm2;
897 pr->u.p.parm3 = parm3;
898 pr->u.p.parm4 = parm4;
899 } // case
900 break;
901
902 default: {
903 __kmp_fatal(KMP_MSG(UnknownSchedTypeDetected), // Primary message
904 KMP_HNT(GetNewerLibrary), // Hint
905 __kmp_msg_null // Variadic argument list terminator
906 );
907 } break;
908 } // switch
909 pr->schedule = schedule;
910}
911
912#if KMP_USE_HIER_SCHED
913template <typename T>
914inline void __kmp_dispatch_init_hier_runtime(ident_t *loc, T lb, T ub,
915 typename traits_t<T>::signed_t st);
916template <>
917inline void
918__kmp_dispatch_init_hier_runtime<kmp_int32>(ident_t *loc, kmp_int32 lb,
919 kmp_int32 ub, kmp_int32 st) {
920 __kmp_dispatch_init_hierarchy<kmp_int32>(
921 loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
922 __kmp_hier_scheds.scheds, __kmp_hier_scheds.small_chunks, lb, ub, st);
923}
924template <>
925inline void
926__kmp_dispatch_init_hier_runtime<kmp_uint32>(ident_t *loc, kmp_uint32 lb,
927 kmp_uint32 ub, kmp_int32 st) {
928 __kmp_dispatch_init_hierarchy<kmp_uint32>(
929 loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
930 __kmp_hier_scheds.scheds, __kmp_hier_scheds.small_chunks, lb, ub, st);
931}
932template <>
933inline void
934__kmp_dispatch_init_hier_runtime<kmp_int64>(ident_t *loc, kmp_int64 lb,
935 kmp_int64 ub, kmp_int64 st) {
936 __kmp_dispatch_init_hierarchy<kmp_int64>(
937 loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
938 __kmp_hier_scheds.scheds, __kmp_hier_scheds.large_chunks, lb, ub, st);
939}
940template <>
941inline void
942__kmp_dispatch_init_hier_runtime<kmp_uint64>(ident_t *loc, kmp_uint64 lb,
943 kmp_uint64 ub, kmp_int64 st) {
944 __kmp_dispatch_init_hierarchy<kmp_uint64>(
945 loc, __kmp_hier_scheds.size, __kmp_hier_scheds.layers,
946 __kmp_hier_scheds.scheds, __kmp_hier_scheds.large_chunks, lb, ub, st);
947}
948
949// free all the hierarchy scheduling memory associated with the team
950void __kmp_dispatch_free_hierarchies(kmp_team_t *team) {
951 int num_disp_buff = team->t.t_max_nproc > 1 ? __kmp_dispatch_num_buffers : 2;
952 for (int i = 0; i < num_disp_buff; ++i) {
953 // type does not matter here so use kmp_int32
954 auto sh =
955 reinterpret_cast<dispatch_shared_info_template<kmp_int32> volatile *>(
956 &team->t.t_disp_buffer[i]);
957 if (sh->hier) {
958 sh->hier->deallocate();
959 __kmp_free(sh->hier);
960 }
961 }
962}
963#endif
964
965// UT - unsigned flavor of T, ST - signed flavor of T,
966// DBL - double if sizeof(T)==4, or long double if sizeof(T)==8
967template <typename T>
968static void
969__kmp_dispatch_init(ident_t *loc, int gtid, enum sched_type schedule, T lb,
970 T ub, typename traits_t<T>::signed_t st,
971 typename traits_t<T>::signed_t chunk, int push_ws) {
972 typedef typename traits_t<T>::unsigned_t UT;
973
974 int active;
975 kmp_info_t *th;
976 kmp_team_t *team;
977 kmp_uint32 my_buffer_index;
978 dispatch_private_info_template<T> *pr;
979 dispatch_shared_info_template<T> volatile *sh;
980
981 KMP_BUILD_ASSERT(sizeof(dispatch_private_info_template<T>) ==
982 sizeof(dispatch_private_info));
983 KMP_BUILD_ASSERT(sizeof(dispatch_shared_info_template<UT>) ==
984 sizeof(dispatch_shared_info));
985 __kmp_assert_valid_gtid(gtid);
986
987 if (!TCR_4(__kmp_init_parallel))
988 __kmp_parallel_initialize();
989
990 __kmp_resume_if_soft_paused();
991
992#if INCLUDE_SSC_MARKS
993 SSC_MARK_DISPATCH_INIT();
994#endif
995#ifdef KMP_DEBUG
996 typedef typename traits_t<T>::signed_t ST;
997 {
998 char *buff;
999 // create format specifiers before the debug output
1000 buff = __kmp_str_format("__kmp_dispatch_init: T#%%d called: schedule:%%d "
1001 "chunk:%%%s lb:%%%s ub:%%%s st:%%%s\n",
1002 traits_t<ST>::spec, traits_t<T>::spec,
1003 traits_t<T>::spec, traits_t<ST>::spec);
1004 KD_TRACE(10, (buff, gtid, schedule, chunk, lb, ub, st));
1005 __kmp_str_free(&buff);
1006 }
1007#endif
1008 /* setup data */
1009 th = __kmp_threads[gtid];
1010 team = th->th.th_team;
1011 active = !team->t.t_serialized;
1012 th->th.th_ident = loc;
1013
1014 // Any half-decent optimizer will remove this test when the blocks are empty
1015 // since the macros expand to nothing
1016 // when statistics are disabled.
1017 if (schedule == __kmp_static) {
1018 KMP_COUNT_BLOCK(OMP_LOOP_STATIC);
1019 } else {
1020 KMP_COUNT_BLOCK(OMP_LOOP_DYNAMIC);
1021 }
1022
1023#if KMP_USE_HIER_SCHED
1024 // Initialize the scheduling hierarchy if requested in OMP_SCHEDULE envirable
1025 // Hierarchical scheduling does not work with ordered, so if ordered is
1026 // detected, then revert back to threaded scheduling.
1027 bool ordered;
1028 enum sched_type my_sched = schedule;
1029 my_buffer_index = th->th.th_dispatch->th_disp_index;
1030 pr = reinterpret_cast<dispatch_private_info_template<T> *>(
1031 &th->th.th_dispatch
1032 ->th_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
1033 my_sched = SCHEDULE_WITHOUT_MODIFIERS(my_sched);
1034 if ((my_sched >= kmp_nm_lower) && (my_sched < kmp_nm_upper))
1035 my_sched =
1036 (enum sched_type)(((int)my_sched) - (kmp_nm_lower - kmp_sch_lower));
1037 ordered = (kmp_ord_lower & my_sched);
1038 if (pr->flags.use_hier) {
1039 if (ordered) {
1040 KD_TRACE(100, ("__kmp_dispatch_init: T#%d ordered loop detected. "
1041 "Disabling hierarchical scheduling.\n",
1042 gtid));
1043 pr->flags.use_hier = FALSE;
1044 }
1045 }
1046 if (schedule == kmp_sch_runtime && __kmp_hier_scheds.size > 0) {
1047 // Don't use hierarchical for ordered parallel loops and don't
1048 // use the runtime hierarchy if one was specified in the program
1049 if (!ordered && !pr->flags.use_hier)
1050 __kmp_dispatch_init_hier_runtime<T>(loc, lb, ub, st);
1051 }
1052#endif // KMP_USE_HIER_SCHED
1053
1054#if USE_ITT_BUILD
1055 kmp_uint64 cur_chunk = chunk;
1056 int itt_need_metadata_reporting =
1057 __itt_metadata_add_ptr && __kmp_forkjoin_frames_mode == 3 &&
1058 KMP_MASTER_GTID(gtid) && th->th.th_teams_microtask == NULL &&
1059 team->t.t_active_level == 1;
1060#endif
1061 if (!active) {
1062 pr = reinterpret_cast<dispatch_private_info_template<T> *>(
1063 th->th.th_dispatch->th_disp_buffer); /* top of the stack */
1064 } else {
1065 KMP_DEBUG_ASSERT(th->th.th_dispatch ==
1066 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
1067
1068 my_buffer_index = th->th.th_dispatch->th_disp_index++;
1069
1070 /* What happens when number of threads changes, need to resize buffer? */
1071 pr = reinterpret_cast<dispatch_private_info_template<T> *>(
1072 &th->th.th_dispatch
1073 ->th_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
1074 sh = reinterpret_cast<dispatch_shared_info_template<T> volatile *>(
1075 &team->t.t_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
1076 KD_TRACE(10, ("__kmp_dispatch_init: T#%d my_buffer_index:%d\n", gtid,
1077 my_buffer_index));
1078 if (sh->buffer_index != my_buffer_index) { // too many loops in progress?
1079 KD_TRACE(100, ("__kmp_dispatch_init: T#%d before wait: my_buffer_index:%d"
1080 " sh->buffer_index:%d\n",
1081 gtid, my_buffer_index, sh->buffer_index));
1082 __kmp_wait<kmp_uint32>(&sh->buffer_index, my_buffer_index,
1083 __kmp_eq<kmp_uint32> USE_ITT_BUILD_ARG(NULL));
1084 // Note: KMP_WAIT() cannot be used there: buffer index and
1085 // my_buffer_index are *always* 32-bit integers.
1086 KD_TRACE(100, ("__kmp_dispatch_init: T#%d after wait: my_buffer_index:%d "
1087 "sh->buffer_index:%d\n",
1088 gtid, my_buffer_index, sh->buffer_index));
1089 }
1090 }
1091
1092 __kmp_dispatch_init_algorithm(loc, gtid, pr, schedule, lb, ub, st,
1093#if USE_ITT_BUILD
1094 &cur_chunk,
1095#endif
1096 chunk, (T)th->th.th_team_nproc,
1097 (T)th->th.th_info.ds.ds_tid);
1098 if (active) {
1099 if (pr->flags.ordered == 0) {
1100 th->th.th_dispatch->th_deo_fcn = __kmp_dispatch_deo_error;
1101 th->th.th_dispatch->th_dxo_fcn = __kmp_dispatch_dxo_error;
1102 } else {
1103 th->th.th_dispatch->th_deo_fcn = __kmp_dispatch_deo<UT>;
1104 th->th.th_dispatch->th_dxo_fcn = __kmp_dispatch_dxo<UT>;
1105 }
1106 th->th.th_dispatch->th_dispatch_pr_current = (dispatch_private_info_t *)pr;
1107 th->th.th_dispatch->th_dispatch_sh_current =
1108 CCAST(dispatch_shared_info_t *, (volatile dispatch_shared_info_t *)sh);
1109#if USE_ITT_BUILD
1110 if (pr->flags.ordered) {
1111 __kmp_itt_ordered_init(gtid);
1112 }
1113 // Report loop metadata
1114 if (itt_need_metadata_reporting) {
1115 // Only report metadata by primary thread of active team at level 1
1116 kmp_uint64 schedtype = 0;
1117 switch (schedule) {
1118 case kmp_sch_static_chunked:
1119 case kmp_sch_static_balanced: // Chunk is calculated in the switch above
1120 break;
1121 case kmp_sch_static_greedy:
1122 cur_chunk = pr->u.p.parm1;
1123 break;
1124 case kmp_sch_dynamic_chunked:
1125 schedtype = 1;
1126 break;
1127 case kmp_sch_guided_iterative_chunked:
1128 case kmp_sch_guided_analytical_chunked:
1130 schedtype = 2;
1131 break;
1132 default:
1133 // Should we put this case under "static"?
1134 // case kmp_sch_static_steal:
1135 schedtype = 3;
1136 break;
1137 }
1138 __kmp_itt_metadata_loop(loc, schedtype, pr->u.p.tc, cur_chunk);
1139 }
1140#if KMP_USE_HIER_SCHED
1141 if (pr->flags.use_hier) {
1142 pr->u.p.count = 0;
1143 pr->u.p.ub = pr->u.p.lb = pr->u.p.st = pr->u.p.tc = 0;
1144 }
1145#endif // KMP_USER_HIER_SCHED
1146#endif /* USE_ITT_BUILD */
1147 }
1148
1149#ifdef KMP_DEBUG
1150 {
1151 char *buff;
1152 // create format specifiers before the debug output
1153 buff = __kmp_str_format(
1154 "__kmp_dispatch_init: T#%%d returning: schedule:%%d ordered:%%%s "
1155 "lb:%%%s ub:%%%s"
1156 " st:%%%s tc:%%%s count:%%%s\n\tordered_lower:%%%s ordered_upper:%%%s"
1157 " parm1:%%%s parm2:%%%s parm3:%%%s parm4:%%%s\n",
1158 traits_t<UT>::spec, traits_t<T>::spec, traits_t<T>::spec,
1159 traits_t<ST>::spec, traits_t<UT>::spec, traits_t<UT>::spec,
1160 traits_t<UT>::spec, traits_t<UT>::spec, traits_t<T>::spec,
1161 traits_t<T>::spec, traits_t<T>::spec, traits_t<T>::spec);
1162 KD_TRACE(10, (buff, gtid, pr->schedule, pr->flags.ordered, pr->u.p.lb,
1163 pr->u.p.ub, pr->u.p.st, pr->u.p.tc, pr->u.p.count,
1164 pr->u.p.ordered_lower, pr->u.p.ordered_upper, pr->u.p.parm1,
1165 pr->u.p.parm2, pr->u.p.parm3, pr->u.p.parm4));
1166 __kmp_str_free(&buff);
1167 }
1168#endif
1169#if OMPT_SUPPORT && OMPT_OPTIONAL
1170 if (ompt_enabled.ompt_callback_work) {
1171 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
1172 ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
1173 ompt_callbacks.ompt_callback(ompt_callback_work)(
1174 ompt_get_work_schedule(pr->schedule), ompt_scope_begin,
1175 &(team_info->parallel_data), &(task_info->task_data), pr->u.p.tc,
1176 OMPT_LOAD_RETURN_ADDRESS(gtid));
1177 }
1178#endif
1179 KMP_PUSH_PARTITIONED_TIMER(OMP_loop_dynamic);
1180}
1181
1182/* For ordered loops, either __kmp_dispatch_finish() should be called after
1183 * every iteration, or __kmp_dispatch_finish_chunk() should be called after
1184 * every chunk of iterations. If the ordered section(s) were not executed
1185 * for this iteration (or every iteration in this chunk), we need to set the
1186 * ordered iteration counters so that the next thread can proceed. */
1187template <typename UT>
1188static void __kmp_dispatch_finish(int gtid, ident_t *loc) {
1189 typedef typename traits_t<UT>::signed_t ST;
1190 __kmp_assert_valid_gtid(gtid);
1191 kmp_info_t *th = __kmp_threads[gtid];
1192
1193 KD_TRACE(100, ("__kmp_dispatch_finish: T#%d called\n", gtid));
1194 if (!th->th.th_team->t.t_serialized) {
1195
1196 dispatch_private_info_template<UT> *pr =
1197 reinterpret_cast<dispatch_private_info_template<UT> *>(
1198 th->th.th_dispatch->th_dispatch_pr_current);
1199 dispatch_shared_info_template<UT> volatile *sh =
1200 reinterpret_cast<dispatch_shared_info_template<UT> volatile *>(
1201 th->th.th_dispatch->th_dispatch_sh_current);
1202 KMP_DEBUG_ASSERT(pr);
1203 KMP_DEBUG_ASSERT(sh);
1204 KMP_DEBUG_ASSERT(th->th.th_dispatch ==
1205 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
1206
1207 if (pr->ordered_bumped) {
1208 KD_TRACE(
1209 1000,
1210 ("__kmp_dispatch_finish: T#%d resetting ordered_bumped to zero\n",
1211 gtid));
1212 pr->ordered_bumped = 0;
1213 } else {
1214 UT lower = pr->u.p.ordered_lower;
1215
1216#ifdef KMP_DEBUG
1217 {
1218 char *buff;
1219 // create format specifiers before the debug output
1220 buff = __kmp_str_format("__kmp_dispatch_finish: T#%%d before wait: "
1221 "ordered_iteration:%%%s lower:%%%s\n",
1222 traits_t<UT>::spec, traits_t<UT>::spec);
1223 KD_TRACE(1000, (buff, gtid, sh->u.s.ordered_iteration, lower));
1224 __kmp_str_free(&buff);
1225 }
1226#endif
1227
1228 __kmp_wait<UT>(&sh->u.s.ordered_iteration, lower,
1229 __kmp_ge<UT> USE_ITT_BUILD_ARG(NULL));
1230 KMP_MB(); /* is this necessary? */
1231#ifdef KMP_DEBUG
1232 {
1233 char *buff;
1234 // create format specifiers before the debug output
1235 buff = __kmp_str_format("__kmp_dispatch_finish: T#%%d after wait: "
1236 "ordered_iteration:%%%s lower:%%%s\n",
1237 traits_t<UT>::spec, traits_t<UT>::spec);
1238 KD_TRACE(1000, (buff, gtid, sh->u.s.ordered_iteration, lower));
1239 __kmp_str_free(&buff);
1240 }
1241#endif
1242
1243 test_then_inc<ST>((volatile ST *)&sh->u.s.ordered_iteration);
1244 } // if
1245 } // if
1246 KD_TRACE(100, ("__kmp_dispatch_finish: T#%d returned\n", gtid));
1247}
1248
1249#ifdef KMP_GOMP_COMPAT
1250
1251template <typename UT>
1252static void __kmp_dispatch_finish_chunk(int gtid, ident_t *loc) {
1253 typedef typename traits_t<UT>::signed_t ST;
1254 __kmp_assert_valid_gtid(gtid);
1255 kmp_info_t *th = __kmp_threads[gtid];
1256
1257 KD_TRACE(100, ("__kmp_dispatch_finish_chunk: T#%d called\n", gtid));
1258 if (!th->th.th_team->t.t_serialized) {
1259 dispatch_private_info_template<UT> *pr =
1260 reinterpret_cast<dispatch_private_info_template<UT> *>(
1261 th->th.th_dispatch->th_dispatch_pr_current);
1262 dispatch_shared_info_template<UT> volatile *sh =
1263 reinterpret_cast<dispatch_shared_info_template<UT> volatile *>(
1264 th->th.th_dispatch->th_dispatch_sh_current);
1265 KMP_DEBUG_ASSERT(pr);
1266 KMP_DEBUG_ASSERT(sh);
1267 KMP_DEBUG_ASSERT(th->th.th_dispatch ==
1268 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
1269
1270 UT lower = pr->u.p.ordered_lower;
1271 UT upper = pr->u.p.ordered_upper;
1272 UT inc = upper - lower + 1;
1273
1274 if (pr->ordered_bumped == inc) {
1275 KD_TRACE(
1276 1000,
1277 ("__kmp_dispatch_finish: T#%d resetting ordered_bumped to zero\n",
1278 gtid));
1279 pr->ordered_bumped = 0;
1280 } else {
1281 inc -= pr->ordered_bumped;
1282
1283#ifdef KMP_DEBUG
1284 {
1285 char *buff;
1286 // create format specifiers before the debug output
1287 buff = __kmp_str_format(
1288 "__kmp_dispatch_finish_chunk: T#%%d before wait: "
1289 "ordered_iteration:%%%s lower:%%%s upper:%%%s\n",
1290 traits_t<UT>::spec, traits_t<UT>::spec, traits_t<UT>::spec);
1291 KD_TRACE(1000, (buff, gtid, sh->u.s.ordered_iteration, lower, upper));
1292 __kmp_str_free(&buff);
1293 }
1294#endif
1295
1296 __kmp_wait<UT>(&sh->u.s.ordered_iteration, lower,
1297 __kmp_ge<UT> USE_ITT_BUILD_ARG(NULL));
1298
1299 KMP_MB(); /* is this necessary? */
1300 KD_TRACE(1000, ("__kmp_dispatch_finish_chunk: T#%d resetting "
1301 "ordered_bumped to zero\n",
1302 gtid));
1303 pr->ordered_bumped = 0;
1305#ifdef KMP_DEBUG
1306 {
1307 char *buff;
1308 // create format specifiers before the debug output
1309 buff = __kmp_str_format(
1310 "__kmp_dispatch_finish_chunk: T#%%d after wait: "
1311 "ordered_iteration:%%%s inc:%%%s lower:%%%s upper:%%%s\n",
1312 traits_t<UT>::spec, traits_t<UT>::spec, traits_t<UT>::spec,
1313 traits_t<UT>::spec);
1314 KD_TRACE(1000,
1315 (buff, gtid, sh->u.s.ordered_iteration, inc, lower, upper));
1316 __kmp_str_free(&buff);
1317 }
1318#endif
1319
1320 test_then_add<ST>((volatile ST *)&sh->u.s.ordered_iteration, inc);
1321 }
1322 // }
1323 }
1324 KD_TRACE(100, ("__kmp_dispatch_finish_chunk: T#%d returned\n", gtid));
1325}
1326
1327#endif /* KMP_GOMP_COMPAT */
1328
1329template <typename T>
1330int __kmp_dispatch_next_algorithm(int gtid,
1331 dispatch_private_info_template<T> *pr,
1332 dispatch_shared_info_template<T> volatile *sh,
1333 kmp_int32 *p_last, T *p_lb, T *p_ub,
1334 typename traits_t<T>::signed_t *p_st, T nproc,
1335 T tid) {
1336 typedef typename traits_t<T>::unsigned_t UT;
1337 typedef typename traits_t<T>::signed_t ST;
1338 typedef typename traits_t<T>::floating_t DBL;
1339 int status = 0;
1340 bool last = false;
1341 T start;
1342 ST incr;
1343 UT limit, trip, init;
1344 kmp_info_t *th = __kmp_threads[gtid];
1345 kmp_team_t *team = th->th.th_team;
1346
1347 KMP_DEBUG_ASSERT(th->th.th_dispatch ==
1348 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
1349 KMP_DEBUG_ASSERT(pr);
1350 KMP_DEBUG_ASSERT(sh);
1351 KMP_DEBUG_ASSERT(tid >= 0 && tid < nproc);
1352#ifdef KMP_DEBUG
1353 {
1354 char *buff;
1355 // create format specifiers before the debug output
1356 buff =
1357 __kmp_str_format("__kmp_dispatch_next_algorithm: T#%%d called pr:%%p "
1358 "sh:%%p nproc:%%%s tid:%%%s\n",
1359 traits_t<T>::spec, traits_t<T>::spec);
1360 KD_TRACE(10, (buff, gtid, pr, sh, nproc, tid));
1361 __kmp_str_free(&buff);
1362 }
1363#endif
1364
1365 // zero trip count
1366 if (pr->u.p.tc == 0) {
1367 KD_TRACE(10,
1368 ("__kmp_dispatch_next_algorithm: T#%d early exit trip count is "
1369 "zero status:%d\n",
1370 gtid, status));
1371 return 0;
1372 }
1373
1374 switch (pr->schedule) {
1375#if KMP_STATIC_STEAL_ENABLED
1376 case kmp_sch_static_steal: {
1377 T chunk = pr->u.p.parm1;
1378 UT nchunks = pr->u.p.parm2;
1379 KD_TRACE(100,
1380 ("__kmp_dispatch_next_algorithm: T#%d kmp_sch_static_steal case\n",
1381 gtid));
1382
1383 trip = pr->u.p.tc - 1;
1384
1385 if (traits_t<T>::type_size > 4) {
1386 // use lock for 8-byte induction variable.
1387 // TODO (optional): check presence and use 16-byte CAS
1388 kmp_lock_t *lck = pr->u.p.steal_lock;
1389 KMP_DEBUG_ASSERT(lck != NULL);
1390 if (pr->u.p.count < (UT)pr->u.p.ub) {
1391 KMP_DEBUG_ASSERT(pr->steal_flag == READY);
1392 __kmp_acquire_lock(lck, gtid);
1393 // try to get own chunk of iterations
1394 init = (pr->u.p.count)++;
1395 status = (init < (UT)pr->u.p.ub);
1396 __kmp_release_lock(lck, gtid);
1397 } else {
1398 status = 0; // no own chunks
1399 }
1400 if (!status) { // try to steal
1401 kmp_lock_t *lckv; // victim buffer's lock
1402 T while_limit = pr->u.p.parm3;
1403 T while_index = 0;
1404 int idx = (th->th.th_dispatch->th_disp_index - 1) %
1405 __kmp_dispatch_num_buffers; // current loop index
1406 // note: victim thread can potentially execute another loop
1407 KMP_ATOMIC_ST_REL(&pr->steal_flag, THIEF); // mark self buffer inactive
1408 while ((!status) && (while_limit != ++while_index)) {
1409 dispatch_private_info_template<T> *v;
1410 T remaining;
1411 T victimId = pr->u.p.parm4;
1412 T oldVictimId = victimId ? victimId - 1 : nproc - 1;
1413 v = reinterpret_cast<dispatch_private_info_template<T> *>(
1414 &team->t.t_dispatch[victimId].th_disp_buffer[idx]);
1415 KMP_DEBUG_ASSERT(v);
1416 while ((v == pr || KMP_ATOMIC_LD_RLX(&v->steal_flag) == THIEF) &&
1417 oldVictimId != victimId) {
1418 victimId = (victimId + 1) % nproc;
1419 v = reinterpret_cast<dispatch_private_info_template<T> *>(
1420 &team->t.t_dispatch[victimId].th_disp_buffer[idx]);
1421 KMP_DEBUG_ASSERT(v);
1422 }
1423 if (v == pr || KMP_ATOMIC_LD_RLX(&v->steal_flag) == THIEF) {
1424 continue; // try once more (nproc attempts in total)
1425 }
1426 if (KMP_ATOMIC_LD_RLX(&v->steal_flag) == UNUSED) {
1427 kmp_uint32 old = UNUSED;
1428 // try to steal whole range from inactive victim
1429 status = v->steal_flag.compare_exchange_strong(old, THIEF);
1430 if (status) {
1431 // initialize self buffer with victim's whole range of chunks
1432 T id = victimId;
1433 T small_chunk = 0, extras = 0, p_extra = 0;
1434 __kmp_initialize_self_buffer<T>(team, id, pr, nchunks, nproc,
1435 init, small_chunk, extras,
1436 p_extra);
1437 __kmp_acquire_lock(lck, gtid);
1438 pr->u.p.count = init + 1; // exclude one we execute immediately
1439 pr->u.p.ub = init + small_chunk + p_extra + (id < extras ? 1 : 0);
1440 __kmp_release_lock(lck, gtid);
1441 pr->u.p.parm4 = (id + 1) % nproc; // remember neighbour tid
1442 // no need to reinitialize other thread invariants: lb, st, etc.
1443#ifdef KMP_DEBUG
1444 {
1445 char *buff;
1446 // create format specifiers before the debug output
1447 buff = __kmp_str_format("__kmp_dispatch_next_algorithm: T#%%d "
1448 "stolen chunks from T#%%d, "
1449 "count:%%%s ub:%%%s\n",
1450 traits_t<UT>::spec, traits_t<T>::spec);
1451 KD_TRACE(10, (buff, gtid, id, pr->u.p.count, pr->u.p.ub));
1452 __kmp_str_free(&buff);
1453 }
1454#endif
1455 // activate non-empty buffer and let others steal from us
1456 if (pr->u.p.count < (UT)pr->u.p.ub)
1457 KMP_ATOMIC_ST_REL(&pr->steal_flag, READY);
1458 break;
1459 }
1460 }
1461 if (KMP_ATOMIC_LD_ACQ(&v->steal_flag) != READY ||
1462 v->u.p.count >= (UT)v->u.p.ub) {
1463 pr->u.p.parm4 = (victimId + 1) % nproc; // shift start victim tid
1464 continue; // no chunks to steal, try next victim
1465 }
1466 lckv = v->u.p.steal_lock;
1467 KMP_ASSERT(lckv != NULL);
1468 __kmp_acquire_lock(lckv, gtid);
1469 limit = v->u.p.ub; // keep initial ub
1470 if (v->u.p.count >= limit) {
1471 __kmp_release_lock(lckv, gtid);
1472 pr->u.p.parm4 = (victimId + 1) % nproc; // shift start victim tid
1473 continue; // no chunks to steal, try next victim
1474 }
1475
1476 // stealing succeded, reduce victim's ub by 1/4 of undone chunks
1477 // TODO: is this heuristics good enough??
1478 remaining = limit - v->u.p.count;
1479 if (remaining > 7) {
1480 // steal 1/4 of remaining
1481 KMP_COUNT_DEVELOPER_VALUE(FOR_static_steal_stolen, remaining >> 2);
1482 init = (v->u.p.ub -= (remaining >> 2));
1483 } else {
1484 // steal 1 chunk of 1..7 remaining
1485 KMP_COUNT_DEVELOPER_VALUE(FOR_static_steal_stolen, 1);
1486 init = (v->u.p.ub -= 1);
1487 }
1488 __kmp_release_lock(lckv, gtid);
1489#ifdef KMP_DEBUG
1490 {
1491 char *buff;
1492 // create format specifiers before the debug output
1493 buff = __kmp_str_format(
1494 "__kmp_dispatch_next: T#%%d stolen chunks from T#%%d, "
1495 "count:%%%s ub:%%%s\n",
1496 traits_t<UT>::spec, traits_t<UT>::spec);
1497 KD_TRACE(10, (buff, gtid, victimId, init, limit));
1498 __kmp_str_free(&buff);
1499 }
1500#endif
1501 KMP_DEBUG_ASSERT(init + 1 <= limit);
1502 pr->u.p.parm4 = victimId; // remember victim to steal from
1503 status = 1;
1504 // now update own count and ub with stolen range excluding init chunk
1505 __kmp_acquire_lock(lck, gtid);
1506 pr->u.p.count = init + 1;
1507 pr->u.p.ub = limit;
1508 __kmp_release_lock(lck, gtid);
1509 // activate non-empty buffer and let others steal from us
1510 if (init + 1 < limit)
1511 KMP_ATOMIC_ST_REL(&pr->steal_flag, READY);
1512 } // while (search for victim)
1513 } // if (try to find victim and steal)
1514 } else {
1515 // 4-byte induction variable, use 8-byte CAS for pair (count, ub)
1516 // as all operations on pair (count, ub) must be done atomically
1517 typedef union {
1518 struct {
1519 UT count;
1520 T ub;
1521 } p;
1522 kmp_int64 b;
1523 } union_i4;
1524 union_i4 vold, vnew;
1525 if (pr->u.p.count < (UT)pr->u.p.ub) {
1526 KMP_DEBUG_ASSERT(pr->steal_flag == READY);
1527 vold.b = *(volatile kmp_int64 *)(&pr->u.p.count);
1528 vnew.b = vold.b;
1529 vnew.p.count++; // get chunk from head of self range
1530 while (!KMP_COMPARE_AND_STORE_REL64(
1531 (volatile kmp_int64 *)&pr->u.p.count,
1532 *VOLATILE_CAST(kmp_int64 *) & vold.b,
1533 *VOLATILE_CAST(kmp_int64 *) & vnew.b)) {
1534 KMP_CPU_PAUSE();
1535 vold.b = *(volatile kmp_int64 *)(&pr->u.p.count);
1536 vnew.b = vold.b;
1537 vnew.p.count++;
1538 }
1539 init = vold.p.count;
1540 status = (init < (UT)vold.p.ub);
1541 } else {
1542 status = 0; // no own chunks
1543 }
1544 if (!status) { // try to steal
1545 T while_limit = pr->u.p.parm3;
1546 T while_index = 0;
1547 int idx = (th->th.th_dispatch->th_disp_index - 1) %
1548 __kmp_dispatch_num_buffers; // current loop index
1549 // note: victim thread can potentially execute another loop
1550 KMP_ATOMIC_ST_REL(&pr->steal_flag, THIEF); // mark self buffer inactive
1551 while ((!status) && (while_limit != ++while_index)) {
1552 dispatch_private_info_template<T> *v;
1553 T remaining;
1554 T victimId = pr->u.p.parm4;
1555 T oldVictimId = victimId ? victimId - 1 : nproc - 1;
1556 v = reinterpret_cast<dispatch_private_info_template<T> *>(
1557 &team->t.t_dispatch[victimId].th_disp_buffer[idx]);
1558 KMP_DEBUG_ASSERT(v);
1559 while ((v == pr || KMP_ATOMIC_LD_RLX(&v->steal_flag) == THIEF) &&
1560 oldVictimId != victimId) {
1561 victimId = (victimId + 1) % nproc;
1562 v = reinterpret_cast<dispatch_private_info_template<T> *>(
1563 &team->t.t_dispatch[victimId].th_disp_buffer[idx]);
1564 KMP_DEBUG_ASSERT(v);
1565 }
1566 if (v == pr || KMP_ATOMIC_LD_RLX(&v->steal_flag) == THIEF) {
1567 continue; // try once more (nproc attempts in total)
1568 }
1569 if (KMP_ATOMIC_LD_RLX(&v->steal_flag) == UNUSED) {
1570 kmp_uint32 old = UNUSED;
1571 // try to steal whole range from inactive victim
1572 status = v->steal_flag.compare_exchange_strong(old, THIEF);
1573 if (status) {
1574 // initialize self buffer with victim's whole range of chunks
1575 T id = victimId;
1576 T small_chunk = 0, extras = 0, p_extra = 0;
1577 __kmp_initialize_self_buffer<T>(team, id, pr, nchunks, nproc,
1578 init, small_chunk, extras,
1579 p_extra);
1580 vnew.p.count = init + 1;
1581 vnew.p.ub = init + small_chunk + p_extra + (id < extras ? 1 : 0);
1582 // write pair (count, ub) at once atomically
1583#if KMP_ARCH_X86
1584 KMP_XCHG_FIXED64((volatile kmp_int64 *)(&pr->u.p.count), vnew.b);
1585#else
1586 *(volatile kmp_int64 *)(&pr->u.p.count) = vnew.b;
1587#endif
1588 pr->u.p.parm4 = (id + 1) % nproc; // remember neighbour tid
1589 // no need to initialize other thread invariants: lb, st, etc.
1590#ifdef KMP_DEBUG
1591 {
1592 char *buff;
1593 // create format specifiers before the debug output
1594 buff = __kmp_str_format("__kmp_dispatch_next_algorithm: T#%%d "
1595 "stolen chunks from T#%%d, "
1596 "count:%%%s ub:%%%s\n",
1597 traits_t<UT>::spec, traits_t<T>::spec);
1598 KD_TRACE(10, (buff, gtid, id, pr->u.p.count, pr->u.p.ub));
1599 __kmp_str_free(&buff);
1600 }
1601#endif
1602 // activate non-empty buffer and let others steal from us
1603 if (pr->u.p.count < (UT)pr->u.p.ub)
1604 KMP_ATOMIC_ST_REL(&pr->steal_flag, READY);
1605 break;
1606 }
1607 }
1608 while (1) { // CAS loop with check if victim still has enough chunks
1609 // many threads may be stealing concurrently from same victim
1610 vold.b = *(volatile kmp_int64 *)(&v->u.p.count);
1611 if (KMP_ATOMIC_LD_ACQ(&v->steal_flag) != READY ||
1612 vold.p.count >= (UT)vold.p.ub) {
1613 pr->u.p.parm4 = (victimId + 1) % nproc; // shift start victim id
1614 break; // no chunks to steal, try next victim
1615 }
1616 vnew.b = vold.b;
1617 remaining = vold.p.ub - vold.p.count;
1618 // try to steal 1/4 of remaining
1619 // TODO: is this heuristics good enough??
1620 if (remaining > 7) {
1621 vnew.p.ub -= remaining >> 2; // steal from tail of victim's range
1622 } else {
1623 vnew.p.ub -= 1; // steal 1 chunk of 1..7 remaining
1624 }
1625 KMP_DEBUG_ASSERT(vnew.p.ub * (UT)chunk <= trip);
1626 if (KMP_COMPARE_AND_STORE_REL64(
1627 (volatile kmp_int64 *)&v->u.p.count,
1628 *VOLATILE_CAST(kmp_int64 *) & vold.b,
1629 *VOLATILE_CAST(kmp_int64 *) & vnew.b)) {
1630 // stealing succedded
1631#ifdef KMP_DEBUG
1632 {
1633 char *buff;
1634 // create format specifiers before the debug output
1635 buff = __kmp_str_format(
1636 "__kmp_dispatch_next: T#%%d stolen chunks from T#%%d, "
1637 "count:%%%s ub:%%%s\n",
1638 traits_t<T>::spec, traits_t<T>::spec);
1639 KD_TRACE(10, (buff, gtid, victimId, vnew.p.ub, vold.p.ub));
1640 __kmp_str_free(&buff);
1641 }
1642#endif
1643 KMP_COUNT_DEVELOPER_VALUE(FOR_static_steal_stolen,
1644 vold.p.ub - vnew.p.ub);
1645 status = 1;
1646 pr->u.p.parm4 = victimId; // keep victim id
1647 // now update own count and ub
1648 init = vnew.p.ub;
1649 vold.p.count = init + 1;
1650#if KMP_ARCH_X86
1651 KMP_XCHG_FIXED64((volatile kmp_int64 *)(&pr->u.p.count), vold.b);
1652#else
1653 *(volatile kmp_int64 *)(&pr->u.p.count) = vold.b;
1654#endif
1655 // activate non-empty buffer and let others steal from us
1656 if (vold.p.count < (UT)vold.p.ub)
1657 KMP_ATOMIC_ST_REL(&pr->steal_flag, READY);
1658 break;
1659 } // if (check CAS result)
1660 KMP_CPU_PAUSE(); // CAS failed, repeatedly attempt
1661 } // while (try to steal from particular victim)
1662 } // while (search for victim)
1663 } // if (try to find victim and steal)
1664 } // if (4-byte induction variable)
1665 if (!status) {
1666 *p_lb = 0;
1667 *p_ub = 0;
1668 if (p_st != NULL)
1669 *p_st = 0;
1670 } else {
1671 start = pr->u.p.lb;
1672 init *= chunk;
1673 limit = chunk + init - 1;
1674 incr = pr->u.p.st;
1675 KMP_COUNT_DEVELOPER_VALUE(FOR_static_steal_chunks, 1);
1676
1677 KMP_DEBUG_ASSERT(init <= trip);
1678 // keep track of done chunks for possible early exit from stealing
1679 // TODO: count executed chunks locally with rare update of shared location
1680 // test_then_inc<ST>((volatile ST *)&sh->u.s.iteration);
1681 if ((last = (limit >= trip)) != 0)
1682 limit = trip;
1683 if (p_st != NULL)
1684 *p_st = incr;
1685
1686 if (incr == 1) {
1687 *p_lb = start + init;
1688 *p_ub = start + limit;
1689 } else {
1690 *p_lb = start + init * incr;
1691 *p_ub = start + limit * incr;
1692 }
1693 } // if
1694 break;
1695 } // case
1696#endif // KMP_STATIC_STEAL_ENABLED
1697 case kmp_sch_static_balanced: {
1698 KD_TRACE(
1699 10,
1700 ("__kmp_dispatch_next_algorithm: T#%d kmp_sch_static_balanced case\n",
1701 gtid));
1702 /* check if thread has any iteration to do */
1703 if ((status = !pr->u.p.count) != 0) {
1704 pr->u.p.count = 1;
1705 *p_lb = pr->u.p.lb;
1706 *p_ub = pr->u.p.ub;
1707 last = (pr->u.p.parm1 != 0);
1708 if (p_st != NULL)
1709 *p_st = pr->u.p.st;
1710 } else { /* no iterations to do */
1711 pr->u.p.lb = pr->u.p.ub + pr->u.p.st;
1712 }
1713 } // case
1714 break;
1715 case kmp_sch_static_greedy: /* original code for kmp_sch_static_greedy was
1716 merged here */
1717 case kmp_sch_static_chunked: {
1718 T parm1;
1719
1720 KD_TRACE(100, ("__kmp_dispatch_next_algorithm: T#%d "
1721 "kmp_sch_static_[affinity|chunked] case\n",
1722 gtid));
1723 parm1 = pr->u.p.parm1;
1724
1725 trip = pr->u.p.tc - 1;
1726 init = parm1 * (pr->u.p.count + tid);
1727
1728 if ((status = (init <= trip)) != 0) {
1729 start = pr->u.p.lb;
1730 incr = pr->u.p.st;
1731 limit = parm1 + init - 1;
1732
1733 if ((last = (limit >= trip)) != 0)
1734 limit = trip;
1735
1736 if (p_st != NULL)
1737 *p_st = incr;
1738
1739 pr->u.p.count += nproc;
1740
1741 if (incr == 1) {
1742 *p_lb = start + init;
1743 *p_ub = start + limit;
1744 } else {
1745 *p_lb = start + init * incr;
1746 *p_ub = start + limit * incr;
1747 }
1748
1749 if (pr->flags.ordered) {
1750 pr->u.p.ordered_lower = init;
1751 pr->u.p.ordered_upper = limit;
1752 } // if
1753 } // if
1754 } // case
1755 break;
1756
1757 case kmp_sch_dynamic_chunked: {
1758 UT chunk_number;
1759 UT chunk_size = pr->u.p.parm1;
1760 UT nchunks = pr->u.p.parm2;
1761
1762 KD_TRACE(
1763 100,
1764 ("__kmp_dispatch_next_algorithm: T#%d kmp_sch_dynamic_chunked case\n",
1765 gtid));
1766
1767 chunk_number = test_then_inc_acq<ST>((volatile ST *)&sh->u.s.iteration);
1768 status = (chunk_number < nchunks);
1769 if (!status) {
1770 *p_lb = 0;
1771 *p_ub = 0;
1772 if (p_st != NULL)
1773 *p_st = 0;
1774 } else {
1775 init = chunk_size * chunk_number;
1776 trip = pr->u.p.tc - 1;
1777 start = pr->u.p.lb;
1778 incr = pr->u.p.st;
1779
1780 if ((last = (trip - init < (UT)chunk_size)))
1781 limit = trip;
1782 else
1783 limit = chunk_size + init - 1;
1784
1785 if (p_st != NULL)
1786 *p_st = incr;
1787
1788 if (incr == 1) {
1789 *p_lb = start + init;
1790 *p_ub = start + limit;
1791 } else {
1792 *p_lb = start + init * incr;
1793 *p_ub = start + limit * incr;
1794 }
1795
1796 if (pr->flags.ordered) {
1797 pr->u.p.ordered_lower = init;
1798 pr->u.p.ordered_upper = limit;
1799 } // if
1800 } // if
1801 } // case
1802 break;
1803
1804 case kmp_sch_guided_iterative_chunked: {
1805 T chunkspec = pr->u.p.parm1;
1806 KD_TRACE(100, ("__kmp_dispatch_next_algorithm: T#%d kmp_sch_guided_chunked "
1807 "iterative case\n",
1808 gtid));
1809 trip = pr->u.p.tc;
1810 // Start atomic part of calculations
1811 while (1) {
1812 ST remaining; // signed, because can be < 0
1813 init = sh->u.s.iteration; // shared value
1814 remaining = trip - init;
1815 if (remaining <= 0) { // AC: need to compare with 0 first
1816 // nothing to do, don't try atomic op
1817 status = 0;
1818 break;
1819 }
1820 if ((T)remaining <
1821 pr->u.p.parm2) { // compare with K*nproc*(chunk+1), K=2 by default
1822 // use dynamic-style schedule
1823 // atomically increment iterations, get old value
1824 init = test_then_add<ST>(RCAST(volatile ST *, &sh->u.s.iteration),
1825 (ST)chunkspec);
1826 remaining = trip - init;
1827 if (remaining <= 0) {
1828 status = 0; // all iterations got by other threads
1829 } else {
1830 // got some iterations to work on
1831 status = 1;
1832 if ((T)remaining > chunkspec) {
1833 limit = init + chunkspec - 1;
1834 } else {
1835 last = true; // the last chunk
1836 limit = init + remaining - 1;
1837 } // if
1838 } // if
1839 break;
1840 } // if
1841 limit = init + (UT)((double)remaining *
1842 *(double *)&pr->u.p.parm3); // divide by K*nproc
1843 if (compare_and_swap<ST>(RCAST(volatile ST *, &sh->u.s.iteration),
1844 (ST)init, (ST)limit)) {
1845 // CAS was successful, chunk obtained
1846 status = 1;
1847 --limit;
1848 break;
1849 } // if
1850 } // while
1851 if (status != 0) {
1852 start = pr->u.p.lb;
1853 incr = pr->u.p.st;
1854 if (p_st != NULL)
1855 *p_st = incr;
1856 *p_lb = start + init * incr;
1857 *p_ub = start + limit * incr;
1858 if (pr->flags.ordered) {
1859 pr->u.p.ordered_lower = init;
1860 pr->u.p.ordered_upper = limit;
1861 } // if
1862 } else {
1863 *p_lb = 0;
1864 *p_ub = 0;
1865 if (p_st != NULL)
1866 *p_st = 0;
1867 } // if
1868 } // case
1869 break;
1870
1871 case kmp_sch_guided_simd: {
1872 // same as iterative but curr-chunk adjusted to be multiple of given
1873 // chunk
1874 T chunk = pr->u.p.parm1;
1875 KD_TRACE(100,
1876 ("__kmp_dispatch_next_algorithm: T#%d kmp_sch_guided_simd case\n",
1877 gtid));
1878 trip = pr->u.p.tc;
1879 // Start atomic part of calculations
1880 while (1) {
1881 ST remaining; // signed, because can be < 0
1882 init = sh->u.s.iteration; // shared value
1883 remaining = trip - init;
1884 if (remaining <= 0) { // AC: need to compare with 0 first
1885 status = 0; // nothing to do, don't try atomic op
1886 break;
1887 }
1888 KMP_DEBUG_ASSERT(chunk && init % chunk == 0);
1889 // compare with K*nproc*(chunk+1), K=2 by default
1890 if ((T)remaining < pr->u.p.parm2) {
1891 // use dynamic-style schedule
1892 // atomically increment iterations, get old value
1893 init = test_then_add<ST>(RCAST(volatile ST *, &sh->u.s.iteration),
1894 (ST)chunk);
1895 remaining = trip - init;
1896 if (remaining <= 0) {
1897 status = 0; // all iterations got by other threads
1898 } else {
1899 // got some iterations to work on
1900 status = 1;
1901 if ((T)remaining > chunk) {
1902 limit = init + chunk - 1;
1903 } else {
1904 last = true; // the last chunk
1905 limit = init + remaining - 1;
1906 } // if
1907 } // if
1908 break;
1909 } // if
1910 // divide by K*nproc
1911 UT span;
1912 __kmp_type_convert((double)remaining * (*(double *)&pr->u.p.parm3),
1913 &span);
1914 UT rem = span % chunk;
1915 if (rem) // adjust so that span%chunk == 0
1916 span += chunk - rem;
1917 limit = init + span;
1918 if (compare_and_swap<ST>(RCAST(volatile ST *, &sh->u.s.iteration),
1919 (ST)init, (ST)limit)) {
1920 // CAS was successful, chunk obtained
1921 status = 1;
1922 --limit;
1923 break;
1924 } // if
1925 } // while
1926 if (status != 0) {
1927 start = pr->u.p.lb;
1928 incr = pr->u.p.st;
1929 if (p_st != NULL)
1930 *p_st = incr;
1931 *p_lb = start + init * incr;
1932 *p_ub = start + limit * incr;
1933 if (pr->flags.ordered) {
1934 pr->u.p.ordered_lower = init;
1935 pr->u.p.ordered_upper = limit;
1936 } // if
1937 } else {
1938 *p_lb = 0;
1939 *p_ub = 0;
1940 if (p_st != NULL)
1941 *p_st = 0;
1942 } // if
1943 } // case
1944 break;
1945
1946 case kmp_sch_guided_analytical_chunked: {
1947 T chunkspec = pr->u.p.parm1;
1948 UT chunkIdx;
1949#if KMP_USE_X87CONTROL
1950 /* for storing original FPCW value for Windows* OS on
1951 IA-32 architecture 8-byte version */
1952 unsigned int oldFpcw;
1953 unsigned int fpcwSet = 0;
1954#endif
1955 KD_TRACE(100, ("__kmp_dispatch_next_algorithm: T#%d "
1956 "kmp_sch_guided_analytical_chunked case\n",
1957 gtid));
1958
1959 trip = pr->u.p.tc;
1960
1961 KMP_DEBUG_ASSERT(nproc > 1);
1962 KMP_DEBUG_ASSERT((2UL * chunkspec + 1) * (UT)nproc < trip);
1963
1964 while (1) { /* this while loop is a safeguard against unexpected zero
1965 chunk sizes */
1966 chunkIdx = test_then_inc_acq<ST>((volatile ST *)&sh->u.s.iteration);
1967 if (chunkIdx >= (UT)pr->u.p.parm2) {
1968 --trip;
1969 /* use dynamic-style scheduling */
1970 init = chunkIdx * chunkspec + pr->u.p.count;
1971 /* need to verify init > 0 in case of overflow in the above
1972 * calculation */
1973 if ((status = (init > 0 && init <= trip)) != 0) {
1974 limit = init + chunkspec - 1;
1975
1976 if ((last = (limit >= trip)) != 0)
1977 limit = trip;
1978 }
1979 break;
1980 } else {
1981/* use exponential-style scheduling */
1982/* The following check is to workaround the lack of long double precision on
1983 Windows* OS.
1984 This check works around the possible effect that init != 0 for chunkIdx == 0.
1985 */
1986#if KMP_USE_X87CONTROL
1987 /* If we haven't already done so, save original
1988 FPCW and set precision to 64-bit, as Windows* OS
1989 on IA-32 architecture defaults to 53-bit */
1990 if (!fpcwSet) {
1991 oldFpcw = _control87(0, 0);
1992 _control87(_PC_64, _MCW_PC);
1993 fpcwSet = 0x30000;
1994 }
1995#endif
1996 if (chunkIdx) {
1997 init = __kmp_dispatch_guided_remaining<T>(
1998 trip, *(DBL *)&pr->u.p.parm3, chunkIdx);
1999 KMP_DEBUG_ASSERT(init);
2000 init = trip - init;
2001 } else
2002 init = 0;
2003 limit = trip - __kmp_dispatch_guided_remaining<T>(
2004 trip, *(DBL *)&pr->u.p.parm3, chunkIdx + 1);
2005 KMP_ASSERT(init <= limit);
2006 if (init < limit) {
2007 KMP_DEBUG_ASSERT(limit <= trip);
2008 --limit;
2009 status = 1;
2010 break;
2011 } // if
2012 } // if
2013 } // while (1)
2014#if KMP_USE_X87CONTROL
2015 /* restore FPCW if necessary
2016 AC: check fpcwSet flag first because oldFpcw can be uninitialized here
2017 */
2018 if (fpcwSet && (oldFpcw & fpcwSet))
2019 _control87(oldFpcw, _MCW_PC);
2020#endif
2021 if (status != 0) {
2022 start = pr->u.p.lb;
2023 incr = pr->u.p.st;
2024 if (p_st != NULL)
2025 *p_st = incr;
2026 *p_lb = start + init * incr;
2027 *p_ub = start + limit * incr;
2028 if (pr->flags.ordered) {
2029 pr->u.p.ordered_lower = init;
2030 pr->u.p.ordered_upper = limit;
2031 }
2032 } else {
2033 *p_lb = 0;
2034 *p_ub = 0;
2035 if (p_st != NULL)
2036 *p_st = 0;
2037 }
2038 } // case
2039 break;
2040
2041 case kmp_sch_trapezoidal: {
2042 UT index;
2043 T parm2 = pr->u.p.parm2;
2044 T parm3 = pr->u.p.parm3;
2045 T parm4 = pr->u.p.parm4;
2046 KD_TRACE(100,
2047 ("__kmp_dispatch_next_algorithm: T#%d kmp_sch_trapezoidal case\n",
2048 gtid));
2049
2050 index = test_then_inc<ST>((volatile ST *)&sh->u.s.iteration);
2051
2052 init = (index * ((2 * parm2) - (index - 1) * parm4)) / 2;
2053 trip = pr->u.p.tc - 1;
2054
2055 if ((status = ((T)index < parm3 && init <= trip)) == 0) {
2056 *p_lb = 0;
2057 *p_ub = 0;
2058 if (p_st != NULL)
2059 *p_st = 0;
2060 } else {
2061 start = pr->u.p.lb;
2062 limit = ((index + 1) * (2 * parm2 - index * parm4)) / 2 - 1;
2063 incr = pr->u.p.st;
2064
2065 if ((last = (limit >= trip)) != 0)
2066 limit = trip;
2067
2068 if (p_st != NULL)
2069 *p_st = incr;
2070
2071 if (incr == 1) {
2072 *p_lb = start + init;
2073 *p_ub = start + limit;
2074 } else {
2075 *p_lb = start + init * incr;
2076 *p_ub = start + limit * incr;
2077 }
2078
2079 if (pr->flags.ordered) {
2080 pr->u.p.ordered_lower = init;
2081 pr->u.p.ordered_upper = limit;
2082 } // if
2083 } // if
2084 } // case
2085 break;
2086 default: {
2087 status = 0; // to avoid complaints on uninitialized variable use
2088 __kmp_fatal(KMP_MSG(UnknownSchedTypeDetected), // Primary message
2089 KMP_HNT(GetNewerLibrary), // Hint
2090 __kmp_msg_null // Variadic argument list terminator
2091 );
2092 } break;
2093 } // switch
2094 if (p_last)
2095 *p_last = last;
2096#ifdef KMP_DEBUG
2097 if (pr->flags.ordered) {
2098 char *buff;
2099 // create format specifiers before the debug output
2100 buff = __kmp_str_format("__kmp_dispatch_next_algorithm: T#%%d "
2101 "ordered_lower:%%%s ordered_upper:%%%s\n",
2102 traits_t<UT>::spec, traits_t<UT>::spec);
2103 KD_TRACE(1000, (buff, gtid, pr->u.p.ordered_lower, pr->u.p.ordered_upper));
2104 __kmp_str_free(&buff);
2105 }
2106 {
2107 char *buff;
2108 // create format specifiers before the debug output
2109 buff = __kmp_str_format(
2110 "__kmp_dispatch_next_algorithm: T#%%d exit status:%%d p_last:%%d "
2111 "p_lb:%%%s p_ub:%%%s p_st:%%%s\n",
2112 traits_t<T>::spec, traits_t<T>::spec, traits_t<ST>::spec);
2113 KMP_DEBUG_ASSERT(p_last);
2114 KMP_DEBUG_ASSERT(p_st);
2115 KD_TRACE(10, (buff, gtid, status, *p_last, *p_lb, *p_ub, *p_st));
2116 __kmp_str_free(&buff);
2117 }
2118#endif
2119 return status;
2120}
2121
2122/* Define a macro for exiting __kmp_dispatch_next(). If status is 0 (no more
2123 work), then tell OMPT the loop is over. In some cases kmp_dispatch_fini()
2124 is not called. */
2125#if OMPT_SUPPORT && OMPT_OPTIONAL
2126#define OMPT_LOOP_END \
2127 if (status == 0) { \
2128 if (ompt_enabled.ompt_callback_work) { \
2129 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL); \
2130 ompt_task_info_t *task_info = __ompt_get_task_info_object(0); \
2131 ompt_callbacks.ompt_callback(ompt_callback_work)( \
2132 ompt_get_work_schedule(pr->schedule), ompt_scope_end, \
2133 &(team_info->parallel_data), &(task_info->task_data), 0, codeptr); \
2134 } \
2135 }
2136#define OMPT_LOOP_DISPATCH(lb, ub, st, status) \
2137 if (ompt_enabled.ompt_callback_dispatch && status) { \
2138 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL); \
2139 ompt_task_info_t *task_info = __ompt_get_task_info_object(0); \
2140 ompt_dispatch_chunk_t chunk; \
2141 ompt_data_t instance = ompt_data_none; \
2142 OMPT_GET_DISPATCH_CHUNK(chunk, lb, ub, st); \
2143 instance.ptr = &chunk; \
2144 ompt_callbacks.ompt_callback(ompt_callback_dispatch)( \
2145 &(team_info->parallel_data), &(task_info->task_data), \
2146 ompt_dispatch_ws_loop_chunk, instance); \
2147 }
2148// TODO: implement count
2149#else
2150#define OMPT_LOOP_END // no-op
2151#define OMPT_LOOP_DISPATCH(lb, ub, st, status) // no-op
2152#endif
2153
2154#if KMP_STATS_ENABLED
2155#define KMP_STATS_LOOP_END \
2156 { \
2157 kmp_int64 u, l, t, i; \
2158 l = (kmp_int64)(*p_lb); \
2159 u = (kmp_int64)(*p_ub); \
2160 i = (kmp_int64)(pr->u.p.st); \
2161 if (status == 0) { \
2162 t = 0; \
2163 KMP_POP_PARTITIONED_TIMER(); \
2164 } else if (i == 1) { \
2165 if (u >= l) \
2166 t = u - l + 1; \
2167 else \
2168 t = 0; \
2169 } else if (i < 0) { \
2170 if (l >= u) \
2171 t = (l - u) / (-i) + 1; \
2172 else \
2173 t = 0; \
2174 } else { \
2175 if (u >= l) \
2176 t = (u - l) / i + 1; \
2177 else \
2178 t = 0; \
2179 } \
2180 KMP_COUNT_VALUE(OMP_loop_dynamic_iterations, t); \
2181 }
2182#else
2183#define KMP_STATS_LOOP_END /* Nothing */
2184#endif
2185
2186template <typename T>
2187static int __kmp_dispatch_next(ident_t *loc, int gtid, kmp_int32 *p_last,
2188 T *p_lb, T *p_ub,
2189 typename traits_t<T>::signed_t *p_st
2190#if OMPT_SUPPORT && OMPT_OPTIONAL
2191 ,
2192 void *codeptr
2193#endif
2194) {
2195
2196 typedef typename traits_t<T>::unsigned_t UT;
2197 typedef typename traits_t<T>::signed_t ST;
2198 // This is potentially slightly misleading, schedule(runtime) will appear here
2199 // even if the actual runtime schedule is static. (Which points out a
2200 // disadvantage of schedule(runtime): even when static scheduling is used it
2201 // costs more than a compile time choice to use static scheduling would.)
2202 KMP_TIME_PARTITIONED_BLOCK(OMP_loop_dynamic_scheduling);
2203
2204 int status;
2205 dispatch_private_info_template<T> *pr;
2206 __kmp_assert_valid_gtid(gtid);
2207 kmp_info_t *th = __kmp_threads[gtid];
2208 kmp_team_t *team = th->th.th_team;
2209
2210 KMP_DEBUG_ASSERT(p_lb && p_ub && p_st); // AC: these cannot be NULL
2211 KD_TRACE(
2212 1000,
2213 ("__kmp_dispatch_next: T#%d called p_lb:%p p_ub:%p p_st:%p p_last: %p\n",
2214 gtid, p_lb, p_ub, p_st, p_last));
2215
2216 if (team->t.t_serialized) {
2217 /* NOTE: serialize this dispatch because we are not at the active level */
2218 pr = reinterpret_cast<dispatch_private_info_template<T> *>(
2219 th->th.th_dispatch->th_disp_buffer); /* top of the stack */
2220 KMP_DEBUG_ASSERT(pr);
2221
2222 if ((status = (pr->u.p.tc != 0)) == 0) {
2223 *p_lb = 0;
2224 *p_ub = 0;
2225 // if ( p_last != NULL )
2226 // *p_last = 0;
2227 if (p_st != NULL)
2228 *p_st = 0;
2229 if (__kmp_env_consistency_check) {
2230 if (pr->pushed_ws != ct_none) {
2231 pr->pushed_ws = __kmp_pop_workshare(gtid, pr->pushed_ws, loc);
2232 }
2233 }
2234 } else if (pr->flags.nomerge) {
2235 kmp_int32 last;
2236 T start;
2237 UT limit, trip, init;
2238 ST incr;
2239 T chunk = pr->u.p.parm1;
2240
2241 KD_TRACE(100, ("__kmp_dispatch_next: T#%d kmp_sch_dynamic_chunked case\n",
2242 gtid));
2243
2244 init = chunk * pr->u.p.count++;
2245 trip = pr->u.p.tc - 1;
2246
2247 if ((status = (init <= trip)) == 0) {
2248 *p_lb = 0;
2249 *p_ub = 0;
2250 // if ( p_last != NULL )
2251 // *p_last = 0;
2252 if (p_st != NULL)
2253 *p_st = 0;
2254 if (__kmp_env_consistency_check) {
2255 if (pr->pushed_ws != ct_none) {
2256 pr->pushed_ws = __kmp_pop_workshare(gtid, pr->pushed_ws, loc);
2257 }
2258 }
2259 } else {
2260 start = pr->u.p.lb;
2261 limit = chunk + init - 1;
2262 incr = pr->u.p.st;
2263
2264 if ((last = (limit >= trip)) != 0) {
2265 limit = trip;
2266#if KMP_OS_WINDOWS
2267 pr->u.p.last_upper = pr->u.p.ub;
2268#endif /* KMP_OS_WINDOWS */
2269 }
2270 if (p_last != NULL)
2271 *p_last = last;
2272 if (p_st != NULL)
2273 *p_st = incr;
2274 if (incr == 1) {
2275 *p_lb = start + init;
2276 *p_ub = start + limit;
2277 } else {
2278 *p_lb = start + init * incr;
2279 *p_ub = start + limit * incr;
2280 }
2281
2282 if (pr->flags.ordered) {
2283 pr->u.p.ordered_lower = init;
2284 pr->u.p.ordered_upper = limit;
2285#ifdef KMP_DEBUG
2286 {
2287 char *buff;
2288 // create format specifiers before the debug output
2289 buff = __kmp_str_format("__kmp_dispatch_next: T#%%d "
2290 "ordered_lower:%%%s ordered_upper:%%%s\n",
2291 traits_t<UT>::spec, traits_t<UT>::spec);
2292 KD_TRACE(1000, (buff, gtid, pr->u.p.ordered_lower,
2293 pr->u.p.ordered_upper));
2294 __kmp_str_free(&buff);
2295 }
2296#endif
2297 } // if
2298 } // if
2299 } else {
2300 pr->u.p.tc = 0;
2301 *p_lb = pr->u.p.lb;
2302 *p_ub = pr->u.p.ub;
2303#if KMP_OS_WINDOWS
2304 pr->u.p.last_upper = *p_ub;
2305#endif /* KMP_OS_WINDOWS */
2306 if (p_last != NULL)
2307 *p_last = TRUE;
2308 if (p_st != NULL)
2309 *p_st = pr->u.p.st;
2310 } // if
2311#ifdef KMP_DEBUG
2312 {
2313 char *buff;
2314 // create format specifiers before the debug output
2315 buff = __kmp_str_format(
2316 "__kmp_dispatch_next: T#%%d serialized case: p_lb:%%%s "
2317 "p_ub:%%%s p_st:%%%s p_last:%%p %%d returning:%%d\n",
2318 traits_t<T>::spec, traits_t<T>::spec, traits_t<ST>::spec);
2319 KD_TRACE(10, (buff, gtid, *p_lb, *p_ub, *p_st, p_last,
2320 (p_last ? *p_last : 0), status));
2321 __kmp_str_free(&buff);
2322 }
2323#endif
2324#if INCLUDE_SSC_MARKS
2325 SSC_MARK_DISPATCH_NEXT();
2326#endif
2327 OMPT_LOOP_DISPATCH(*p_lb, *p_ub, pr->u.p.st, status);
2328 OMPT_LOOP_END;
2329 KMP_STATS_LOOP_END;
2330 return status;
2331 } else {
2332 kmp_int32 last = 0;
2333 dispatch_shared_info_template<T> volatile *sh;
2334
2335 KMP_DEBUG_ASSERT(th->th.th_dispatch ==
2336 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
2337
2338 pr = reinterpret_cast<dispatch_private_info_template<T> *>(
2339 th->th.th_dispatch->th_dispatch_pr_current);
2340 KMP_DEBUG_ASSERT(pr);
2341 sh = reinterpret_cast<dispatch_shared_info_template<T> volatile *>(
2342 th->th.th_dispatch->th_dispatch_sh_current);
2343 KMP_DEBUG_ASSERT(sh);
2344
2345#if KMP_USE_HIER_SCHED
2346 if (pr->flags.use_hier)
2347 status = sh->hier->next(loc, gtid, pr, &last, p_lb, p_ub, p_st);
2348 else
2349#endif // KMP_USE_HIER_SCHED
2350 status = __kmp_dispatch_next_algorithm<T>(gtid, pr, sh, &last, p_lb, p_ub,
2351 p_st, th->th.th_team_nproc,
2352 th->th.th_info.ds.ds_tid);
2353 // status == 0: no more iterations to execute
2354 if (status == 0) {
2355 ST num_done;
2356 num_done = test_then_inc<ST>(&sh->u.s.num_done);
2357#ifdef KMP_DEBUG
2358 {
2359 char *buff;
2360 // create format specifiers before the debug output
2361 buff = __kmp_str_format(
2362 "__kmp_dispatch_next: T#%%d increment num_done:%%%s\n",
2363 traits_t<ST>::spec);
2364 KD_TRACE(10, (buff, gtid, sh->u.s.num_done));
2365 __kmp_str_free(&buff);
2366 }
2367#endif
2368
2369#if KMP_USE_HIER_SCHED
2370 pr->flags.use_hier = FALSE;
2371#endif
2372 if (num_done == th->th.th_team_nproc - 1) {
2373#if KMP_STATIC_STEAL_ENABLED
2374 if (pr->schedule == kmp_sch_static_steal) {
2375 int i;
2376 int idx = (th->th.th_dispatch->th_disp_index - 1) %
2377 __kmp_dispatch_num_buffers; // current loop index
2378 // loop complete, safe to destroy locks used for stealing
2379 for (i = 0; i < th->th.th_team_nproc; ++i) {
2380 dispatch_private_info_template<T> *buf =
2381 reinterpret_cast<dispatch_private_info_template<T> *>(
2382 &team->t.t_dispatch[i].th_disp_buffer[idx]);
2383 KMP_ASSERT(buf->steal_flag == THIEF); // buffer must be inactive
2384 KMP_ATOMIC_ST_RLX(&buf->steal_flag, UNUSED);
2385 if (traits_t<T>::type_size > 4) {
2386 // destroy locks used for stealing
2387 kmp_lock_t *lck = buf->u.p.steal_lock;
2388 KMP_ASSERT(lck != NULL);
2389 __kmp_destroy_lock(lck);
2390 __kmp_free(lck);
2391 buf->u.p.steal_lock = NULL;
2392 }
2393 }
2394 }
2395#endif
2396 /* NOTE: release shared buffer to be reused */
2397
2398 KMP_MB(); /* Flush all pending memory write invalidates. */
2399
2400 sh->u.s.num_done = 0;
2401 sh->u.s.iteration = 0;
2402
2403 /* TODO replace with general release procedure? */
2404 if (pr->flags.ordered) {
2405 sh->u.s.ordered_iteration = 0;
2406 }
2407
2408 KMP_MB(); /* Flush all pending memory write invalidates. */
2409
2410 sh->buffer_index += __kmp_dispatch_num_buffers;
2411 KD_TRACE(100, ("__kmp_dispatch_next: T#%d change buffer_index:%d\n",
2412 gtid, sh->buffer_index));
2413
2414 KMP_MB(); /* Flush all pending memory write invalidates. */
2415
2416 } // if
2417 if (__kmp_env_consistency_check) {
2418 if (pr->pushed_ws != ct_none) {
2419 pr->pushed_ws = __kmp_pop_workshare(gtid, pr->pushed_ws, loc);
2420 }
2421 }
2422
2423 th->th.th_dispatch->th_deo_fcn = NULL;
2424 th->th.th_dispatch->th_dxo_fcn = NULL;
2425 th->th.th_dispatch->th_dispatch_sh_current = NULL;
2426 th->th.th_dispatch->th_dispatch_pr_current = NULL;
2427 } // if (status == 0)
2428#if KMP_OS_WINDOWS
2429 else if (last) {
2430 pr->u.p.last_upper = pr->u.p.ub;
2431 }
2432#endif /* KMP_OS_WINDOWS */
2433 if (p_last != NULL && status != 0)
2434 *p_last = last;
2435 } // if
2436
2437#ifdef KMP_DEBUG
2438 {
2439 char *buff;
2440 // create format specifiers before the debug output
2441 buff = __kmp_str_format(
2442 "__kmp_dispatch_next: T#%%d normal case: "
2443 "p_lb:%%%s p_ub:%%%s p_st:%%%s p_last:%%p (%%d) returning:%%d\n",
2444 traits_t<T>::spec, traits_t<T>::spec, traits_t<ST>::spec);
2445 KD_TRACE(10, (buff, gtid, *p_lb, *p_ub, p_st ? *p_st : 0, p_last,
2446 (p_last ? *p_last : 0), status));
2447 __kmp_str_free(&buff);
2448 }
2449#endif
2450#if INCLUDE_SSC_MARKS
2451 SSC_MARK_DISPATCH_NEXT();
2452#endif
2453 OMPT_LOOP_DISPATCH(*p_lb, *p_ub, pr->u.p.st, status);
2454 OMPT_LOOP_END;
2455 KMP_STATS_LOOP_END;
2456 return status;
2457}
2458
2474kmp_int32 __kmpc_sections_init(ident_t *loc, kmp_int32 gtid) {
2475
2476 int active;
2477 kmp_info_t *th;
2478 kmp_team_t *team;
2479 kmp_uint32 my_buffer_index;
2480 dispatch_shared_info_template<kmp_int32> volatile *sh;
2481
2482 KMP_DEBUG_ASSERT(__kmp_init_serial);
2483
2484 if (!TCR_4(__kmp_init_parallel))
2485 __kmp_parallel_initialize();
2486 __kmp_resume_if_soft_paused();
2487
2488 /* setup data */
2489 th = __kmp_threads[gtid];
2490 team = th->th.th_team;
2491 active = !team->t.t_serialized;
2492 th->th.th_ident = loc;
2493
2494 KMP_COUNT_BLOCK(OMP_SECTIONS);
2495 KD_TRACE(10, ("__kmpc_sections: called by T#%d\n", gtid));
2496
2497 if (active) {
2498 // Setup sections in the same way as dynamic scheduled loops.
2499 // We need one shared data: which section is to execute next.
2500 // (in case parallel is not active, all sections will be executed on the
2501 // same thread)
2502 KMP_DEBUG_ASSERT(th->th.th_dispatch ==
2503 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
2504
2505 my_buffer_index = th->th.th_dispatch->th_disp_index++;
2506
2507 // reuse shared data structures from dynamic sched loops:
2508 sh = reinterpret_cast<dispatch_shared_info_template<kmp_int32> volatile *>(
2509 &team->t.t_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]);
2510 KD_TRACE(10, ("__kmpc_sections_init: T#%d my_buffer_index:%d\n", gtid,
2511 my_buffer_index));
2512
2513 th->th.th_dispatch->th_deo_fcn = __kmp_dispatch_deo_error;
2514 th->th.th_dispatch->th_dxo_fcn = __kmp_dispatch_dxo_error;
2515
2516 KD_TRACE(100, ("__kmpc_sections_init: T#%d before wait: my_buffer_index:%d "
2517 "sh->buffer_index:%d\n",
2518 gtid, my_buffer_index, sh->buffer_index));
2519 __kmp_wait<kmp_uint32>(&sh->buffer_index, my_buffer_index,
2520 __kmp_eq<kmp_uint32> USE_ITT_BUILD_ARG(NULL));
2521 // Note: KMP_WAIT() cannot be used there: buffer index and
2522 // my_buffer_index are *always* 32-bit integers.
2523 KMP_MB();
2524 KD_TRACE(100, ("__kmpc_sections_init: T#%d after wait: my_buffer_index:%d "
2525 "sh->buffer_index:%d\n",
2526 gtid, my_buffer_index, sh->buffer_index));
2527
2528 th->th.th_dispatch->th_dispatch_pr_current =
2529 nullptr; // sections construct doesn't need private data
2530 th->th.th_dispatch->th_dispatch_sh_current =
2531 CCAST(dispatch_shared_info_t *, (volatile dispatch_shared_info_t *)sh);
2532 }
2533
2534#if OMPT_SUPPORT && OMPT_OPTIONAL
2535 if (ompt_enabled.ompt_callback_work) {
2536 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
2537 ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
2538 ompt_callbacks.ompt_callback(ompt_callback_work)(
2539 ompt_work_sections, ompt_scope_begin, &(team_info->parallel_data),
2540 &(task_info->task_data), 0, OMPT_GET_RETURN_ADDRESS(0));
2541 }
2542#endif
2543 KMP_PUSH_PARTITIONED_TIMER(OMP_sections);
2544
2545 return active;
2546}
2547
2557
2558kmp_int32 __kmpc_next_section(ident_t *loc, kmp_int32 gtid,
2559 kmp_int32 numberOfSections) {
2560
2561 KMP_TIME_PARTITIONED_BLOCK(OMP_sections_overhead);
2562
2563 kmp_info_t *th = __kmp_threads[gtid];
2564#ifdef KMP_DEBUG
2565 kmp_team_t *team = th->th.th_team;
2566#endif
2567
2568 KD_TRACE(1000, ("__kmp_dispatch_next: T#%d; number of sections:%d\n", gtid,
2569 numberOfSections));
2570
2571 // For serialized case we should not call this function:
2572 KMP_DEBUG_ASSERT(!team->t.t_serialized);
2573
2574 dispatch_shared_info_template<kmp_int32> volatile *sh;
2575
2576 KMP_DEBUG_ASSERT(th->th.th_dispatch ==
2577 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]);
2578
2579 KMP_DEBUG_ASSERT(!(th->th.th_dispatch->th_dispatch_pr_current));
2580 sh = reinterpret_cast<dispatch_shared_info_template<kmp_int32> volatile *>(
2581 th->th.th_dispatch->th_dispatch_sh_current);
2582 KMP_DEBUG_ASSERT(sh);
2583
2584 kmp_int32 sectionIndex = 0;
2585 bool moreSectionsToExecute = true;
2586
2587 // Find section to execute:
2588 sectionIndex = test_then_inc<kmp_int32>((kmp_int32 *)&sh->u.s.iteration);
2589 if (sectionIndex >= numberOfSections) {
2590 moreSectionsToExecute = false;
2591 }
2592
2593 // status == 0: no more sections to execute;
2594 // OMPTODO: __kmpc_end_sections could be bypassed?
2595 if (!moreSectionsToExecute) {
2596 kmp_int32 num_done;
2597
2598 num_done = test_then_inc<kmp_int32>((kmp_int32 *)(&sh->u.s.num_done));
2599
2600 if (num_done == th->th.th_team_nproc - 1) {
2601 /* NOTE: release this buffer to be reused */
2602
2603 KMP_MB(); /* Flush all pending memory write invalidates. */
2604
2605 sh->u.s.num_done = 0;
2606 sh->u.s.iteration = 0;
2607
2608 KMP_MB(); /* Flush all pending memory write invalidates. */
2609
2610 sh->buffer_index += __kmp_dispatch_num_buffers;
2611 KD_TRACE(100, ("__kmpc_next_section: T#%d change buffer_index:%d\n", gtid,
2612 sh->buffer_index));
2613
2614 KMP_MB(); /* Flush all pending memory write invalidates. */
2615
2616 } // if
2617
2618 th->th.th_dispatch->th_deo_fcn = NULL;
2619 th->th.th_dispatch->th_dxo_fcn = NULL;
2620 th->th.th_dispatch->th_dispatch_sh_current = NULL;
2621 th->th.th_dispatch->th_dispatch_pr_current = NULL;
2622
2623#if OMPT_SUPPORT && OMPT_OPTIONAL
2624 if (ompt_enabled.ompt_callback_dispatch) {
2625 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
2626 ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
2627 ompt_data_t instance = ompt_data_none;
2628 instance.ptr = OMPT_GET_RETURN_ADDRESS(0);
2629 ompt_callbacks.ompt_callback(ompt_callback_dispatch)(
2630 &(team_info->parallel_data), &(task_info->task_data),
2631 ompt_dispatch_section, instance);
2632 }
2633#endif
2634 }
2635
2636 return sectionIndex;
2637}
2638
2647void __kmpc_end_sections(ident_t *loc, kmp_int32 gtid) {
2648
2649 kmp_info_t *th = __kmp_threads[gtid];
2650 int active = !th->th.th_team->t.t_serialized;
2651
2652 KD_TRACE(100, ("__kmpc_end_sections: T#%d called\n", gtid));
2653
2654 if (!active) {
2655 // In active case call finalization is done in __kmpc_next_section
2656#if OMPT_SUPPORT && OMPT_OPTIONAL
2657 if (ompt_enabled.ompt_callback_work) {
2658 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
2659 ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
2660 ompt_callbacks.ompt_callback(ompt_callback_work)(
2661 ompt_work_sections, ompt_scope_end, &(team_info->parallel_data),
2662 &(task_info->task_data), 0, OMPT_GET_RETURN_ADDRESS(0));
2663 }
2664#endif
2665 }
2666
2667 KMP_POP_PARTITIONED_TIMER();
2668 KD_TRACE(100, ("__kmpc_end_sections: T#%d returned\n", gtid));
2669}
2670
2671template <typename T>
2672static void __kmp_dist_get_bounds(ident_t *loc, kmp_int32 gtid,
2673 kmp_int32 *plastiter, T *plower, T *pupper,
2674 typename traits_t<T>::signed_t incr) {
2675 typedef typename traits_t<T>::unsigned_t UT;
2676 kmp_uint32 team_id;
2677 kmp_uint32 nteams;
2678 UT trip_count;
2679 kmp_team_t *team;
2680 kmp_info_t *th;
2681
2682 KMP_DEBUG_ASSERT(plastiter && plower && pupper);
2683 KE_TRACE(10, ("__kmpc_dist_get_bounds called (%d)\n", gtid));
2684#ifdef KMP_DEBUG
2685 typedef typename traits_t<T>::signed_t ST;
2686 {
2687 char *buff;
2688 // create format specifiers before the debug output
2689 buff = __kmp_str_format("__kmpc_dist_get_bounds: T#%%d liter=%%d "
2690 "iter=(%%%s, %%%s, %%%s) signed?<%s>\n",
2691 traits_t<T>::spec, traits_t<T>::spec,
2692 traits_t<ST>::spec, traits_t<T>::spec);
2693 KD_TRACE(100, (buff, gtid, *plastiter, *plower, *pupper, incr));
2694 __kmp_str_free(&buff);
2695 }
2696#endif
2697
2698 if (__kmp_env_consistency_check) {
2699 if (incr == 0) {
2700 __kmp_error_construct(kmp_i18n_msg_CnsLoopIncrZeroProhibited, ct_pdo,
2701 loc);
2702 }
2703 if (incr > 0 ? (*pupper < *plower) : (*plower < *pupper)) {
2704 // The loop is illegal.
2705 // Some zero-trip loops maintained by compiler, e.g.:
2706 // for(i=10;i<0;++i) // lower >= upper - run-time check
2707 // for(i=0;i>10;--i) // lower <= upper - run-time check
2708 // for(i=0;i>10;++i) // incr > 0 - compile-time check
2709 // for(i=10;i<0;--i) // incr < 0 - compile-time check
2710 // Compiler does not check the following illegal loops:
2711 // for(i=0;i<10;i+=incr) // where incr<0
2712 // for(i=10;i>0;i-=incr) // where incr<0
2713 __kmp_error_construct(kmp_i18n_msg_CnsLoopIncrIllegal, ct_pdo, loc);
2714 }
2715 }
2716 __kmp_assert_valid_gtid(gtid);
2717 th = __kmp_threads[gtid];
2718 team = th->th.th_team;
2719 KMP_DEBUG_ASSERT(th->th.th_teams_microtask); // we are in the teams construct
2720 nteams = th->th.th_teams_size.nteams;
2721 team_id = team->t.t_master_tid;
2722 KMP_DEBUG_ASSERT(nteams == (kmp_uint32)team->t.t_parent->t.t_nproc);
2723
2724 // compute global trip count
2725 if (incr == 1) {
2726 trip_count = *pupper - *plower + 1;
2727 } else if (incr == -1) {
2728 trip_count = *plower - *pupper + 1;
2729 } else if (incr > 0) {
2730 // upper-lower can exceed the limit of signed type
2731 trip_count = (UT)(*pupper - *plower) / incr + 1;
2732 } else {
2733 trip_count = (UT)(*plower - *pupper) / (-incr) + 1;
2734 }
2735
2736 if (trip_count <= nteams) {
2737 KMP_DEBUG_ASSERT(
2738 __kmp_static == kmp_sch_static_greedy ||
2739 __kmp_static ==
2740 kmp_sch_static_balanced); // Unknown static scheduling type.
2741 // only some teams get single iteration, others get nothing
2742 if (team_id < trip_count) {
2743 *pupper = *plower = *plower + team_id * incr;
2744 } else {
2745 *plower = *pupper + incr; // zero-trip loop
2746 }
2747 if (plastiter != NULL)
2748 *plastiter = (team_id == trip_count - 1);
2749 } else {
2750 if (__kmp_static == kmp_sch_static_balanced) {
2751 UT chunk = trip_count / nteams;
2752 UT extras = trip_count % nteams;
2753 *plower +=
2754 incr * (team_id * chunk + (team_id < extras ? team_id : extras));
2755 *pupper = *plower + chunk * incr - (team_id < extras ? 0 : incr);
2756 if (plastiter != NULL)
2757 *plastiter = (team_id == nteams - 1);
2758 } else {
2759 T chunk_inc_count =
2760 (trip_count / nteams + ((trip_count % nteams) ? 1 : 0)) * incr;
2761 T upper = *pupper;
2762 KMP_DEBUG_ASSERT(__kmp_static == kmp_sch_static_greedy);
2763 // Unknown static scheduling type.
2764 *plower += team_id * chunk_inc_count;
2765 *pupper = *plower + chunk_inc_count - incr;
2766 // Check/correct bounds if needed
2767 if (incr > 0) {
2768 if (*pupper < *plower)
2769 *pupper = traits_t<T>::max_value;
2770 if (plastiter != NULL)
2771 *plastiter = *plower <= upper && *pupper > upper - incr;
2772 if (*pupper > upper)
2773 *pupper = upper; // tracker C73258
2774 } else {
2775 if (*pupper > *plower)
2776 *pupper = traits_t<T>::min_value;
2777 if (plastiter != NULL)
2778 *plastiter = *plower >= upper && *pupper < upper - incr;
2779 if (*pupper < upper)
2780 *pupper = upper; // tracker C73258
2781 }
2782 }
2783 }
2784}
2785
2786//-----------------------------------------------------------------------------
2787// Dispatch routines
2788// Transfer call to template< type T >
2789// __kmp_dispatch_init( ident_t *loc, int gtid, enum sched_type schedule,
2790// T lb, T ub, ST st, ST chunk )
2791extern "C" {
2792
2808
2809void __kmpc_dispatch_init_4(ident_t *loc, kmp_int32 gtid,
2810 enum sched_type schedule, kmp_int32 lb,
2811 kmp_int32 ub, kmp_int32 st, kmp_int32 chunk) {
2812 KMP_DEBUG_ASSERT(__kmp_init_serial);
2813#if OMPT_SUPPORT && OMPT_OPTIONAL
2814 OMPT_STORE_RETURN_ADDRESS(gtid);
2815#endif
2816 __kmp_dispatch_init<kmp_int32>(loc, gtid, schedule, lb, ub, st, chunk, true);
2817}
2818
2821void __kmpc_dispatch_init_4u(ident_t *loc, kmp_int32 gtid,
2822 enum sched_type schedule, kmp_uint32 lb,
2823 kmp_uint32 ub, kmp_int32 st, kmp_int32 chunk) {
2824 KMP_DEBUG_ASSERT(__kmp_init_serial);
2825#if OMPT_SUPPORT && OMPT_OPTIONAL
2826 OMPT_STORE_RETURN_ADDRESS(gtid);
2827#endif
2828 __kmp_dispatch_init<kmp_uint32>(loc, gtid, schedule, lb, ub, st, chunk, true);
2829}
2830
2834void __kmpc_dispatch_init_8(ident_t *loc, kmp_int32 gtid,
2835 enum sched_type schedule, kmp_int64 lb,
2836 kmp_int64 ub, kmp_int64 st, kmp_int64 chunk) {
2837 KMP_DEBUG_ASSERT(__kmp_init_serial);
2838#if OMPT_SUPPORT && OMPT_OPTIONAL
2839 OMPT_STORE_RETURN_ADDRESS(gtid);
2840#endif
2841 __kmp_dispatch_init<kmp_int64>(loc, gtid, schedule, lb, ub, st, chunk, true);
2842}
2843
2847void __kmpc_dispatch_init_8u(ident_t *loc, kmp_int32 gtid,
2848 enum sched_type schedule, kmp_uint64 lb,
2849 kmp_uint64 ub, kmp_int64 st, kmp_int64 chunk) {
2850 KMP_DEBUG_ASSERT(__kmp_init_serial);
2851#if OMPT_SUPPORT && OMPT_OPTIONAL
2852 OMPT_STORE_RETURN_ADDRESS(gtid);
2853#endif
2854 __kmp_dispatch_init<kmp_uint64>(loc, gtid, schedule, lb, ub, st, chunk, true);
2855}
2856
2866void __kmpc_dist_dispatch_init_4(ident_t *loc, kmp_int32 gtid,
2867 enum sched_type schedule, kmp_int32 *p_last,
2868 kmp_int32 lb, kmp_int32 ub, kmp_int32 st,
2869 kmp_int32 chunk) {
2870 KMP_DEBUG_ASSERT(__kmp_init_serial);
2871#if OMPT_SUPPORT && OMPT_OPTIONAL
2872 OMPT_STORE_RETURN_ADDRESS(gtid);
2873#endif
2874 __kmp_dist_get_bounds<kmp_int32>(loc, gtid, p_last, &lb, &ub, st);
2875 __kmp_dispatch_init<kmp_int32>(loc, gtid, schedule, lb, ub, st, chunk, true);
2876}
2877
2878void __kmpc_dist_dispatch_init_4u(ident_t *loc, kmp_int32 gtid,
2879 enum sched_type schedule, kmp_int32 *p_last,
2880 kmp_uint32 lb, kmp_uint32 ub, kmp_int32 st,
2881 kmp_int32 chunk) {
2882 KMP_DEBUG_ASSERT(__kmp_init_serial);
2883#if OMPT_SUPPORT && OMPT_OPTIONAL
2884 OMPT_STORE_RETURN_ADDRESS(gtid);
2885#endif
2886 __kmp_dist_get_bounds<kmp_uint32>(loc, gtid, p_last, &lb, &ub, st);
2887 __kmp_dispatch_init<kmp_uint32>(loc, gtid, schedule, lb, ub, st, chunk, true);
2888}
2889
2890void __kmpc_dist_dispatch_init_8(ident_t *loc, kmp_int32 gtid,
2891 enum sched_type schedule, kmp_int32 *p_last,
2892 kmp_int64 lb, kmp_int64 ub, kmp_int64 st,
2893 kmp_int64 chunk) {
2894 KMP_DEBUG_ASSERT(__kmp_init_serial);
2895#if OMPT_SUPPORT && OMPT_OPTIONAL
2896 OMPT_STORE_RETURN_ADDRESS(gtid);
2897#endif
2898 __kmp_dist_get_bounds<kmp_int64>(loc, gtid, p_last, &lb, &ub, st);
2899 __kmp_dispatch_init<kmp_int64>(loc, gtid, schedule, lb, ub, st, chunk, true);
2900}
2901
2902void __kmpc_dist_dispatch_init_8u(ident_t *loc, kmp_int32 gtid,
2903 enum sched_type schedule, kmp_int32 *p_last,
2904 kmp_uint64 lb, kmp_uint64 ub, kmp_int64 st,
2905 kmp_int64 chunk) {
2906 KMP_DEBUG_ASSERT(__kmp_init_serial);
2907#if OMPT_SUPPORT && OMPT_OPTIONAL
2908 OMPT_STORE_RETURN_ADDRESS(gtid);
2909#endif
2910 __kmp_dist_get_bounds<kmp_uint64>(loc, gtid, p_last, &lb, &ub, st);
2911 __kmp_dispatch_init<kmp_uint64>(loc, gtid, schedule, lb, ub, st, chunk, true);
2912}
2913
2927int __kmpc_dispatch_next_4(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last,
2928 kmp_int32 *p_lb, kmp_int32 *p_ub, kmp_int32 *p_st) {
2929#if OMPT_SUPPORT && OMPT_OPTIONAL
2930 OMPT_STORE_RETURN_ADDRESS(gtid);
2931#endif
2932 return __kmp_dispatch_next<kmp_int32>(loc, gtid, p_last, p_lb, p_ub, p_st
2933#if OMPT_SUPPORT && OMPT_OPTIONAL
2934 ,
2935 OMPT_LOAD_RETURN_ADDRESS(gtid)
2936#endif
2937 );
2938}
2939
2943int __kmpc_dispatch_next_4u(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last,
2944 kmp_uint32 *p_lb, kmp_uint32 *p_ub,
2945 kmp_int32 *p_st) {
2946#if OMPT_SUPPORT && OMPT_OPTIONAL
2947 OMPT_STORE_RETURN_ADDRESS(gtid);
2948#endif
2949 return __kmp_dispatch_next<kmp_uint32>(loc, gtid, p_last, p_lb, p_ub, p_st
2950#if OMPT_SUPPORT && OMPT_OPTIONAL
2951 ,
2952 OMPT_LOAD_RETURN_ADDRESS(gtid)
2953#endif
2954 );
2955}
2956
2960int __kmpc_dispatch_next_8(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last,
2961 kmp_int64 *p_lb, kmp_int64 *p_ub, kmp_int64 *p_st) {
2962#if OMPT_SUPPORT && OMPT_OPTIONAL
2963 OMPT_STORE_RETURN_ADDRESS(gtid);
2964#endif
2965 return __kmp_dispatch_next<kmp_int64>(loc, gtid, p_last, p_lb, p_ub, p_st
2966#if OMPT_SUPPORT && OMPT_OPTIONAL
2967 ,
2968 OMPT_LOAD_RETURN_ADDRESS(gtid)
2969#endif
2970 );
2971}
2972
2976int __kmpc_dispatch_next_8u(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last,
2977 kmp_uint64 *p_lb, kmp_uint64 *p_ub,
2978 kmp_int64 *p_st) {
2979#if OMPT_SUPPORT && OMPT_OPTIONAL
2980 OMPT_STORE_RETURN_ADDRESS(gtid);
2981#endif
2982 return __kmp_dispatch_next<kmp_uint64>(loc, gtid, p_last, p_lb, p_ub, p_st
2983#if OMPT_SUPPORT && OMPT_OPTIONAL
2984 ,
2985 OMPT_LOAD_RETURN_ADDRESS(gtid)
2986#endif
2987 );
2988}
2989
2996void __kmpc_dispatch_fini_4(ident_t *loc, kmp_int32 gtid) {
2997 __kmp_dispatch_finish<kmp_uint32>(gtid, loc);
2998}
2999
3003void __kmpc_dispatch_fini_8(ident_t *loc, kmp_int32 gtid) {
3004 __kmp_dispatch_finish<kmp_uint64>(gtid, loc);
3005}
3006
3010void __kmpc_dispatch_fini_4u(ident_t *loc, kmp_int32 gtid) {
3011 __kmp_dispatch_finish<kmp_uint32>(gtid, loc);
3012}
3013
3017void __kmpc_dispatch_fini_8u(ident_t *loc, kmp_int32 gtid) {
3018 __kmp_dispatch_finish<kmp_uint64>(gtid, loc);
3019}
3020
3024void __kmpc_dispatch_deinit(ident_t *loc, kmp_int32 gtid) {}
3026
3027//-----------------------------------------------------------------------------
3028// Non-template routines from kmp_dispatch.cpp used in other sources
3029
3030kmp_uint32 __kmp_eq_4(kmp_uint32 value, kmp_uint32 checker) {
3031 return value == checker;
3032}
3033
3034kmp_uint32 __kmp_neq_4(kmp_uint32 value, kmp_uint32 checker) {
3035 return value != checker;
3036}
3037
3038kmp_uint32 __kmp_lt_4(kmp_uint32 value, kmp_uint32 checker) {
3039 return value < checker;
3040}
3041
3042kmp_uint32 __kmp_ge_4(kmp_uint32 value, kmp_uint32 checker) {
3043 return value >= checker;
3044}
3045
3046kmp_uint32 __kmp_le_4(kmp_uint32 value, kmp_uint32 checker) {
3047 return value <= checker;
3048}
3049
3050kmp_uint32
3051__kmp_wait_4(volatile kmp_uint32 *spinner, kmp_uint32 checker,
3052 kmp_uint32 (*pred)(kmp_uint32, kmp_uint32),
3053 void *obj // Higher-level synchronization object, or NULL.
3054) {
3055 // note: we may not belong to a team at this point
3056 volatile kmp_uint32 *spin = spinner;
3057 kmp_uint32 check = checker;
3058 kmp_uint32 spins;
3059 kmp_uint32 (*f)(kmp_uint32, kmp_uint32) = pred;
3060 kmp_uint32 r;
3061 kmp_uint64 time;
3062
3063 KMP_FSYNC_SPIN_INIT(obj, CCAST(kmp_uint32 *, spin));
3064 KMP_INIT_YIELD(spins);
3065 KMP_INIT_BACKOFF(time);
3066 // main wait spin loop
3067 while (!f(r = TCR_4(*spin), check)) {
3068 KMP_FSYNC_SPIN_PREPARE(obj);
3069 /* GEH - remove this since it was accidentally introduced when kmp_wait was
3070 split. It causes problems with infinite recursion because of exit lock */
3071 /* if ( TCR_4(__kmp_global.g.g_done) && __kmp_global.g.g_abort)
3072 __kmp_abort_thread(); */
3073 KMP_YIELD_OVERSUB_ELSE_SPIN(spins, time);
3074 }
3075 KMP_FSYNC_SPIN_ACQUIRED(obj);
3076 return r;
3077}
3078
3079void __kmp_wait_4_ptr(void *spinner, kmp_uint32 checker,
3080 kmp_uint32 (*pred)(void *, kmp_uint32),
3081 void *obj // Higher-level synchronization object, or NULL.
3082) {
3083 // note: we may not belong to a team at this point
3084 void *spin = spinner;
3085 kmp_uint32 check = checker;
3086 kmp_uint32 spins;
3087 kmp_uint32 (*f)(void *, kmp_uint32) = pred;
3088 kmp_uint64 time;
3089
3090 KMP_FSYNC_SPIN_INIT(obj, spin);
3091 KMP_INIT_YIELD(spins);
3092 KMP_INIT_BACKOFF(time);
3093 // main wait spin loop
3094 while (!f(spin, check)) {
3095 KMP_FSYNC_SPIN_PREPARE(obj);
3096 /* if we have waited a bit, or are noversubscribed, yield */
3097 /* pause is in the following code */
3098 KMP_YIELD_OVERSUB_ELSE_SPIN(spins, time);
3099 }
3100 KMP_FSYNC_SPIN_ACQUIRED(obj);
3101}
3102
3103} // extern "C"
3104
3105#ifdef KMP_GOMP_COMPAT
3106
3107void __kmp_aux_dispatch_init_4(ident_t *loc, kmp_int32 gtid,
3108 enum sched_type schedule, kmp_int32 lb,
3109 kmp_int32 ub, kmp_int32 st, kmp_int32 chunk,
3110 int push_ws) {
3111 __kmp_dispatch_init<kmp_int32>(loc, gtid, schedule, lb, ub, st, chunk,
3112 push_ws);
3113}
3114
3115void __kmp_aux_dispatch_init_4u(ident_t *loc, kmp_int32 gtid,
3116 enum sched_type schedule, kmp_uint32 lb,
3117 kmp_uint32 ub, kmp_int32 st, kmp_int32 chunk,
3118 int push_ws) {
3119 __kmp_dispatch_init<kmp_uint32>(loc, gtid, schedule, lb, ub, st, chunk,
3120 push_ws);
3121}
3122
3123void __kmp_aux_dispatch_init_8(ident_t *loc, kmp_int32 gtid,
3124 enum sched_type schedule, kmp_int64 lb,
3125 kmp_int64 ub, kmp_int64 st, kmp_int64 chunk,
3126 int push_ws) {
3127 __kmp_dispatch_init<kmp_int64>(loc, gtid, schedule, lb, ub, st, chunk,
3128 push_ws);
3129}
3130
3131void __kmp_aux_dispatch_init_8u(ident_t *loc, kmp_int32 gtid,
3132 enum sched_type schedule, kmp_uint64 lb,
3133 kmp_uint64 ub, kmp_int64 st, kmp_int64 chunk,
3134 int push_ws) {
3135 __kmp_dispatch_init<kmp_uint64>(loc, gtid, schedule, lb, ub, st, chunk,
3136 push_ws);
3137}
3138
3139void __kmp_aux_dispatch_fini_chunk_4(ident_t *loc, kmp_int32 gtid) {
3140 __kmp_dispatch_finish_chunk<kmp_uint32>(gtid, loc);
3141}
3142
3143void __kmp_aux_dispatch_fini_chunk_8(ident_t *loc, kmp_int32 gtid) {
3144 __kmp_dispatch_finish_chunk<kmp_uint64>(gtid, loc);
3145}
3146
3147void __kmp_aux_dispatch_fini_chunk_4u(ident_t *loc, kmp_int32 gtid) {
3148 __kmp_dispatch_finish_chunk<kmp_uint32>(gtid, loc);
3149}
3150
3151void __kmp_aux_dispatch_fini_chunk_8u(ident_t *loc, kmp_int32 gtid) {
3152 __kmp_dispatch_finish_chunk<kmp_uint64>(gtid, loc);
3153}
3154
3155#endif /* KMP_GOMP_COMPAT */
3156
3157/* ------------------------------------------------------------------------ */
struct ident ident_t
#define KMP_COUNT_VALUE(name, value)
Adds value to specified timer (name).
Definition kmp_stats.h:898
#define KMP_COUNT_BLOCK(name)
Increments specified counter (name).
Definition kmp_stats.h:911
int __kmpc_dispatch_next_4(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last, kmp_int32 *p_lb, kmp_int32 *p_ub, kmp_int32 *p_st)
sched_type
Definition kmp.h:340
void __kmpc_dispatch_fini_4(ident_t *loc, kmp_int32 gtid)
void __kmpc_dispatch_deinit(ident_t *loc, kmp_int32 gtid)
kmp_int32 __kmpc_next_section(ident_t *loc, kmp_int32 gtid, kmp_int32 numberOfSections)
void __kmpc_dist_dispatch_init_4(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_int32 *p_last, kmp_int32 lb, kmp_int32 ub, kmp_int32 st, kmp_int32 chunk)
int __kmpc_dispatch_next_4u(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last, kmp_uint32 *p_lb, kmp_uint32 *p_ub, kmp_int32 *p_st)
void __kmpc_end_sections(ident_t *loc, kmp_int32 gtid)
int __kmpc_dispatch_next_8u(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last, kmp_uint64 *p_lb, kmp_uint64 *p_ub, kmp_int64 *p_st)
void __kmpc_dispatch_fini_8(ident_t *loc, kmp_int32 gtid)
kmp_int32 __kmpc_sections_init(ident_t *loc, kmp_int32 gtid)
int __kmpc_dispatch_next_8(ident_t *loc, kmp_int32 gtid, kmp_int32 *p_last, kmp_int64 *p_lb, kmp_int64 *p_ub, kmp_int64 *p_st)
void __kmpc_dispatch_fini_8u(ident_t *loc, kmp_int32 gtid)
void __kmpc_dispatch_init_4(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_int32 lb, kmp_int32 ub, kmp_int32 st, kmp_int32 chunk)
void __kmpc_dispatch_init_4u(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_uint32 lb, kmp_uint32 ub, kmp_int32 st, kmp_int32 chunk)
void __kmpc_dispatch_init_8u(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_uint64 lb, kmp_uint64 ub, kmp_int64 st, kmp_int64 chunk)
void __kmpc_dispatch_fini_4u(ident_t *loc, kmp_int32 gtid)
void __kmpc_dispatch_init_8(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_int64 lb, kmp_int64 ub, kmp_int64 st, kmp_int64 chunk)
@ kmp_sch_runtime_simd
Definition kmp.h:362
@ kmp_sch_auto
Definition kmp.h:347
@ kmp_sch_static
Definition kmp.h:343
@ kmp_sch_guided_simd
Definition kmp.h:361
@ kmp_sch_modifier_nonmonotonic
Definition kmp.h:430
@ kmp_sch_guided_chunked
Definition kmp.h:345
@ kmp_sch_lower
Definition kmp.h:341
@ kmp_nm_upper
Definition kmp.h:412
@ kmp_ord_lower
Definition kmp.h:367
@ kmp_sch_upper
Definition kmp.h:365
@ kmp_nm_lower
Definition kmp.h:385