LLVM OpenMP
kmp_dispatch.cpp
Go to the documentation of this file.
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
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
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
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)];
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>
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
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) {
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) {
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
382 if (st == 0) {
383 __kmp_error_construct(kmp_i18n_msg_CnsLoopIncrZeroProhibited,
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
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;
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
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
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
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;
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 );
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 -
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;
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;
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) {
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) {
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) {
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) {
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
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;
980
982 sizeof(dispatch_private_info));
984 sizeof(dispatch_shared_info));
986
989
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,
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 =
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) {
1119 case kmp_sch_static_balanced: // Chunk is calculated in the switch above
1120 break;
1122 cur_chunk = pr->u.p.parm1;
1123 break;
1125 schedtype = 1;
1126 break;
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);
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;
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
1197 reinterpret_cast<dispatch_private_info_template<UT> *>(
1198 th->th.th_dispatch->th_dispatch_pr_current);
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,
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;
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) {
1260 reinterpret_cast<dispatch_private_info_template<UT> *>(
1261 th->th.th_dispatch->th_dispatch_pr_current);
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,
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;
1304//!!!!! TODO check if the inc should be unsigned, or signed???
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>
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)) {
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]);
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]);
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
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)) {
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]);
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]);
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);
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
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 */
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
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
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
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) {
1998 trip, *(DBL *)&pr->u.p.parm3, chunkIdx);
2000 init = trip - init;
2001 } else
2002 init = 0;
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;
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;
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;
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);
2330 return status;
2331 } else {
2332 kmp_int32 last = 0;
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) {
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);
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
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
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);
2456 return status;
2457}
2458
2459/*!
2460@ingroup WORK_SHARING
2461@param loc source location information
2462@param global_tid global thread number
2463@return Zero if the parallel region is not active and this thread should execute
2464all sections, non-zero otherwise.
2465
2466Beginning of sections construct.
2467There are no implicit barriers in the "sections" calls, rather the compiler
2468should introduce an explicit barrier if it is required.
2469
2470This implementation is based on __kmp_dispatch_init, using same constructs for
2471shared data (we can't have sections nested directly in omp for loop, there
2472should be a parallel region in between)
2473*/
2475
2476 int active;
2477 kmp_info_t *th;
2478 kmp_team_t *team;
2479 kmp_uint32 my_buffer_index;
2481
2483
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,
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 =
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);
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
2548/*!
2549@ingroup WORK_SHARING
2550@param loc source location information
2551@param global_tid global thread number
2552@param numberOfSections number of sections in the 'sections' construct
2553@return unsigned [from 0 to n) - number (id) of the section to execute next on
2554this thread. n (or any other number not in range) - nothing to execute on this
2555thread
2556*/
2557
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
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
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);
2627 ompt_data_t instance = ompt_data_none;
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
2639/*!
2640@ingroup WORK_SHARING
2641@param loc source location information
2642@param global_tid global thread number
2643
2644End of "sections" construct.
2645Don't need to wait here: barrier is added separately when needed.
2646*/
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);
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
2668 KD_TRACE(100, ("__kmpc_end_sections: T#%d returned\n", gtid));
2669}
2670
2671template <typename T>
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
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 }
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) {
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 {
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;
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
2793/*!
2794@ingroup WORK_SHARING
2795@{
2796@param loc Source location
2797@param gtid Global thread id
2798@param schedule Schedule type
2799@param lb Lower bound
2800@param ub Upper bound
2801@param st Step (or increment if you prefer)
2802@param chunk The chunk size to block with
2803
2804This function prepares the runtime to start a dynamically scheduled for loop,
2805saving the loop arguments.
2806These functions are all identical apart from the types of the arguments.
2807*/
2808
2810 enum sched_type schedule, kmp_int32 lb,
2811 kmp_int32 ub, kmp_int32 st, kmp_int32 chunk) {
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/*!
2819See @ref __kmpc_dispatch_init_4
2820*/
2822 enum sched_type schedule, kmp_uint32 lb,
2823 kmp_uint32 ub, kmp_int32 st, kmp_int32 chunk) {
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
2831/*!
2832See @ref __kmpc_dispatch_init_4
2833*/
2835 enum sched_type schedule, kmp_int64 lb,
2836 kmp_int64 ub, kmp_int64 st, kmp_int64 chunk) {
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
2844/*!
2845See @ref __kmpc_dispatch_init_4
2846*/
2848 enum sched_type schedule, kmp_uint64 lb,
2849 kmp_uint64 ub, kmp_int64 st, kmp_int64 chunk) {
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
2857/*!
2858See @ref __kmpc_dispatch_init_4
2859
2860Difference from __kmpc_dispatch_init set of functions is these functions
2861are called for composite distribute parallel for construct. Thus before
2862regular iterations dispatching we need to calc per-team iteration space.
2863
2864These functions are all identical apart from the types of the arguments.
2865*/
2867 enum sched_type schedule, kmp_int32 *p_last,
2868 kmp_int32 lb, kmp_int32 ub, kmp_int32 st,
2869 kmp_int32 chunk) {
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
2879 enum sched_type schedule, kmp_int32 *p_last,
2880 kmp_uint32 lb, kmp_uint32 ub, kmp_int32 st,
2881 kmp_int32 chunk) {
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
2891 enum sched_type schedule, kmp_int32 *p_last,
2892 kmp_int64 lb, kmp_int64 ub, kmp_int64 st,
2893 kmp_int64 chunk) {
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
2903 enum sched_type schedule, kmp_int32 *p_last,
2904 kmp_uint64 lb, kmp_uint64 ub, kmp_int64 st,
2905 kmp_int64 chunk) {
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
2914/*!
2915@param loc Source code location
2916@param gtid Global thread id
2917@param p_last Pointer to a flag set to one if this is the last chunk or zero
2918otherwise
2919@param p_lb Pointer to the lower bound for the next chunk of work
2920@param p_ub Pointer to the upper bound for the next chunk of work
2921@param p_st Pointer to the stride for the next chunk of work
2922@return one if there is work to be done, zero otherwise
2923
2924Get the next dynamically allocated chunk of work for this thread.
2925If there is no more work, then the lb,ub and stride need not be modified.
2926*/
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
2940/*!
2941See @ref __kmpc_dispatch_next_4
2942*/
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
2957/*!
2958See @ref __kmpc_dispatch_next_4
2959*/
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
2973/*!
2974See @ref __kmpc_dispatch_next_4
2975*/
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
2990/*!
2991@param loc Source code location
2992@param gtid Global thread id
2993
2994Mark the end of a dynamic loop.
2995*/
2999
3000/*!
3001See @ref __kmpc_dispatch_fini_4
3002*/
3006
3007/*!
3008See @ref __kmpc_dispatch_fini_4
3009*/
3013
3014/*!
3015See @ref __kmpc_dispatch_fini_4
3016*/
3020
3021/*!
3022See @ref __kmpc_dispatch_deinit
3023*/
3025/*! @} */
3026
3027//-----------------------------------------------------------------------------
3028// Non-template routines from kmp_dispatch.cpp used in other sources
3029
3033
3037
3041
3045
3049
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;
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)) {
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 }
3076 return r;
3077}
3078
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;
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)) {
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 }
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/* ------------------------------------------------------------------------ */
char buf[BUFFER_SIZE]
void * target(void *task)
int64_t kmp_int64
Definition common.h:10
void __kmpc_dist_dispatch_init_4u(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_int32 *p_last, kmp_uint32 lb, kmp_uint32 ub, kmp_int32 st, kmp_int32 chunk)
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
Describes the loop schedule to be used for a parallel for loop.
Definition kmp.h:340
void __kmpc_dist_dispatch_init_8u(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_int32 *p_last, kmp_uint64 lb, kmp_uint64 ub, kmp_int64 st, kmp_int64 chunk)
void __kmpc_dispatch_fini_4(ident_t *loc, kmp_int32 gtid)
void __kmpc_dispatch_deinit(ident_t *loc, kmp_int32 gtid)
See __kmpc_dispatch_deinit.
kmp_int32 __kmpc_next_section(ident_t *loc, kmp_int32 gtid, kmp_int32 numberOfSections)
void __kmpc_dist_dispatch_init_8(ident_t *loc, kmp_int32 gtid, enum sched_type schedule, kmp_int32 *p_last, kmp_int64 lb, kmp_int64 ub, kmp_int64 st, kmp_int64 chunk)
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)
See __kmpc_dispatch_init_4.
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)
See __kmpc_dispatch_next_4.
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)
See __kmpc_dispatch_next_4.
void __kmpc_dispatch_fini_8(ident_t *loc, kmp_int32 gtid)
See __kmpc_dispatch_fini_4.
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)
See __kmpc_dispatch_next_4.
void __kmpc_dispatch_fini_8u(ident_t *loc, kmp_int32 gtid)
See __kmpc_dispatch_fini_4.
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)
See __kmpc_dispatch_init_4.
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)
See __kmpc_dispatch_init_4.
void __kmpc_dispatch_fini_4u(ident_t *loc, kmp_int32 gtid)
See __kmpc_dispatch_fini_4.
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)
See __kmpc_dispatch_init_4.
@ kmp_sch_runtime_simd
runtime with chunk adjustment
Definition kmp.h:362
@ kmp_sch_auto
auto
Definition kmp.h:347
@ kmp_sch_static
static unspecialized
Definition kmp.h:343
@ kmp_sch_guided_simd
guided with chunk adjustment
Definition kmp.h:361
@ kmp_sch_runtime
Definition kmp.h:346
@ kmp_sch_modifier_nonmonotonic
Set if the nonmonotonic schedule modifier was present.
Definition kmp.h:430
@ kmp_sch_guided_chunked
guided unspecialized
Definition kmp.h:345
@ kmp_sch_dynamic_chunked
Definition kmp.h:344
@ kmp_sch_guided_analytical_chunked
Definition kmp.h:355
@ kmp_sch_static_balanced
Definition kmp.h:352
@ kmp_sch_static_greedy
Definition kmp.h:351
@ kmp_sch_lower
lower bound for unordered values
Definition kmp.h:341
@ kmp_sch_static_chunked
Definition kmp.h:342
@ kmp_sch_trapezoidal
Definition kmp.h:348
@ kmp_nm_upper
upper bound for nomerge values
Definition kmp.h:412
@ kmp_ord_lower
lower bound for ordered values, must be power of 2
Definition kmp.h:367
@ kmp_sch_guided_iterative_chunked
Definition kmp.h:354
@ kmp_sch_static_balanced_chunked
Definition kmp.h:360
@ kmp_sch_upper
upper bound for unordered values
Definition kmp.h:365
@ kmp_nm_lower
lower bound for nomerge values
Definition kmp.h:385
@ kmp_sch_static_steal
Definition kmp.h:357
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance * instance
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t count
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long value
void const char const char int ITT_FORMAT __itt_group_sync p
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type size_t void ITT_FORMAT p const __itt_domain __itt_id __itt_string_handle const wchar_t size_t ITT_FORMAT lu const __itt_domain __itt_id __itt_relation __itt_id ITT_FORMAT p const wchar_t int ITT_FORMAT __itt_group_mark d int
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type type
#define __kmp_free(ptr)
Definition kmp.h:3749
#define KMP_CPU_PAUSE()
Definition kmp.h:1585
#define KMP_DEFAULT_CHUNK
Definition kmp.h:1305
@ ct_ordered_in_pdo
Definition kmp.h:1691
@ ct_none
Definition kmp.h:1683
@ ct_pdo_ordered
Definition kmp.h:1686
@ ct_pdo
Definition kmp.h:1685
#define KMP_YIELD_OVERSUB_ELSE_SPIN(count, time)
Definition kmp.h:1661
struct dispatch_shared_info dispatch_shared_info_t
struct KMP_ALIGN_CACHE dispatch_private_info dispatch_private_info_t
#define SCHEDULE_MONOTONIC
Definition kmp.h:446
#define SCHEDULE_HAS_MONOTONIC(s)
Definition kmp.h:436
enum sched_type __kmp_auto
enum sched_type __kmp_static
int __kmp_force_monotonic
kmp_info_t ** __kmp_threads
int __kmp_dispatch_num_buffers
#define SCHEDULE_WITHOUT_MODIFIERS(s)
Definition kmp.h:433
union kmp_team kmp_team_t
Definition kmp.h:241
#define KMP_INIT_YIELD(count)
Definition kmp.h:1588
#define KMP_MASTER_GTID(gtid)
Definition kmp.h:1335
void __kmp_parallel_initialize(void)
#define KMP_INIT_BACKOFF(time)
Definition kmp.h:1591
volatile int __kmp_init_parallel
#define __kmp_allocate(size)
Definition kmp.h:3747
#define TRUE
Definition kmp.h:1341
#define FALSE
Definition kmp.h:1340
static bool __kmp_is_hybrid_cpu()
Definition kmp.h:3361
int __kmp_env_consistency_check
#define SCHEDULE_HAS_NONMONOTONIC(s)
Definition kmp.h:437
static int __kmp_gtid_from_tid(int tid, const kmp_team_t *team)
Definition kmp.h:3617
enum sched_type __kmp_guided
void __kmp_resume_if_soft_paused()
static void __kmp_assert_valid_gtid(kmp_int32 gtid)
Definition kmp.h:3637
kmp_hw_core_type_t
Definition kmp.h:608
@ KMP_HW_CORE_TYPE_UNKNOWN
Definition kmp.h:609
volatile int __kmp_init_serial
static void __kmp_type_convert(T1 src, T2 *dest)
Definition kmp.h:4879
union KMP_ALIGN_CACHE kmp_info kmp_info_t
#define SCHEDULE_NONMONOTONIC
Definition kmp.h:445
KMP_ARCH_X86 KMP_ARCH_X86 long double
KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86<<, 2i, 1, KMP_ARCH_X86) ATOMIC_CMPXCHG(fixed2, shr, kmp_int16, 16, > KMP_ARCH_X86 KMP_ARCH_X86 kmp_uint32
#define KE_TRACE(d, x)
Definition kmp_debug.h:161
#define KMP_ASSERT(cond)
Definition kmp_debug.h:59
#define KMP_BUILD_ASSERT(expr)
Definition kmp_debug.h:26
#define KD_TRACE(d, x)
Definition kmp_debug.h:160
#define KMP_DEBUG_ASSERT(cond)
Definition kmp_debug.h:61
#define KMP_ASSERT2(cond, msg)
Definition kmp_debug.h:60
unsigned long long kmp_uint64
kmp_uint32 __kmp_ge_4(kmp_uint32 value, kmp_uint32 checker)
#define GUIDED_ANALYTICAL_WORKAROUND
#define OMPT_LOOP_END
int __kmp_dispatch_next_algorithm(int gtid, dispatch_private_info_template< T > *pr, dispatch_shared_info_template< T > volatile *sh, kmp_int32 *p_last, T *p_lb, T *p_ub, typename traits_t< T >::signed_t *p_st, T nproc, T tid)
kmp_uint32 __kmp_wait_4(volatile kmp_uint32 *spinner, kmp_uint32 checker, kmp_uint32(*pred)(kmp_uint32, kmp_uint32), void *obj)
void __kmp_wait_4_ptr(void *spinner, kmp_uint32 checker, kmp_uint32(*pred)(void *, kmp_uint32), void *obj)
#define KMP_STATS_LOOP_END
static int __kmp_dispatch_next(ident_t *loc, int gtid, kmp_int32 *p_last, T *p_lb, T *p_ub, typename traits_t< T >::signed_t *p_st)
kmp_uint32 __kmp_eq_4(kmp_uint32 value, kmp_uint32 checker)
void __kmp_initialize_self_buffer(kmp_team_t *team, T id, dispatch_private_info_template< T > *pr, typename traits_t< T >::unsigned_t nchunks, T nproc, typename traits_t< T >::unsigned_t &init, T &small_chunk, T &extras, T &p_extra)
void __kmp_dispatch_deo_error(int *gtid_ref, int *cid_ref, ident_t *loc_ref)
kmp_uint32 __kmp_lt_4(kmp_uint32 value, kmp_uint32 checker)
static void __kmp_dispatch_finish(int gtid, ident_t *loc)
kmp_uint32 __kmp_neq_4(kmp_uint32 value, kmp_uint32 checker)
static void __kmp_dist_get_bounds(ident_t *loc, kmp_int32 gtid, kmp_int32 *plastiter, T *plower, T *pupper, typename traits_t< T >::signed_t incr)
void __kmp_dispatch_init_algorithm(ident_t *loc, int gtid, dispatch_private_info_template< T > *pr, enum sched_type schedule, T lb, T ub, typename traits_t< T >::signed_t st, typename traits_t< T >::signed_t chunk, T nproc, T tid)
kmp_uint32 __kmp_le_4(kmp_uint32 value, kmp_uint32 checker)
void __kmp_dispatch_dxo_error(int *gtid_ref, int *cid_ref, ident_t *loc_ref)
#define OMPT_LOOP_DISPATCH(lb, ub, st, status)
static void __kmp_dispatch_init(ident_t *loc, int gtid, enum sched_type schedule, T lb, T ub, typename traits_t< T >::signed_t st, typename traits_t< T >::signed_t chunk, int push_ws)
static int __kmp_get_monotonicity(ident_t *loc, enum sched_type schedule, bool use_hier=false)
static __inline traits_t< T >::unsigned_t __kmp_dispatch_guided_remaining(T tc, typename traits_t< T >::floating_t base, typename traits_t< T >::unsigned_t idx)
static const int guided_int_param
__forceinline kmp_int32 test_then_inc< kmp_int32 >(volatile kmp_int32 *p)
kmp_uint32 __kmp_eq(T value, T checker)
void __kmp_dispatch_dxo(int *gtid_ref, int *cid_ref, ident_t *loc_ref)
static __forceinline T test_then_inc_acq(volatile T *p)
static __forceinline kmp_int32 compare_and_swap(volatile T *p, T c, T s)
static __forceinline T test_then_inc(volatile T *p)
static __forceinline long double __kmp_pow(long double x, UT y)
static const double guided_flt_param
static __forceinline T test_then_add(volatile T *p, T d)
void __kmp_dispatch_deo(int *gtid_ref, int *cid_ref, ident_t *loc_ref)
UT __kmp_wait(volatile UT *spinner, UT checker, kmp_uint32(*pred)(UT, UT) USE_ITT_BUILD_ARG(void *obj))
kmp_uint32 __kmp_ge(T value, T checker)
void __kmp_dispatch_init_hierarchy(ident_t *loc, int n, kmp_hier_layer_e *new_layers, enum sched_type *new_scheds, typename traits_t< T >::signed_t *new_chunks, T lb, T ub, typename traits_t< T >::signed_t st)
kmp_hier_sched_env_t __kmp_hier_scheds
void __kmp_dispatch_free_hierarchies(kmp_team_t *team)
void __kmp_push_sync(int gtid, enum cons_type ct, ident_t const *ident, kmp_user_lock_p lck)
enum cons_type __kmp_pop_workshare(int gtid, enum cons_type ct, ident_t const *ident)
void __kmp_error_construct(kmp_i18n_id_t id, enum cons_type ct, ident_t const *ident)
void __kmp_pop_sync(int gtid, enum cons_type ct, ident_t const *ident)
static volatile kmp_i18n_cat_status_t status
Definition kmp_i18n.cpp:48
kmp_msg_t __kmp_msg_null
Definition kmp_i18n.cpp:36
void __kmp_fatal(kmp_msg_t message,...)
Definition kmp_i18n.cpp:873
#define KMP_WARNING(...)
Definition kmp_i18n.h:144
#define KMP_MSG(...)
Definition kmp_i18n.h:121
#define KMP_HNT(...)
Definition kmp_i18n.h:122
#define KMP_FSYNC_SPIN_ACQUIRED(obj)
Definition kmp_itt.h:339
#define KMP_FSYNC_SPIN_PREPARE(obj)
Definition kmp_itt.h:338
#define USE_ITT_BUILD_ARG(x)
Definition kmp_itt.h:346
#define KMP_FSYNC_SPIN_INIT(obj, spin)
Definition kmp_itt.h:337
static int __kmp_acquire_lock(kmp_lock_t *lck, kmp_int32 gtid)
Definition kmp_lock.h:559
static void __kmp_init_lock(kmp_lock_t *lck)
Definition kmp_lock.h:571
static void __kmp_destroy_lock(kmp_lock_t *lck)
Definition kmp_lock.h:575
static void __kmp_release_lock(kmp_lock_t *lck, kmp_int32 gtid)
Definition kmp_lock.h:567
kmp_ticket_lock_t kmp_lock_t
Definition kmp_lock.h:555
#define KMP_COMPARE_AND_STORE_REL64(p, cv, sv)
Definition kmp_os.h:864
#define KMP_ATOMIC_ST_REL(p, v)
Definition kmp_os.h:1265
#define RCAST(type, var)
Definition kmp_os.h:294
#define KMP_XCHG_FIXED64(p, v)
Definition kmp_os.h:884
#define KMP_ATOMIC_LD_ACQ(p)
Definition kmp_os.h:1263
#define KMP_ATOMIC_ST_RLX(p, v)
Definition kmp_os.h:1266
#define VOLATILE_CAST(x)
Definition kmp_os.h:1194
#define CCAST(type, var)
Definition kmp_os.h:293
#define KMP_MB()
Definition kmp_os.h:1070
#define TCR_4(a)
Definition kmp_os.h:1141
#define KMP_ATOMIC_LD_RLX(p)
Definition kmp_os.h:1264
Functions for collecting statistics.
#define KMP_COUNT_VALUE(n, v)
Definition kmp_stats.h:1000
#define KMP_PUSH_PARTITIONED_TIMER(name)
Definition kmp_stats.h:1014
#define KMP_POP_PARTITIONED_TIMER()
Definition kmp_stats.h:1015
#define KMP_COUNT_DEVELOPER_VALUE(n, v)
Definition kmp_stats.h:1006
#define KMP_TIME_PARTITIONED_BLOCK(name)
Definition kmp_stats.h:1013
#define KMP_COUNT_BLOCK(n)
Definition kmp_stats.h:1001
char * __kmp_str_format(char const *format,...)
Definition kmp_str.cpp:448
void __kmp_str_free(char **str)
Definition kmp_str.cpp:494
#define i
Definition kmp_stub.cpp:88
#define ST
int a
Definition check.py:1
int32_t kmp_int32
const int chunk_size
omp_lock_t lck
Definition omp_lock.c:7
void init(int &A, int val)
int x[NDEPS]
ompt_callbacks_active_t ompt_enabled
ompt_callbacks_internal_t ompt_callbacks
#define OMPT_GET_RETURN_ADDRESS(level)
ompt_team_info_t * __ompt_get_teaminfo(int depth, int *size)
ompt_task_info_t * __ompt_get_task_info_object(int depth)
static id loc
static int checker
std::atomic< kmp_uint32 > steal_flag
union KMP_ALIGN_CACHE dispatch_private_info_template::private_info_tmpl u
union dispatch_shared_info_template::shared_info_tmpl u
volatile kmp_uint32 buffer_index
unsigned ordered
Definition kmp.h:1897
unsigned use_hier
Definition kmp.h:1900
unsigned use_hybrid
Definition kmp.h:1901
unsigned nomerge
Definition kmp.h:1898
ompt_data_t task_data
ompt_data_t parallel_data
dispatch_private_infoXX_template< T > p
dispatch_shared_infoXX_template< UT > s
kmp_base_team_t t
Definition kmp.h:3227