LLVM OpenMP
kmp_barrier.cpp
Go to the documentation of this file.
1/*
2 * kmp_barrier.cpp
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#include "kmp_wait_release.h"
14#include "kmp_barrier.h"
15#include "kmp_itt.h"
16#include "kmp_os.h"
17#include "kmp_stats.h"
18#include "ompt-specific.h"
19// for distributed barrier
20#include "kmp_affinity.h"
21
22#if KMP_MIC
23#include <immintrin.h>
24#define USE_NGO_STORES 1
25#endif // KMP_MIC
26
27#if KMP_MIC && USE_NGO_STORES
28// ICV copying
29#define ngo_load(src) __m512d Vt = _mm512_load_pd((void *)(src))
30#define ngo_store_icvs(dst, src) _mm512_storenrngo_pd((void *)(dst), Vt)
31#define ngo_store_go(dst, src) _mm512_storenrngo_pd((void *)(dst), Vt)
32#define ngo_sync() __asm__ volatile("lock; addl $0,0(%%rsp)" ::: "memory")
33#else
34#define ngo_load(src) ((void)0)
35#define ngo_store_icvs(dst, src) copy_icvs((dst), (src))
36#define ngo_store_go(dst, src) KMP_MEMCPY((dst), (src), CACHE_LINE)
37#define ngo_sync() ((void)0)
38#endif /* KMP_MIC && USE_NGO_STORES */
39
40void __kmp_print_structure(void); // Forward declaration
41
42// ---------------------------- Barrier Algorithms ----------------------------
43// Distributed barrier
44
45// Compute how many threads to have polling each cache-line.
46// We want to limit the number of writes to IDEAL_GO_RESOLUTION.
47void distributedBarrier::computeVarsForN(size_t n) {
48 int nsockets = 1;
49 if (__kmp_topology) {
50 int socket_level = __kmp_topology->get_level(KMP_HW_SOCKET);
51 int core_level = __kmp_topology->get_level(KMP_HW_CORE);
52 int ncores_per_socket =
53 __kmp_topology->calculate_ratio(core_level, socket_level);
54 nsockets = __kmp_topology->get_count(socket_level);
55
56 if (nsockets <= 0)
57 nsockets = 1;
58 if (ncores_per_socket <= 0)
59 ncores_per_socket = 1;
60
61 threads_per_go = ncores_per_socket >> 1;
62 if (!fix_threads_per_go) {
63 // Minimize num_gos
64 if (threads_per_go > 4) {
67 }
68 if (threads_per_go > 4 && nsockets == 1)
70 }
71 }
72 if (threads_per_go == 0)
74 fix_threads_per_go = true;
76 if (n % threads_per_go)
77 num_gos++;
78 if (nsockets == 1 || num_gos == 1)
79 num_groups = 1;
80 else {
81 num_groups = num_gos / nsockets;
82 if (num_gos % nsockets)
83 num_groups++;
84 }
85 if (num_groups <= 0)
86 num_groups = 1;
88 if (num_gos % num_groups)
91 } else {
93 if (n % threads_per_go)
94 num_gos++;
95 if (num_gos == 1)
96 num_groups = 1;
97 else {
98 num_groups = num_gos / 2;
99 if (num_gos % 2)
100 num_groups++;
101 }
103 if (num_gos % num_groups)
106 }
107}
108
109void distributedBarrier::computeGo(size_t n) {
110 // Minimize num_gos
111 for (num_gos = 1;; num_gos++)
112 if (IDEAL_CONTENTION * num_gos >= n)
113 break;
115 if (n % num_gos)
117 while (num_gos > MAX_GOS) {
120 if (n % threads_per_go)
121 num_gos++;
122 }
123 computeVarsForN(n);
124}
125
126// This function is to resize the barrier arrays when the new number of threads
127// exceeds max_threads, which is the current size of all the arrays
128void distributedBarrier::resize(size_t nthr) {
130
131 // expand to requested size * 2
132 max_threads = nthr * 2;
133
134 // allocate arrays to new max threads
135 for (int i = 0; i < MAX_ITERS; ++i) {
136 if (flags[i])
137 flags[i] = (flags_s *)KMP_INTERNAL_REALLOC(flags[i],
138 max_threads * sizeof(flags_s));
139 else
140 flags[i] = (flags_s *)KMP_INTERNAL_MALLOC(max_threads * sizeof(flags_s));
141 }
142
143 if (go)
144 go = (go_s *)KMP_INTERNAL_REALLOC(go, max_threads * sizeof(go_s));
145 else
146 go = (go_s *)KMP_INTERNAL_MALLOC(max_threads * sizeof(go_s));
147
148 if (iter)
149 iter = (iter_s *)KMP_INTERNAL_REALLOC(iter, max_threads * sizeof(iter_s));
150 else
151 iter = (iter_s *)KMP_INTERNAL_MALLOC(max_threads * sizeof(iter_s));
152
153 if (sleep)
154 sleep =
155 (sleep_s *)KMP_INTERNAL_REALLOC(sleep, max_threads * sizeof(sleep_s));
156 else
157 sleep = (sleep_s *)KMP_INTERNAL_MALLOC(max_threads * sizeof(sleep_s));
158}
159
160// This function is to set all the go flags that threads might be waiting
161// on, and when blocktime is not infinite, it should be followed by a wake-up
162// call to each thread
165 for (size_t j = 0; j < num_gos; j++) {
166 go[j].go.store(next_go);
167 }
168 return next_go;
169}
170
172 for (size_t j = 0; j < max_threads; ++j) {
173 for (size_t i = 0; i < distributedBarrier::MAX_ITERS; ++i) {
174 flags[i][j].stillNeed.store(1, std::memory_order_relaxed);
175 }
176 go[j].go.store(0);
177 iter[j].iter = 0;
178 }
179}
180
181// This function inits/re-inits the distributed barrier for a particular number
182// of threads. If a resize of arrays is needed, it calls the resize function.
183void distributedBarrier::init(size_t nthr) {
184 size_t old_max = max_threads;
185 if (nthr > max_threads) { // need more space in arrays
186 resize(nthr);
187 }
188
189 for (size_t i = 0; i < max_threads; i++) {
190 for (size_t j = 0; j < distributedBarrier::MAX_ITERS; j++) {
191 flags[j][i].stillNeed.store(1, std::memory_order_relaxed);
192 }
193 go[i].go.store(0);
194 iter[i].iter = 0;
195 if (i >= old_max)
196 sleep[i].sleep = false;
197 }
198
199 // Recalculate num_gos, etc. based on new nthr
200 computeVarsForN(nthr);
201
202 num_threads = nthr;
203
204 if (team_icvs == NULL)
206}
207
209 for (int i = 0; i < MAX_ITERS; ++i) {
210 if (db->flags[i])
212 db->flags[i] = NULL;
213 }
214 if (db->go) {
216 db->go = NULL;
217 }
218 if (db->iter) {
220 db->iter = NULL;
221 }
222 if (db->sleep) {
224 db->sleep = NULL;
225 }
226 if (db->team_icvs) {
228 db->team_icvs = NULL;
229 }
231}
232
233// This function is used only when KMP_BLOCKTIME is not infinite.
234// static
236 size_t start, size_t stop, size_t inc,
237 size_t tid) {
239 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
240 return;
241
242 kmp_info_t **other_threads = team->t.t_threads;
243 for (size_t thr = start; thr < stop; thr += inc) {
244 KMP_DEBUG_ASSERT(other_threads[thr]);
245 int gtid = other_threads[thr]->th.th_info.ds.ds_gtid;
246 // Wake up worker regardless of if it appears to be sleeping or not
248 }
249}
250
252 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
253 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
255 kmp_team_t *team;
257 kmp_info_t **other_threads;
258 kmp_uint64 my_current_iter, my_next_iter;
259 kmp_uint32 nproc;
260 bool group_leader;
261
262 team = this_thr->th.th_team;
263 nproc = this_thr->th.th_team_nproc;
264 other_threads = team->t.t_threads;
265 b = team->t.b;
266 my_current_iter = b->iter[tid].iter;
267 my_next_iter = (my_current_iter + 1) % distributedBarrier::MAX_ITERS;
268 group_leader = ((tid % b->threads_per_group) == 0);
269
270 KA_TRACE(20,
271 ("__kmp_dist_barrier_gather: T#%d(%d:%d) enter; barrier type %d\n",
272 gtid, team->t.t_id, tid, bt));
273
274#if USE_ITT_BUILD && USE_ITT_NOTIFY
275 // Barrier imbalance - save arrive time to the thread
276 if (__kmp_forkjoin_frames_mode == 3 || __kmp_forkjoin_frames_mode == 2) {
277 this_thr->th.th_bar_arrive_time = this_thr->th.th_bar_min_time =
278 __itt_get_timestamp();
279 }
280#endif
281
282 if (group_leader) {
283 // Start from the thread after the group leader
284 size_t group_start = tid + 1;
285 size_t group_end = tid + b->threads_per_group;
286 size_t threads_pending = 0;
287
288 if (group_end > nproc)
289 group_end = nproc;
290 do { // wait for threads in my group
291 threads_pending = 0;
292 // Check all the flags every time to avoid branch misspredict
293 for (size_t thr = group_start; thr < group_end; thr++) {
294 // Each thread uses a different cache line. Use relaxed loads while
295 // polling; the acquire is performed once after the loop observes that
296 // all threads have arrived.
297 threads_pending += b->flags[my_current_iter][thr].stillNeed.load(
298 std::memory_order_relaxed);
299 }
300 // Execute tasks here
302 kmp_task_team_t *task_team = this_thr->th.th_task_team;
303 if (task_team != NULL) {
304 if (TCR_SYNC_4(task_team->tt.tt_active)) {
305 if (KMP_TASKING_ENABLED(task_team)) {
306 int tasks_completed = FALSE;
308 this_thr, gtid, (kmp_atomic_flag_64<> *)NULL, FALSE,
309 &tasks_completed USE_ITT_BUILD_ARG(itt_sync_obj), 0);
310 } else
311 this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
312 }
313 } else {
314 this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
315 } // if
316 }
317 if (TCR_4(__kmp_global.g.g_done)) {
318 if (__kmp_global.g.g_abort)
320 break;
322 this_thr->th.th_reap_state == KMP_SAFE_TO_REAP) {
323 this_thr->th.th_reap_state = KMP_NOT_SAFE_TO_REAP;
324 }
325 } while (threads_pending > 0);
326 // Acquire: now that all monitored stillNeed=0 stores are observed, make the
327 // arrived threads' pre-barrier writes (incl. reduce_data) visible here.
328 std::atomic_thread_fence(std::memory_order_acquire);
329
330 if (reduce) { // Perform reduction if needed
331 OMPT_REDUCTION_DECL(this_thr, gtid);
333 // Group leader reduces all threads in group
334 for (size_t thr = group_start; thr < group_end; thr++) {
335 (*reduce)(this_thr->th.th_local.reduce_data,
336 other_threads[thr]->th.th_local.reduce_data);
337 }
339 }
340
341 // Set flag for next iteration
342 b->flags[my_next_iter][tid].stillNeed.store(1, std::memory_order_relaxed);
343 // Each thread uses a different cache line; resets stillNeed to 0 to
344 // indicate it has reached the barrier. Release so that this thread's
345 // pre-barrier writes are visible to whoever observes the 0.
346 b->flags[my_current_iter][tid].stillNeed.store(0,
347 std::memory_order_release);
348
349 do { // wait for all group leaders
350 threads_pending = 0;
351 for (size_t thr = 0; thr < nproc; thr += b->threads_per_group) {
352 threads_pending += b->flags[my_current_iter][thr].stillNeed.load(
353 std::memory_order_relaxed);
354 }
355 // Execute tasks here
357 kmp_task_team_t *task_team = this_thr->th.th_task_team;
358 if (task_team != NULL) {
359 if (TCR_SYNC_4(task_team->tt.tt_active)) {
360 if (KMP_TASKING_ENABLED(task_team)) {
361 int tasks_completed = FALSE;
363 this_thr, gtid, (kmp_atomic_flag_64<> *)NULL, FALSE,
364 &tasks_completed USE_ITT_BUILD_ARG(itt_sync_obj), 0);
365 } else
366 this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
367 }
368 } else {
369 this_thr->th.th_reap_state = KMP_SAFE_TO_REAP;
370 } // if
371 }
372 if (TCR_4(__kmp_global.g.g_done)) {
373 if (__kmp_global.g.g_abort)
375 break;
377 this_thr->th.th_reap_state == KMP_SAFE_TO_REAP) {
378 this_thr->th.th_reap_state = KMP_NOT_SAFE_TO_REAP;
379 }
380 } while (threads_pending > 0);
381 // Acquire: pair with the group leaders' releasing stillNeed=0 stores.
382 std::atomic_thread_fence(std::memory_order_acquire);
383
384 if (reduce) { // Perform reduction if needed
385 if (KMP_MASTER_TID(tid)) { // Master reduces over group leaders
386 OMPT_REDUCTION_DECL(this_thr, gtid);
388 for (size_t thr = b->threads_per_group; thr < nproc;
389 thr += b->threads_per_group) {
390 (*reduce)(this_thr->th.th_local.reduce_data,
391 other_threads[thr]->th.th_local.reduce_data);
392 }
394 }
395 }
396 } else {
397 // Set flag for next iteration
398 b->flags[my_next_iter][tid].stillNeed.store(1, std::memory_order_relaxed);
399 // Each thread uses a different cache line; resets stillNeed to 0 to
400 // indicate it has reached the barrier. Release so that this thread's
401 // pre-barrier writes are visible to whoever observes the 0.
402 b->flags[my_current_iter][tid].stillNeed.store(0,
403 std::memory_order_release);
404 }
405
406 KMP_MFENCE();
407
408 KA_TRACE(20,
409 ("__kmp_dist_barrier_gather: T#%d(%d:%d) exit for barrier type %d\n",
410 gtid, team->t.t_id, tid, bt));
411}
412
414 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
415 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
416 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_dist_release);
417 kmp_team_t *team;
419 kmp_bstate_t *thr_bar;
420 kmp_uint64 my_current_iter, next_go;
421 size_t my_go_index;
422 bool group_leader;
423
424 KA_TRACE(20, ("__kmp_dist_barrier_release: T#%d(%d) enter; barrier type %d\n",
425 gtid, tid, bt));
426
427 thr_bar = &this_thr->th.th_bar[bt].bb;
428
429 if (!KMP_MASTER_TID(tid)) {
430 // workers and non-master group leaders need to check their presence in team
431 do {
432 if (this_thr->th.th_used_in_team.load() != 1 &&
433 this_thr->th.th_used_in_team.load() != 3) {
434 // Thread is not in use in a team. Wait on location in tid's thread
435 // struct. The 0 value tells anyone looking that this thread is spinning
436 // or sleeping until this location becomes 3 again; 3 is the transition
437 // state to get to 1 which is waiting on go and being in the team
438 kmp_flag_32<false, false> my_flag(&(this_thr->th.th_used_in_team), 3);
439 if (KMP_COMPARE_AND_STORE_ACQ32(&(this_thr->th.th_used_in_team), 2,
440 0) ||
441 this_thr->th.th_used_in_team.load() == 0) {
442 my_flag.wait(this_thr, true USE_ITT_BUILD_ARG(itt_sync_obj));
443 }
444#if USE_ITT_BUILD && USE_ITT_NOTIFY
445 if ((__itt_sync_create_ptr && itt_sync_obj == NULL) || KMP_ITT_DEBUG) {
446 // In fork barrier where we could not get the object reliably
447 itt_sync_obj =
448 __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier, 0, -1);
449 // Cancel wait on previous parallel region...
450 __kmp_itt_task_starting(itt_sync_obj);
451
452 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
453 return;
454
455 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
456 if (itt_sync_obj != NULL)
457 // Call prepare as early as possible for "new" barrier
458 __kmp_itt_task_finished(itt_sync_obj);
459 } else
460#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
461 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
462 return;
463 }
464 if (this_thr->th.th_used_in_team.load() != 1 &&
465 this_thr->th.th_used_in_team.load() != 3) // spurious wake-up?
466 continue;
467 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
468 return;
469
470 // At this point, the thread thinks it is in use in a team, or in
471 // transition to be used in a team, but it might have reached this barrier
472 // before it was marked unused by the team. Unused threads are awoken and
473 // shifted to wait on local thread struct elsewhere. It also might reach
474 // this point by being picked up for use by a different team. Either way,
475 // we need to update the tid.
476 tid = __kmp_tid_from_gtid(gtid);
477 team = this_thr->th.th_team;
478 KMP_DEBUG_ASSERT(tid >= 0);
479 KMP_DEBUG_ASSERT(team);
480 b = team->t.b;
481 my_current_iter = b->iter[tid].iter;
482 next_go = my_current_iter + distributedBarrier::MAX_ITERS;
483 my_go_index = tid / b->threads_per_go;
484 if (this_thr->th.th_used_in_team.load() == 3) {
485 (void)KMP_COMPARE_AND_STORE_ACQ32(&(this_thr->th.th_used_in_team), 3,
486 1);
487 }
488 // Check if go flag is set
489 if (b->go[my_go_index].go.load() != next_go) {
490 // Wait on go flag on team
492 &(b->go[my_go_index].go), next_go, &(b->sleep[tid].sleep));
493 my_flag.wait(this_thr, true USE_ITT_BUILD_ARG(itt_sync_obj));
494 KMP_DEBUG_ASSERT(my_current_iter == b->iter[tid].iter ||
495 b->iter[tid].iter == 0);
496 KMP_DEBUG_ASSERT(b->sleep[tid].sleep == false);
497 }
498
499 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
500 return;
501 // At this point, the thread's go location was set. This means the primary
502 // thread is safely in the barrier, and so this thread's data is
503 // up-to-date, but we should check again that this thread is really in
504 // use in the team, as it could have been woken up for the purpose of
505 // changing team size, or reaping threads at shutdown.
506 if (this_thr->th.th_used_in_team.load() == 1)
507 break;
508 } while (1);
509
510 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
511 return;
512
513 group_leader = ((tid % b->threads_per_group) == 0);
514 if (group_leader) {
515 // Tell all the threads in my group they can go!
516 for (size_t go_idx = my_go_index + 1;
517 go_idx < my_go_index + b->gos_per_group; go_idx++) {
518 b->go[go_idx].go.store(next_go);
519 }
520 // Fence added so that workers can see changes to go. sfence inadequate.
521 KMP_MFENCE();
522 }
523
524#if KMP_BARRIER_ICV_PUSH
525 if (propagate_icvs) { // copy ICVs to final dest
526 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[tid], team,
527 tid, FALSE);
528 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
529 (kmp_internal_control_t *)team->t.b->team_icvs);
530 copy_icvs(&thr_bar->th_fixed_icvs,
531 &team->t.t_implicit_task_taskdata[tid].td_icvs);
532 }
533#endif
534 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME && group_leader) {
535 // This thread is now awake and participating in the barrier;
536 // wake up the other threads in the group
537 size_t nproc = this_thr->th.th_team_nproc;
538 size_t group_end = tid + b->threads_per_group;
539 if (nproc < group_end)
540 group_end = nproc;
541 __kmp_dist_barrier_wakeup(bt, team, tid + 1, group_end, 1, tid);
542 }
543 } else { // Primary thread
544 team = this_thr->th.th_team;
545 b = team->t.b;
546 my_current_iter = b->iter[tid].iter;
547 next_go = my_current_iter + distributedBarrier::MAX_ITERS;
548#if KMP_BARRIER_ICV_PUSH
549 if (propagate_icvs) {
550 // primary thread has ICVs in final destination; copy
551 copy_icvs(&thr_bar->th_fixed_icvs,
552 &team->t.t_implicit_task_taskdata[tid].td_icvs);
553 }
554#endif
555 // Tell all the group leaders they can go!
556 for (size_t go_idx = 0; go_idx < b->num_gos; go_idx += b->gos_per_group) {
557 b->go[go_idx].go.store(next_go);
558 }
559
561 // Wake-up the group leaders
562 size_t nproc = this_thr->th.th_team_nproc;
563 __kmp_dist_barrier_wakeup(bt, team, tid + b->threads_per_group, nproc,
564 b->threads_per_group, tid);
565 }
566
567 // Tell all the threads in my group they can go!
568 for (size_t go_idx = 1; go_idx < b->gos_per_group; go_idx++) {
569 b->go[go_idx].go.store(next_go);
570 }
571
572 // Fence added so that workers can see changes to go. sfence inadequate.
573 KMP_MFENCE();
574
576 // Wake-up the other threads in my group
577 size_t nproc = this_thr->th.th_team_nproc;
578 size_t group_end = tid + b->threads_per_group;
579 if (nproc < group_end)
580 group_end = nproc;
581 __kmp_dist_barrier_wakeup(bt, team, tid + 1, group_end, 1, tid);
582 }
583 }
584 // Update to next iteration
585 KMP_ASSERT(my_current_iter == b->iter[tid].iter);
586 b->iter[tid].iter = (b->iter[tid].iter + 1) % distributedBarrier::MAX_ITERS;
587
588 KA_TRACE(
589 20, ("__kmp_dist_barrier_release: T#%d(%d:%d) exit for barrier type %d\n",
590 gtid, team->t.t_id, tid, bt));
591}
592
593// Linear Barrier
594template <bool cancellable = false>
596 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
597 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
598 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_linear_gather);
599 kmp_team_t *team = this_thr->th.th_team;
600 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
601 kmp_info_t **other_threads = team->t.t_threads;
602
603 KA_TRACE(
604 20,
605 ("__kmp_linear_barrier_gather: T#%d(%d:%d) enter for barrier type %d\n",
606 gtid, team->t.t_id, tid, bt));
607 KMP_DEBUG_ASSERT(this_thr == other_threads[this_thr->th.th_info.ds.ds_tid]);
608
609#if USE_ITT_BUILD && USE_ITT_NOTIFY
610 // Barrier imbalance - save arrive time to the thread
611 if (__kmp_forkjoin_frames_mode == 3 || __kmp_forkjoin_frames_mode == 2) {
612 this_thr->th.th_bar_arrive_time = this_thr->th.th_bar_min_time =
613 __itt_get_timestamp();
614 }
615#endif
616 // We now perform a linear reduction to signal that all of the threads have
617 // arrived.
618 if (!KMP_MASTER_TID(tid)) {
619 KA_TRACE(20,
620 ("__kmp_linear_barrier_gather: T#%d(%d:%d) releasing T#%d(%d:%d)"
621 "arrived(%p): %llu => %llu\n",
622 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(0, team),
623 team->t.t_id, 0, &thr_bar->b_arrived, thr_bar->b_arrived,
624 thr_bar->b_arrived + KMP_BARRIER_STATE_BUMP));
625 // Mark arrival to primary thread
626 /* After performing this write, a worker thread may not assume that the team
627 is valid any more - it could be deallocated by the primary thread at any
628 time. */
629 kmp_flag_64<> flag(&thr_bar->b_arrived, other_threads[0]);
630 flag.release();
631 } else {
632 kmp_balign_team_t *team_bar = &team->t.t_bar[bt];
633 int nproc = this_thr->th.th_team_nproc;
634 int i;
635 // Don't have to worry about sleep bit here or atomic since team setting
636 kmp_uint64 new_state = team_bar->b_arrived + KMP_BARRIER_STATE_BUMP;
637
638 // Collect all the worker team member threads.
639 for (i = 1; i < nproc; ++i) {
640#if KMP_CACHE_MANAGE
641 // Prefetch next thread's arrived count
642 if (i + 1 < nproc)
643 KMP_CACHE_PREFETCH(&other_threads[i + 1]->th.th_bar[bt].bb.b_arrived);
644#endif /* KMP_CACHE_MANAGE */
645 KA_TRACE(20, ("__kmp_linear_barrier_gather: T#%d(%d:%d) wait T#%d(%d:%d) "
646 "arrived(%p) == %llu\n",
647 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(i, team),
648 team->t.t_id, i,
649 &other_threads[i]->th.th_bar[bt].bb.b_arrived, new_state));
650
651 // Wait for worker thread to arrive
652 if (cancellable) {
654 &other_threads[i]->th.th_bar[bt].bb.b_arrived, new_state);
655 if (flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj)))
656 return true;
657 } else {
658 kmp_flag_64<> flag(&other_threads[i]->th.th_bar[bt].bb.b_arrived,
659 new_state);
660 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
661 }
662#if USE_ITT_BUILD && USE_ITT_NOTIFY
663 // Barrier imbalance - write min of the thread time and the other thread
664 // time to the thread.
665 if (__kmp_forkjoin_frames_mode == 2) {
666 this_thr->th.th_bar_min_time = KMP_MIN(
667 this_thr->th.th_bar_min_time, other_threads[i]->th.th_bar_min_time);
668 }
669#endif
670 if (reduce) {
671 KA_TRACE(100,
672 ("__kmp_linear_barrier_gather: T#%d(%d:%d) += T#%d(%d:%d)\n",
673 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(i, team),
674 team->t.t_id, i));
675 OMPT_REDUCTION_DECL(this_thr, gtid);
677 (*reduce)(this_thr->th.th_local.reduce_data,
678 other_threads[i]->th.th_local.reduce_data);
680 }
681 }
682 // Don't have to worry about sleep bit here or atomic since team setting
683 team_bar->b_arrived = new_state;
684 KA_TRACE(20, ("__kmp_linear_barrier_gather: T#%d(%d:%d) set team %d "
685 "arrived(%p) = %llu\n",
686 gtid, team->t.t_id, tid, team->t.t_id, &team_bar->b_arrived,
687 new_state));
688 }
689 KA_TRACE(
690 20,
691 ("__kmp_linear_barrier_gather: T#%d(%d:%d) exit for barrier type %d\n",
692 gtid, team->t.t_id, tid, bt));
693 return false;
694}
695
696template <bool cancellable = false>
698 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
699 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
700 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_linear_release);
701 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
702 kmp_team_t *team;
703
704 if (KMP_MASTER_TID(tid)) {
705 unsigned int i;
706 kmp_uint32 nproc = this_thr->th.th_team_nproc;
707 kmp_info_t **other_threads;
708
709 team = __kmp_threads[gtid]->th.th_team;
710 KMP_DEBUG_ASSERT(team != NULL);
711 other_threads = team->t.t_threads;
712
713 KA_TRACE(20, ("__kmp_linear_barrier_release: T#%d(%d:%d) primary enter for "
714 "barrier type %d\n",
715 gtid, team->t.t_id, tid, bt));
716
717 if (nproc > 1) {
718#if KMP_BARRIER_ICV_PUSH
719 {
721 if (propagate_icvs) {
722 ngo_load(&team->t.t_implicit_task_taskdata[0].td_icvs);
723 for (i = 1; i < nproc; ++i) {
724 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[i],
725 team, i, FALSE);
726 ngo_store_icvs(&team->t.t_implicit_task_taskdata[i].td_icvs,
727 &team->t.t_implicit_task_taskdata[0].td_icvs);
728 }
729 ngo_sync();
730 }
731 }
732#endif // KMP_BARRIER_ICV_PUSH
733
734 // Now, release all of the worker threads
735 for (i = 1; i < nproc; ++i) {
736#if KMP_CACHE_MANAGE
737 // Prefetch next thread's go flag
738 if (i + 1 < nproc)
739 KMP_CACHE_PREFETCH(&other_threads[i + 1]->th.th_bar[bt].bb.b_go);
740#endif /* KMP_CACHE_MANAGE */
741 KA_TRACE(
742 20,
743 ("__kmp_linear_barrier_release: T#%d(%d:%d) releasing T#%d(%d:%d) "
744 "go(%p): %u => %u\n",
745 gtid, team->t.t_id, tid, other_threads[i]->th.th_info.ds.ds_gtid,
746 team->t.t_id, i, &other_threads[i]->th.th_bar[bt].bb.b_go,
747 other_threads[i]->th.th_bar[bt].bb.b_go,
748 other_threads[i]->th.th_bar[bt].bb.b_go + KMP_BARRIER_STATE_BUMP));
749 kmp_flag_64<> flag(&other_threads[i]->th.th_bar[bt].bb.b_go,
750 other_threads[i]);
751 flag.release();
752 }
753 }
754 } else { // Wait for the PRIMARY thread to release us
755 KA_TRACE(20, ("__kmp_linear_barrier_release: T#%d wait go(%p) == %u\n",
756 gtid, &thr_bar->b_go, KMP_BARRIER_STATE_BUMP));
757 if (cancellable) {
759 if (flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj)))
760 return true;
761 } else {
763 flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
764 }
765#if USE_ITT_BUILD && USE_ITT_NOTIFY
766 if ((__itt_sync_create_ptr && itt_sync_obj == NULL) || KMP_ITT_DEBUG) {
767 // In a fork barrier; cannot get the object reliably (or ITTNOTIFY is
768 // disabled)
769 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier, 0, -1);
770 // Cancel wait on previous parallel region...
771 __kmp_itt_task_starting(itt_sync_obj);
772
773 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
774 return false;
775
776 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
777 if (itt_sync_obj != NULL)
778 // Call prepare as early as possible for "new" barrier
779 __kmp_itt_task_finished(itt_sync_obj);
780 } else
781#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
782 // Early exit for reaping threads releasing forkjoin barrier
783 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
784 return false;
785// The worker thread may now assume that the team is valid.
786#ifdef KMP_DEBUG
787 tid = __kmp_tid_from_gtid(gtid);
788 team = __kmp_threads[gtid]->th.th_team;
789#endif
790 KMP_DEBUG_ASSERT(team != NULL);
791 TCW_4(thr_bar->b_go, KMP_INIT_BARRIER_STATE);
792 KA_TRACE(20,
793 ("__kmp_linear_barrier_release: T#%d(%d:%d) set go(%p) = %u\n",
794 gtid, team->t.t_id, tid, &thr_bar->b_go, KMP_INIT_BARRIER_STATE));
795 KMP_MB(); // Flush all pending memory write invalidates.
796 }
797 KA_TRACE(
798 20,
799 ("__kmp_linear_barrier_release: T#%d(%d:%d) exit for barrier type %d\n",
800 gtid, team->t.t_id, tid, bt));
801 return false;
802}
803
805 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
806 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
808 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
809}
810
812 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
813 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
815 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
816}
817
819 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
820 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
822 bt, this_thr, gtid, tid, propagate_icvs USE_ITT_BUILD_ARG(itt_sync_obj));
823}
824
826 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
827 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
829 bt, this_thr, gtid, tid, propagate_icvs USE_ITT_BUILD_ARG(itt_sync_obj));
830}
831
832// Tree barrier
834 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
835 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
837 kmp_team_t *team = this_thr->th.th_team;
838 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
839 kmp_info_t **other_threads = team->t.t_threads;
840 kmp_uint32 nproc = this_thr->th.th_team_nproc;
842 kmp_uint32 branch_factor = 1 << branch_bits;
843 kmp_uint32 child;
844 kmp_uint32 child_tid;
845 kmp_uint64 new_state = 0;
846
847 KA_TRACE(
848 20, ("__kmp_tree_barrier_gather: T#%d(%d:%d) enter for barrier type %d\n",
849 gtid, team->t.t_id, tid, bt));
850 KMP_DEBUG_ASSERT(this_thr == other_threads[this_thr->th.th_info.ds.ds_tid]);
851
852#if USE_ITT_BUILD && USE_ITT_NOTIFY
853 // Barrier imbalance - save arrive time to the thread
854 if (__kmp_forkjoin_frames_mode == 3 || __kmp_forkjoin_frames_mode == 2) {
855 this_thr->th.th_bar_arrive_time = this_thr->th.th_bar_min_time =
856 __itt_get_timestamp();
857 }
858#endif
859 // Perform tree gather to wait until all threads have arrived; reduce any
860 // required data as we go
861 child_tid = (tid << branch_bits) + 1;
862 if (child_tid < nproc) {
863 // Parent threads wait for all their children to arrive
864 new_state = team->t.t_bar[bt].b_arrived + KMP_BARRIER_STATE_BUMP;
865 child = 1;
866 do {
867 kmp_info_t *child_thr = other_threads[child_tid];
868 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
869#if KMP_CACHE_MANAGE
870 // Prefetch next thread's arrived count
871 if (child + 1 <= branch_factor && child_tid + 1 < nproc)
873 &other_threads[child_tid + 1]->th.th_bar[bt].bb.b_arrived);
874#endif /* KMP_CACHE_MANAGE */
875 KA_TRACE(20,
876 ("__kmp_tree_barrier_gather: T#%d(%d:%d) wait T#%d(%d:%u) "
877 "arrived(%p) == %llu\n",
878 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
879 team->t.t_id, child_tid, &child_bar->b_arrived, new_state));
880 // Wait for child to arrive
881 kmp_flag_64<> flag(&child_bar->b_arrived, new_state);
882 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
883#if USE_ITT_BUILD && USE_ITT_NOTIFY
884 // Barrier imbalance - write min of the thread time and a child time to
885 // the thread.
886 if (__kmp_forkjoin_frames_mode == 2) {
887 this_thr->th.th_bar_min_time = KMP_MIN(this_thr->th.th_bar_min_time,
888 child_thr->th.th_bar_min_time);
889 }
890#endif
891 if (reduce) {
892 KA_TRACE(100,
893 ("__kmp_tree_barrier_gather: T#%d(%d:%d) += T#%d(%d:%u)\n",
894 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
895 team->t.t_id, child_tid));
896 OMPT_REDUCTION_DECL(this_thr, gtid);
898 (*reduce)(this_thr->th.th_local.reduce_data,
899 child_thr->th.th_local.reduce_data);
901 }
902 child++;
903 child_tid++;
904 } while (child <= branch_factor && child_tid < nproc);
905 }
906
907 if (!KMP_MASTER_TID(tid)) { // Worker threads
908 kmp_int32 parent_tid = (tid - 1) >> branch_bits;
909
910 KA_TRACE(20,
911 ("__kmp_tree_barrier_gather: T#%d(%d:%d) releasing T#%d(%d:%d) "
912 "arrived(%p): %llu => %llu\n",
913 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(parent_tid, team),
914 team->t.t_id, parent_tid, &thr_bar->b_arrived, thr_bar->b_arrived,
915 thr_bar->b_arrived + KMP_BARRIER_STATE_BUMP));
916
917 // Mark arrival to parent thread
918 /* After performing this write, a worker thread may not assume that the team
919 is valid any more - it could be deallocated by the primary thread at any
920 time. */
921 kmp_flag_64<> flag(&thr_bar->b_arrived, other_threads[parent_tid]);
922 flag.release();
923 } else {
924 // Need to update the team arrived pointer if we are the primary thread
925 if (nproc > 1) // New value was already computed above
926 team->t.t_bar[bt].b_arrived = new_state;
927 else
928 team->t.t_bar[bt].b_arrived += KMP_BARRIER_STATE_BUMP;
929 KA_TRACE(20, ("__kmp_tree_barrier_gather: T#%d(%d:%d) set team %d "
930 "arrived(%p) = %llu\n",
931 gtid, team->t.t_id, tid, team->t.t_id,
932 &team->t.t_bar[bt].b_arrived, team->t.t_bar[bt].b_arrived));
933 }
934 KA_TRACE(20,
935 ("__kmp_tree_barrier_gather: T#%d(%d:%d) exit for barrier type %d\n",
936 gtid, team->t.t_id, tid, bt));
937}
938
940 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
941 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
942 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_tree_release);
943 kmp_team_t *team;
944 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
945 kmp_uint32 nproc;
947 kmp_uint32 branch_factor = 1 << branch_bits;
948 kmp_uint32 child;
949 kmp_uint32 child_tid;
950
951 // Perform a tree release for all of the threads that have been gathered
952 if (!KMP_MASTER_TID(
953 tid)) { // Handle fork barrier workers who aren't part of a team yet
954 KA_TRACE(20, ("__kmp_tree_barrier_release: T#%d wait go(%p) == %u\n", gtid,
955 &thr_bar->b_go, KMP_BARRIER_STATE_BUMP));
956 // Wait for parent thread to release us
958 flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
959#if USE_ITT_BUILD && USE_ITT_NOTIFY
960 if ((__itt_sync_create_ptr && itt_sync_obj == NULL) || KMP_ITT_DEBUG) {
961 // In fork barrier where we could not get the object reliably (or
962 // ITTNOTIFY is disabled)
963 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier, 0, -1);
964 // Cancel wait on previous parallel region...
965 __kmp_itt_task_starting(itt_sync_obj);
966
967 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
968 return;
969
970 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
971 if (itt_sync_obj != NULL)
972 // Call prepare as early as possible for "new" barrier
973 __kmp_itt_task_finished(itt_sync_obj);
974 } else
975#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
976 // Early exit for reaping threads releasing forkjoin barrier
977 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
978 return;
979
980 // The worker thread may now assume that the team is valid.
981 team = __kmp_threads[gtid]->th.th_team;
982 KMP_DEBUG_ASSERT(team != NULL);
983 tid = __kmp_tid_from_gtid(gtid);
984
985 TCW_4(thr_bar->b_go, KMP_INIT_BARRIER_STATE);
986 KA_TRACE(20,
987 ("__kmp_tree_barrier_release: T#%d(%d:%d) set go(%p) = %u\n", gtid,
988 team->t.t_id, tid, &thr_bar->b_go, KMP_INIT_BARRIER_STATE));
989 KMP_MB(); // Flush all pending memory write invalidates.
990 } else {
991 team = __kmp_threads[gtid]->th.th_team;
992 KMP_DEBUG_ASSERT(team != NULL);
993 KA_TRACE(20, ("__kmp_tree_barrier_release: T#%d(%d:%d) primary enter for "
994 "barrier type %d\n",
995 gtid, team->t.t_id, tid, bt));
996 }
997 nproc = this_thr->th.th_team_nproc;
998 child_tid = (tid << branch_bits) + 1;
999
1000 if (child_tid < nproc) {
1001 kmp_info_t **other_threads = team->t.t_threads;
1002 child = 1;
1003 // Parent threads release all their children
1004 do {
1005 kmp_info_t *child_thr = other_threads[child_tid];
1006 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1007#if KMP_CACHE_MANAGE
1008 // Prefetch next thread's go count
1009 if (child + 1 <= branch_factor && child_tid + 1 < nproc)
1011 &other_threads[child_tid + 1]->th.th_bar[bt].bb.b_go);
1012#endif /* KMP_CACHE_MANAGE */
1013
1014#if KMP_BARRIER_ICV_PUSH
1015 {
1017 if (propagate_icvs) {
1018 __kmp_init_implicit_task(team->t.t_ident,
1019 team->t.t_threads[child_tid], team,
1020 child_tid, FALSE);
1021 copy_icvs(&team->t.t_implicit_task_taskdata[child_tid].td_icvs,
1022 &team->t.t_implicit_task_taskdata[0].td_icvs);
1023 }
1024 }
1025#endif // KMP_BARRIER_ICV_PUSH
1026 KA_TRACE(20,
1027 ("__kmp_tree_barrier_release: T#%d(%d:%d) releasing T#%d(%d:%u)"
1028 "go(%p): %u => %u\n",
1029 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
1030 team->t.t_id, child_tid, &child_bar->b_go, child_bar->b_go,
1031 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1032 // Release child from barrier
1033 kmp_flag_64<> flag(&child_bar->b_go, child_thr);
1034 flag.release();
1035 child++;
1036 child_tid++;
1037 } while (child <= branch_factor && child_tid < nproc);
1038 }
1039 KA_TRACE(
1040 20, ("__kmp_tree_barrier_release: T#%d(%d:%d) exit for barrier type %d\n",
1041 gtid, team->t.t_id, tid, bt));
1042}
1043
1044// Hyper Barrier
1046 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
1047 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
1048 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_hyper_gather);
1049 kmp_team_t *team = this_thr->th.th_team;
1050 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
1051 kmp_info_t **other_threads = team->t.t_threads;
1053 kmp_uint32 num_threads = this_thr->th.th_team_nproc;
1055 kmp_uint32 branch_factor = 1 << branch_bits;
1056 kmp_uint32 offset;
1058
1059 KA_TRACE(
1060 20,
1061 ("__kmp_hyper_barrier_gather: T#%d(%d:%d) enter for barrier type %d\n",
1062 gtid, team->t.t_id, tid, bt));
1063 KMP_DEBUG_ASSERT(this_thr == other_threads[this_thr->th.th_info.ds.ds_tid]);
1064
1065#if USE_ITT_BUILD && USE_ITT_NOTIFY
1066 // Barrier imbalance - save arrive time to the thread
1067 if (__kmp_forkjoin_frames_mode == 3 || __kmp_forkjoin_frames_mode == 2) {
1068 this_thr->th.th_bar_arrive_time = this_thr->th.th_bar_min_time =
1069 __itt_get_timestamp();
1070 }
1071#endif
1072 /* Perform a hypercube-embedded tree gather to wait until all of the threads
1073 have arrived, and reduce any required data as we go. */
1074 kmp_flag_64<> p_flag(&thr_bar->b_arrived);
1075 for (level = 0, offset = 1; offset < num_threads;
1076 level += branch_bits, offset <<= branch_bits) {
1077 kmp_uint32 child;
1078 kmp_uint32 child_tid;
1079
1080 if (((tid >> level) & (branch_factor - 1)) != 0) {
1081 kmp_int32 parent_tid = tid & ~((1 << (level + branch_bits)) - 1);
1082
1083 KMP_MB(); // Synchronize parent and child threads.
1084 KA_TRACE(20,
1085 ("__kmp_hyper_barrier_gather: T#%d(%d:%d) releasing T#%d(%d:%d) "
1086 "arrived(%p): %llu => %llu\n",
1087 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(parent_tid, team),
1088 team->t.t_id, parent_tid, &thr_bar->b_arrived,
1089 thr_bar->b_arrived,
1090 thr_bar->b_arrived + KMP_BARRIER_STATE_BUMP));
1091 // Mark arrival to parent thread
1092 /* After performing this write (in the last iteration of the enclosing for
1093 loop), a worker thread may not assume that the team is valid any more
1094 - it could be deallocated by the primary thread at any time. */
1095 p_flag.set_waiter(other_threads[parent_tid]);
1096 p_flag.release();
1097 break;
1098 }
1099
1100 // Parent threads wait for children to arrive
1101 if (new_state == KMP_BARRIER_UNUSED_STATE)
1102 new_state = team->t.t_bar[bt].b_arrived + KMP_BARRIER_STATE_BUMP;
1103 for (child = 1, child_tid = tid + (1 << level);
1104 child < branch_factor && child_tid < num_threads;
1105 child++, child_tid += (1 << level)) {
1106 kmp_info_t *child_thr = other_threads[child_tid];
1107 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1108#if KMP_CACHE_MANAGE
1109 kmp_uint32 next_child_tid = child_tid + (1 << level);
1110 // Prefetch next thread's arrived count
1111 if (child + 1 < branch_factor && next_child_tid < num_threads)
1113 &other_threads[next_child_tid]->th.th_bar[bt].bb.b_arrived);
1114#endif /* KMP_CACHE_MANAGE */
1115 KA_TRACE(20,
1116 ("__kmp_hyper_barrier_gather: T#%d(%d:%d) wait T#%d(%d:%u) "
1117 "arrived(%p) == %llu\n",
1118 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
1119 team->t.t_id, child_tid, &child_bar->b_arrived, new_state));
1120 // Wait for child to arrive
1121 kmp_flag_64<> c_flag(&child_bar->b_arrived, new_state);
1122 c_flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
1123 KMP_MB(); // Synchronize parent and child threads.
1124#if USE_ITT_BUILD && USE_ITT_NOTIFY
1125 // Barrier imbalance - write min of the thread time and a child time to
1126 // the thread.
1127 if (__kmp_forkjoin_frames_mode == 2) {
1128 this_thr->th.th_bar_min_time = KMP_MIN(this_thr->th.th_bar_min_time,
1129 child_thr->th.th_bar_min_time);
1130 }
1131#endif
1132 if (reduce) {
1133 KA_TRACE(100,
1134 ("__kmp_hyper_barrier_gather: T#%d(%d:%d) += T#%d(%d:%u)\n",
1135 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
1136 team->t.t_id, child_tid));
1137 OMPT_REDUCTION_DECL(this_thr, gtid);
1139 (*reduce)(this_thr->th.th_local.reduce_data,
1140 child_thr->th.th_local.reduce_data);
1142 }
1143 }
1144 }
1145
1146 if (KMP_MASTER_TID(tid)) {
1147 // Need to update the team arrived pointer if we are the primary thread
1148 if (new_state == KMP_BARRIER_UNUSED_STATE)
1149 team->t.t_bar[bt].b_arrived += KMP_BARRIER_STATE_BUMP;
1150 else
1151 team->t.t_bar[bt].b_arrived = new_state;
1152 KA_TRACE(20, ("__kmp_hyper_barrier_gather: T#%d(%d:%d) set team %d "
1153 "arrived(%p) = %llu\n",
1154 gtid, team->t.t_id, tid, team->t.t_id,
1155 &team->t.t_bar[bt].b_arrived, team->t.t_bar[bt].b_arrived));
1156 }
1157 KA_TRACE(
1158 20, ("__kmp_hyper_barrier_gather: T#%d(%d:%d) exit for barrier type %d\n",
1159 gtid, team->t.t_id, tid, bt));
1160}
1161
1162// The reverse versions seem to beat the forward versions overall
1163#define KMP_REVERSE_HYPER_BAR
1165 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
1166 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
1167 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_hyper_release);
1168 kmp_team_t *team;
1169 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
1170 kmp_info_t **other_threads;
1171 kmp_uint32 num_threads;
1173 kmp_uint32 branch_factor = 1 << branch_bits;
1174 kmp_uint32 child;
1175 kmp_uint32 child_tid;
1176 kmp_uint32 offset;
1178
1179 /* Perform a hypercube-embedded tree release for all of the threads that have
1180 been gathered. If KMP_REVERSE_HYPER_BAR is defined (default) the threads
1181 are released in the reverse order of the corresponding gather, otherwise
1182 threads are released in the same order. */
1183 if (KMP_MASTER_TID(tid)) { // primary thread
1184 team = __kmp_threads[gtid]->th.th_team;
1185 KMP_DEBUG_ASSERT(team != NULL);
1186 KA_TRACE(20, ("__kmp_hyper_barrier_release: T#%d(%d:%d) primary enter for "
1187 "barrier type %d\n",
1188 gtid, team->t.t_id, tid, bt));
1189#if KMP_BARRIER_ICV_PUSH
1190 if (propagate_icvs) { // primary already has ICVs in final destination; copy
1191 copy_icvs(&thr_bar->th_fixed_icvs,
1192 &team->t.t_implicit_task_taskdata[tid].td_icvs);
1193 }
1194#endif
1195 } else { // Handle fork barrier workers who aren't part of a team yet
1196 KA_TRACE(20, ("__kmp_hyper_barrier_release: T#%d wait go(%p) == %u\n", gtid,
1197 &thr_bar->b_go, KMP_BARRIER_STATE_BUMP));
1198 // Wait for parent thread to release us
1199 kmp_flag_64<> flag(&thr_bar->b_go, KMP_BARRIER_STATE_BUMP);
1200 flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
1201#if USE_ITT_BUILD && USE_ITT_NOTIFY
1202 if ((__itt_sync_create_ptr && itt_sync_obj == NULL) || KMP_ITT_DEBUG) {
1203 // In fork barrier where we could not get the object reliably
1204 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier, 0, -1);
1205 // Cancel wait on previous parallel region...
1206 __kmp_itt_task_starting(itt_sync_obj);
1207
1208 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
1209 return;
1210
1211 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
1212 if (itt_sync_obj != NULL)
1213 // Call prepare as early as possible for "new" barrier
1214 __kmp_itt_task_finished(itt_sync_obj);
1215 } else
1216#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
1217 // Early exit for reaping threads releasing forkjoin barrier
1218 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
1219 return;
1220
1221 // The worker thread may now assume that the team is valid.
1222 team = __kmp_threads[gtid]->th.th_team;
1223 KMP_DEBUG_ASSERT(team != NULL);
1224 tid = __kmp_tid_from_gtid(gtid);
1225
1226 TCW_4(thr_bar->b_go, KMP_INIT_BARRIER_STATE);
1227 KA_TRACE(20,
1228 ("__kmp_hyper_barrier_release: T#%d(%d:%d) set go(%p) = %u\n",
1229 gtid, team->t.t_id, tid, &thr_bar->b_go, KMP_INIT_BARRIER_STATE));
1230 KMP_MB(); // Flush all pending memory write invalidates.
1231 }
1232 num_threads = this_thr->th.th_team_nproc;
1233 other_threads = team->t.t_threads;
1234
1235#ifdef KMP_REVERSE_HYPER_BAR
1236 // Count up to correct level for parent
1237 for (level = 0, offset = 1;
1238 offset < num_threads && (((tid >> level) & (branch_factor - 1)) == 0);
1239 level += branch_bits, offset <<= branch_bits)
1240 ;
1241
1242 // Now go down from there
1243 for (level -= branch_bits, offset >>= branch_bits; offset != 0;
1244 level -= branch_bits, offset >>= branch_bits)
1245#else
1246 // Go down the tree, level by level
1247 for (level = 0, offset = 1; offset < num_threads;
1248 level += branch_bits, offset <<= branch_bits)
1249#endif // KMP_REVERSE_HYPER_BAR
1250 {
1251#ifdef KMP_REVERSE_HYPER_BAR
1252 /* Now go in reverse order through the children, highest to lowest.
1253 Initial setting of child is conservative here. */
1254 child = num_threads >> ((level == 0) ? level : level - 1);
1255 for (child = (child < branch_factor - 1) ? child : branch_factor - 1,
1256 child_tid = tid + (child << level);
1257 child >= 1; child--, child_tid -= (1 << level))
1258#else
1259 if (((tid >> level) & (branch_factor - 1)) != 0)
1260 // No need to go lower than this, since this is the level parent would be
1261 // notified
1262 break;
1263 // Iterate through children on this level of the tree
1264 for (child = 1, child_tid = tid + (1 << level);
1265 child < branch_factor && child_tid < num_threads;
1266 child++, child_tid += (1 << level))
1267#endif // KMP_REVERSE_HYPER_BAR
1268 {
1269 if (child_tid >= num_threads)
1270 continue; // Child doesn't exist so keep going
1271 else {
1272 kmp_info_t *child_thr = other_threads[child_tid];
1273 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1274#if KMP_CACHE_MANAGE
1275 kmp_uint32 next_child_tid = child_tid - (1 << level);
1276// Prefetch next thread's go count
1277#ifdef KMP_REVERSE_HYPER_BAR
1278 if (child - 1 >= 1 && next_child_tid < num_threads)
1279#else
1280 if (child + 1 < branch_factor && next_child_tid < num_threads)
1281#endif // KMP_REVERSE_HYPER_BAR
1283 &other_threads[next_child_tid]->th.th_bar[bt].bb.b_go);
1284#endif /* KMP_CACHE_MANAGE */
1285
1286#if KMP_BARRIER_ICV_PUSH
1287 if (propagate_icvs) // push my fixed ICVs to my child
1288 copy_icvs(&child_bar->th_fixed_icvs, &thr_bar->th_fixed_icvs);
1289#endif // KMP_BARRIER_ICV_PUSH
1290
1291 KA_TRACE(
1292 20,
1293 ("__kmp_hyper_barrier_release: T#%d(%d:%d) releasing T#%d(%d:%u)"
1294 "go(%p): %u => %u\n",
1295 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
1296 team->t.t_id, child_tid, &child_bar->b_go, child_bar->b_go,
1297 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1298 // Release child from barrier
1299 kmp_flag_64<> flag(&child_bar->b_go, child_thr);
1300 flag.release();
1301 }
1302 }
1303 }
1304#if KMP_BARRIER_ICV_PUSH
1305 if (propagate_icvs &&
1306 !KMP_MASTER_TID(tid)) { // copy ICVs locally to final dest
1307 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[tid], team, tid,
1308 FALSE);
1309 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
1310 &thr_bar->th_fixed_icvs);
1311 }
1312#endif
1313 KA_TRACE(
1314 20,
1315 ("__kmp_hyper_barrier_release: T#%d(%d:%d) exit for barrier type %d\n",
1316 gtid, team->t.t_id, tid, bt));
1317}
1318
1319// Hierarchical Barrier
1320
1321// Initialize thread barrier data
1322/* Initializes/re-initializes the hierarchical barrier data stored on a thread.
1323 Performs the minimum amount of initialization required based on how the team
1324 has changed. Returns true if leaf children will require both on-core and
1325 traditional wake-up mechanisms. For example, if the team size increases,
1326 threads already in the team will respond to on-core wakeup on their parent
1327 thread, but threads newly added to the team will only be listening on the
1328 their local b_go. */
1330 kmp_bstate_t *thr_bar,
1331 kmp_uint32 nproc, int gtid,
1332 int tid, kmp_team_t *team) {
1333 // Helper macro to identify bytes in a kmp_uint64 in an endian-independent
1334 // way. Input 0 results in the byte address of the MSB, input 7 results
1335 // in the byte address of the LSB.
1336#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
1337#define __kmp_msb_byteoffset(offset) (offset)
1338#else
1339#define __kmp_msb_byteoffset(offset) (7 - (offset))
1340#endif
1341
1342 // Checks to determine if (re-)initialization is needed
1343 bool uninitialized = thr_bar->team == NULL;
1344 bool team_changed = team != thr_bar->team;
1345 bool team_sz_changed = nproc != thr_bar->nproc;
1346 bool tid_changed = tid != thr_bar->old_tid;
1347 bool retval = false;
1348
1349 if (uninitialized || team_sz_changed) {
1350 __kmp_get_hierarchy(nproc, thr_bar);
1351 }
1352
1353 if (uninitialized || team_sz_changed || tid_changed) {
1354 thr_bar->my_level = thr_bar->depth - 1; // default for primary thread
1355 thr_bar->parent_tid = -1; // default for primary thread
1356 thr_bar->offset = -1; // unused for primary thread
1357 if (!KMP_MASTER_TID(tid)) {
1358 // if not primary thread, find parent thread in hierarchy
1359 kmp_uint32 d = 0;
1360 while (d < thr_bar->depth) { // find parent based on level of thread in
1361 // hierarchy, and note level
1362 kmp_uint32 rem;
1363 if (d == thr_bar->depth - 2) { // reached level right below the primary
1364 thr_bar->parent_tid = 0;
1365 thr_bar->my_level = d;
1366 break;
1367 } else if ((rem = tid % thr_bar->skip_per_level[d + 1]) != 0) {
1368 // TODO: can we make the above op faster?
1369 // thread is not a subtree root at next level, so this is max
1370 thr_bar->parent_tid = tid - rem;
1371 thr_bar->my_level = d;
1372 break;
1373 }
1374 ++d;
1375 }
1376
1377 kmp_uint32 offset = ((kmp_uint32)tid - thr_bar->parent_tid) /
1378 thr_bar->skip_per_level[thr_bar->my_level];
1379 offset = offset - 1;
1380 KMP_ASSERT(offset < 7);
1381 __kmp_type_convert(__kmp_msb_byteoffset(offset), &(thr_bar->offset));
1382 }
1383
1384 thr_bar->old_tid = tid;
1385 thr_bar->wait_flag = KMP_BARRIER_NOT_WAITING;
1386 thr_bar->team = team;
1387 thr_bar->parent_bar =
1388 &team->t.t_threads[thr_bar->parent_tid]->th.th_bar[bt].bb;
1389 }
1390 if (uninitialized || team_changed || tid_changed) {
1391 thr_bar->team = team;
1392 thr_bar->parent_bar =
1393 &team->t.t_threads[thr_bar->parent_tid]->th.th_bar[bt].bb;
1394 retval = true;
1395 }
1396 if (uninitialized || team_sz_changed || tid_changed) {
1397 thr_bar->nproc = nproc;
1398 thr_bar->leaf_kids = thr_bar->base_leaf_kids;
1399 if (thr_bar->my_level == 0)
1400 thr_bar->leaf_kids = 0;
1401 if (thr_bar->leaf_kids && (kmp_uint32)tid + thr_bar->leaf_kids + 1 > nproc)
1402 __kmp_type_convert(nproc - tid - 1, &(thr_bar->leaf_kids));
1403 thr_bar->leaf_state = 0;
1404 for (int i = 0; i < thr_bar->leaf_kids; ++i)
1405 ((char *)&(thr_bar->leaf_state))[__kmp_msb_byteoffset(i)] = 1;
1406 }
1407 return retval;
1408
1409#undef __kmp_msb_byteoffset
1410}
1411
1413 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
1414 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
1415 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_hier_gather);
1416 kmp_team_t *team = this_thr->th.th_team;
1417 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
1418 kmp_uint32 nproc = this_thr->th.th_team_nproc;
1419 kmp_info_t **other_threads = team->t.t_threads;
1420 kmp_uint64 new_state = 0;
1421
1422 int level = team->t.t_level;
1423 if (other_threads[0]
1424 ->th.th_teams_microtask) // are we inside the teams construct?
1425 if (this_thr->th.th_teams_size.nteams > 1)
1426 ++level; // level was not increased in teams construct for team_of_masters
1427 if (level == 1)
1428 thr_bar->use_oncore_barrier = 1;
1429 else
1430 thr_bar->use_oncore_barrier = 0; // Do not use oncore barrier when nested
1431
1432 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) enter for "
1433 "barrier type %d\n",
1434 gtid, team->t.t_id, tid, bt));
1435 KMP_DEBUG_ASSERT(this_thr == other_threads[this_thr->th.th_info.ds.ds_tid]);
1436
1437#if USE_ITT_BUILD && USE_ITT_NOTIFY
1438 // Barrier imbalance - save arrive time to the thread
1439 if (__kmp_forkjoin_frames_mode == 3 || __kmp_forkjoin_frames_mode == 2) {
1440 this_thr->th.th_bar_arrive_time = __itt_get_timestamp();
1441 }
1442#endif
1443
1444 (void)__kmp_init_hierarchical_barrier_thread(bt, thr_bar, nproc, gtid, tid,
1445 team);
1446
1447 if (thr_bar->my_level) { // not a leaf (my_level==0 means leaf)
1448 kmp_int32 child_tid;
1449 new_state =
1450 (kmp_uint64)team->t.t_bar[bt].b_arrived + KMP_BARRIER_STATE_BUMP;
1452 thr_bar->use_oncore_barrier) {
1453 if (thr_bar->leaf_kids) {
1454 // First, wait for leaf children to check-in on my b_arrived flag
1455 kmp_uint64 leaf_state =
1456 KMP_MASTER_TID(tid)
1457 ? thr_bar->b_arrived | thr_bar->leaf_state
1458 : team->t.t_bar[bt].b_arrived | thr_bar->leaf_state;
1459 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) waiting "
1460 "for leaf kids\n",
1461 gtid, team->t.t_id, tid));
1462 kmp_flag_64<> flag(&thr_bar->b_arrived, leaf_state);
1463 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
1464 if (reduce) {
1465 OMPT_REDUCTION_DECL(this_thr, gtid);
1467 for (child_tid = tid + 1; child_tid <= tid + thr_bar->leaf_kids;
1468 ++child_tid) {
1469 KA_TRACE(100, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) += "
1470 "T#%d(%d:%d)\n",
1471 gtid, team->t.t_id, tid,
1472 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1473 child_tid));
1474 (*reduce)(this_thr->th.th_local.reduce_data,
1475 other_threads[child_tid]->th.th_local.reduce_data);
1476 }
1478 }
1479 // clear leaf_state bits
1480 KMP_TEST_THEN_AND64(&thr_bar->b_arrived, ~(thr_bar->leaf_state));
1481 }
1482 // Next, wait for higher level children on each child's b_arrived flag
1483 for (kmp_uint32 d = 1; d < thr_bar->my_level;
1484 ++d) { // gather lowest level threads first, but skip 0
1485 kmp_uint32 last = tid + thr_bar->skip_per_level[d + 1],
1486 skip = thr_bar->skip_per_level[d];
1487 if (last > nproc)
1488 last = nproc;
1489 for (child_tid = tid + skip; child_tid < (int)last; child_tid += skip) {
1490 kmp_info_t *child_thr = other_threads[child_tid];
1491 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1492 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) wait "
1493 "T#%d(%d:%d) "
1494 "arrived(%p) == %llu\n",
1495 gtid, team->t.t_id, tid,
1496 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1497 child_tid, &child_bar->b_arrived, new_state));
1498 kmp_flag_64<> flag(&child_bar->b_arrived, new_state);
1499 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
1500 if (reduce) {
1501 KA_TRACE(100, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) += "
1502 "T#%d(%d:%d)\n",
1503 gtid, team->t.t_id, tid,
1504 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1505 child_tid));
1506 (*reduce)(this_thr->th.th_local.reduce_data,
1507 child_thr->th.th_local.reduce_data);
1508 }
1509 }
1510 }
1511 } else { // Blocktime is not infinite
1512 for (kmp_uint32 d = 0; d < thr_bar->my_level;
1513 ++d) { // Gather lowest level threads first
1514 kmp_uint32 last = tid + thr_bar->skip_per_level[d + 1],
1515 skip = thr_bar->skip_per_level[d];
1516 if (last > nproc)
1517 last = nproc;
1518 for (child_tid = tid + skip; child_tid < (int)last; child_tid += skip) {
1519 kmp_info_t *child_thr = other_threads[child_tid];
1520 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1521 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) wait "
1522 "T#%d(%d:%d) "
1523 "arrived(%p) == %llu\n",
1524 gtid, team->t.t_id, tid,
1525 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1526 child_tid, &child_bar->b_arrived, new_state));
1527 kmp_flag_64<> flag(&child_bar->b_arrived, new_state);
1528 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
1529 if (reduce) {
1530 KA_TRACE(100, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) += "
1531 "T#%d(%d:%d)\n",
1532 gtid, team->t.t_id, tid,
1533 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1534 child_tid));
1535 (*reduce)(this_thr->th.th_local.reduce_data,
1536 child_thr->th.th_local.reduce_data);
1537 }
1538 }
1539 }
1540 }
1541 }
1542 // All subordinates are gathered; now release parent if not primary thread
1543
1544 if (!KMP_MASTER_TID(tid)) { // worker threads release parent in hierarchy
1545 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) releasing"
1546 " T#%d(%d:%d) arrived(%p): %llu => %llu\n",
1547 gtid, team->t.t_id, tid,
1548 __kmp_gtid_from_tid(thr_bar->parent_tid, team), team->t.t_id,
1549 thr_bar->parent_tid, &thr_bar->b_arrived, thr_bar->b_arrived,
1550 thr_bar->b_arrived + KMP_BARRIER_STATE_BUMP));
1551 /* Mark arrival to parent: After performing this write, a worker thread may
1552 not assume that the team is valid any more - it could be deallocated by
1553 the primary thread at any time. */
1554 if (thr_bar->my_level || __kmp_dflt_blocktime != KMP_MAX_BLOCKTIME ||
1555 !thr_bar->use_oncore_barrier) { // Parent is waiting on my b_arrived
1556 // flag; release it
1557 kmp_flag_64<> flag(&thr_bar->b_arrived,
1558 other_threads[thr_bar->parent_tid]);
1559 flag.release();
1560 } else {
1561 // Leaf does special release on "offset" bits of parent's b_arrived flag
1562 thr_bar->b_arrived = team->t.t_bar[bt].b_arrived + KMP_BARRIER_STATE_BUMP;
1563 kmp_flag_oncore flag(&thr_bar->parent_bar->b_arrived, thr_bar->offset);
1564 flag.set_waiter(other_threads[thr_bar->parent_tid]);
1565 flag.release();
1566 }
1567 } else { // Primary thread needs to update the team's b_arrived value
1568 team->t.t_bar[bt].b_arrived = new_state;
1569 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) set team %d "
1570 "arrived(%p) = %llu\n",
1571 gtid, team->t.t_id, tid, team->t.t_id,
1572 &team->t.t_bar[bt].b_arrived, team->t.t_bar[bt].b_arrived));
1573 }
1574 // Is the team access below unsafe or just technically invalid?
1575 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) exit for "
1576 "barrier type %d\n",
1577 gtid, team->t.t_id, tid, bt));
1578}
1579
1581 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
1582 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
1583 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_hier_release);
1584 kmp_team_t *team;
1585 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
1586 kmp_uint32 nproc;
1587 bool team_change = false; // indicates on-core barrier shouldn't be used
1588
1589 if (KMP_MASTER_TID(tid)) {
1590 team = __kmp_threads[gtid]->th.th_team;
1591 KMP_DEBUG_ASSERT(team != NULL);
1592 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) primary "
1593 "entered barrier type %d\n",
1594 gtid, team->t.t_id, tid, bt));
1595 } else { // Worker threads
1596 // Wait for parent thread to release me
1597 if (!thr_bar->use_oncore_barrier ||
1598 __kmp_dflt_blocktime != KMP_MAX_BLOCKTIME || thr_bar->my_level != 0 ||
1599 thr_bar->team == NULL) {
1600 // Use traditional method of waiting on my own b_go flag
1601 thr_bar->wait_flag = KMP_BARRIER_OWN_FLAG;
1602 kmp_flag_64<> flag(&thr_bar->b_go, KMP_BARRIER_STATE_BUMP);
1603 flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
1604 TCW_8(thr_bar->b_go,
1605 KMP_INIT_BARRIER_STATE); // Reset my b_go flag for next time
1606 } else { // Thread barrier data is initialized, this is a leaf, blocktime is
1607 // infinite, not nested
1608 // Wait on my "offset" bits on parent's b_go flag
1609 thr_bar->wait_flag = KMP_BARRIER_PARENT_FLAG;
1610 kmp_flag_oncore flag(&thr_bar->parent_bar->b_go, KMP_BARRIER_STATE_BUMP,
1611 thr_bar->offset, bt,
1612 this_thr USE_ITT_BUILD_ARG(itt_sync_obj));
1613 flag.wait(this_thr, TRUE);
1614 if (thr_bar->wait_flag ==
1615 KMP_BARRIER_SWITCHING) { // Thread was switched to own b_go
1616 TCW_8(thr_bar->b_go,
1617 KMP_INIT_BARRIER_STATE); // Reset my b_go flag for next time
1618 } else { // Reset my bits on parent's b_go flag
1619 (RCAST(volatile char *,
1620 &(thr_bar->parent_bar->b_go)))[thr_bar->offset] = 0;
1621 }
1622 }
1623 thr_bar->wait_flag = KMP_BARRIER_NOT_WAITING;
1624 // Early exit for reaping threads releasing forkjoin barrier
1625 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
1626 return;
1627 // The worker thread may now assume that the team is valid.
1628 team = __kmp_threads[gtid]->th.th_team;
1629 KMP_DEBUG_ASSERT(team != NULL);
1630 tid = __kmp_tid_from_gtid(gtid);
1631
1632 KA_TRACE(
1633 20,
1634 ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) set go(%p) = %u\n",
1635 gtid, team->t.t_id, tid, &thr_bar->b_go, KMP_INIT_BARRIER_STATE));
1636 KMP_MB(); // Flush all pending memory write invalidates.
1637 }
1638
1639 nproc = this_thr->th.th_team_nproc;
1640 int level = team->t.t_level;
1641 if (team->t.t_threads[0]
1642 ->th.th_teams_microtask) { // are we inside the teams construct?
1643 if (team->t.t_pkfn != (microtask_t)__kmp_teams_master &&
1644 this_thr->th.th_teams_level == level)
1645 ++level; // level was not increased in teams construct for team_of_workers
1646 if (this_thr->th.th_teams_size.nteams > 1)
1647 ++level; // level was not increased in teams construct for team_of_masters
1648 }
1649 if (level == 1)
1650 thr_bar->use_oncore_barrier = 1;
1651 else
1652 thr_bar->use_oncore_barrier = 0; // Do not use oncore barrier when nested
1653
1654 // If the team size has increased, we still communicate with old leaves via
1655 // oncore barrier.
1656 unsigned short int old_leaf_kids = thr_bar->leaf_kids;
1657 kmp_uint64 old_leaf_state = thr_bar->leaf_state;
1658 team_change = __kmp_init_hierarchical_barrier_thread(bt, thr_bar, nproc, gtid,
1659 tid, team);
1660 // But if the entire team changes, we won't use oncore barrier at all
1661 if (team_change)
1662 old_leaf_kids = 0;
1663
1664#if KMP_BARRIER_ICV_PUSH
1665 if (propagate_icvs) {
1666 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[tid], team, tid,
1667 FALSE);
1668 if (KMP_MASTER_TID(
1669 tid)) { // primary already has copy in final destination; copy
1670 copy_icvs(&thr_bar->th_fixed_icvs,
1671 &team->t.t_implicit_task_taskdata[tid].td_icvs);
1673 thr_bar->use_oncore_barrier) { // optimization for inf blocktime
1674 if (!thr_bar->my_level) // I'm a leaf in the hierarchy (my_level==0)
1675 // leaves (on-core children) pull parent's fixed ICVs directly to local
1676 // ICV store
1677 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
1678 &thr_bar->parent_bar->th_fixed_icvs);
1679 // non-leaves will get ICVs piggybacked with b_go via NGO store
1680 } else { // blocktime is not infinite; pull ICVs from parent's fixed ICVs
1681 if (thr_bar->my_level) // not a leaf; copy ICVs to my fixed ICVs child can
1682 // access
1683 copy_icvs(&thr_bar->th_fixed_icvs, &thr_bar->parent_bar->th_fixed_icvs);
1684 else // leaves copy parent's fixed ICVs directly to local ICV store
1685 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
1686 &thr_bar->parent_bar->th_fixed_icvs);
1687 }
1688 }
1689#endif // KMP_BARRIER_ICV_PUSH
1690
1691 // Now, release my children
1692 if (thr_bar->my_level) { // not a leaf
1693 kmp_int32 child_tid;
1694 kmp_uint32 last;
1696 thr_bar->use_oncore_barrier) {
1697 if (KMP_MASTER_TID(tid)) { // do a flat release
1698 // Set local b_go to bump children via NGO store of the cache line
1699 // containing IVCs and b_go.
1700 thr_bar->b_go = KMP_BARRIER_STATE_BUMP;
1701 // Use ngo stores if available; b_go piggybacks in the last 8 bytes of
1702 // the cache line
1703 ngo_load(&thr_bar->th_fixed_icvs);
1704 // This loops over all the threads skipping only the leaf nodes in the
1705 // hierarchy
1706 for (child_tid = thr_bar->skip_per_level[1]; child_tid < (int)nproc;
1707 child_tid += thr_bar->skip_per_level[1]) {
1708 kmp_bstate_t *child_bar =
1709 &team->t.t_threads[child_tid]->th.th_bar[bt].bb;
1710 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) "
1711 "releasing T#%d(%d:%d)"
1712 " go(%p): %u => %u\n",
1713 gtid, team->t.t_id, tid,
1714 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1715 child_tid, &child_bar->b_go, child_bar->b_go,
1716 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1717 // Use ngo store (if available) to both store ICVs and release child
1718 // via child's b_go
1719 ngo_store_go(&child_bar->th_fixed_icvs, &thr_bar->th_fixed_icvs);
1720 }
1721 ngo_sync();
1722 }
1723 TCW_8(thr_bar->b_go,
1724 KMP_INIT_BARRIER_STATE); // Reset my b_go flag for next time
1725 // Now, release leaf children
1726 if (thr_bar->leaf_kids) { // if there are any
1727 // We test team_change on the off-chance that the level 1 team changed.
1728 if (team_change ||
1729 old_leaf_kids < thr_bar->leaf_kids) { // some old, some new
1730 if (old_leaf_kids) { // release old leaf kids
1731 thr_bar->b_go |= old_leaf_state;
1732 }
1733 // Release new leaf kids
1734 last = tid + thr_bar->skip_per_level[1];
1735 if (last > nproc)
1736 last = nproc;
1737 for (child_tid = tid + 1 + old_leaf_kids; child_tid < (int)last;
1738 ++child_tid) { // skip_per_level[0]=1
1739 kmp_info_t *child_thr = team->t.t_threads[child_tid];
1740 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1741 KA_TRACE(
1742 20,
1743 ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) releasing"
1744 " T#%d(%d:%d) go(%p): %u => %u\n",
1745 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
1746 team->t.t_id, child_tid, &child_bar->b_go, child_bar->b_go,
1747 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1748 // Release child using child's b_go flag
1749 kmp_flag_64<> flag(&child_bar->b_go, child_thr);
1750 flag.release();
1751 }
1752 } else { // Release all children at once with leaf_state bits on my own
1753 // b_go flag
1754 thr_bar->b_go |= thr_bar->leaf_state;
1755 }
1756 }
1757 } else { // Blocktime is not infinite; do a simple hierarchical release
1758 for (int d = thr_bar->my_level - 1; d >= 0;
1759 --d) { // Release highest level threads first
1760 last = tid + thr_bar->skip_per_level[d + 1];
1761 kmp_uint32 skip = thr_bar->skip_per_level[d];
1762 if (last > nproc)
1763 last = nproc;
1764 for (child_tid = tid + skip; child_tid < (int)last; child_tid += skip) {
1765 kmp_info_t *child_thr = team->t.t_threads[child_tid];
1766 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1767 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) "
1768 "releasing T#%d(%d:%d) go(%p): %u => %u\n",
1769 gtid, team->t.t_id, tid,
1770 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1771 child_tid, &child_bar->b_go, child_bar->b_go,
1772 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1773 // Release child using child's b_go flag
1774 kmp_flag_64<> flag(&child_bar->b_go, child_thr);
1775 flag.release();
1776 }
1777 }
1778 }
1779#if KMP_BARRIER_ICV_PUSH
1780 if (propagate_icvs && !KMP_MASTER_TID(tid))
1781 // non-leaves copy ICVs from fixed ICVs to local dest
1782 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
1783 &thr_bar->th_fixed_icvs);
1784#endif // KMP_BARRIER_ICV_PUSH
1785 }
1786 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) exit for "
1787 "barrier type %d\n",
1788 gtid, team->t.t_id, tid, bt));
1789}
1790
1791// End of Barrier Algorithms
1792
1793// type traits for cancellable value
1794// if cancellable is true, then is_cancellable is a normal boolean variable
1795// if cancellable is false, then is_cancellable is a compile time constant
1796template <bool cancellable> struct is_cancellable {};
1797template <> struct is_cancellable<true> {
1798 bool value;
1799 is_cancellable() : value(false) {}
1802 value = b;
1803 return *this;
1804 }
1805 operator bool() const { return value; }
1806};
1807template <> struct is_cancellable<false> {
1808 is_cancellable &operator=(bool b) { return *this; }
1809 constexpr operator bool() const { return false; }
1810};
1811
1812// Internal function to do a barrier.
1813/* If is_split is true, do a split barrier, otherwise, do a plain barrier
1814 If reduce is non-NULL, do a split reduction barrier, otherwise, do a split
1815 barrier
1816 When cancellable = false,
1817 Returns 0 if primary thread, 1 if worker thread.
1818 When cancellable = true
1819 Returns 0 if not cancelled, 1 if cancelled. */
1820template <bool cancellable = false>
1821static int __kmp_barrier_template(enum barrier_type bt, int gtid, int is_split,
1822 size_t reduce_size, void *reduce_data,
1823 void (*reduce)(void *, void *)) {
1824 KMP_TIME_PARTITIONED_BLOCK(OMP_plain_barrier);
1825 KMP_SET_THREAD_STATE_BLOCK(PLAIN_BARRIER);
1826 int tid = __kmp_tid_from_gtid(gtid);
1827 kmp_info_t *this_thr = __kmp_threads[gtid];
1828 kmp_team_t *team = this_thr->th.th_team;
1829 int status = 0;
1831#if OMPT_SUPPORT && OMPT_OPTIONAL
1832 ompt_data_t *my_task_data;
1833 ompt_data_t *my_parallel_data;
1834 void *return_address;
1835 ompt_sync_region_t barrier_kind;
1836#endif
1837
1838 KA_TRACE(15, ("__kmp_barrier: T#%d(%d:%d) has arrived\n", gtid,
1839 __kmp_team_from_gtid(gtid)->t.t_id, __kmp_tid_from_gtid(gtid)));
1840
1841#if OMPT_SUPPORT
1842 if (ompt_enabled.enabled) {
1843#if OMPT_OPTIONAL
1844 my_task_data = OMPT_CUR_TASK_DATA(this_thr);
1845 my_parallel_data = OMPT_CUR_TEAM_DATA(this_thr);
1846 return_address = OMPT_LOAD_RETURN_ADDRESS(gtid);
1847 barrier_kind = __ompt_get_barrier_kind(bt, this_thr);
1848 if (ompt_enabled.ompt_callback_sync_region) {
1849 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
1850 barrier_kind, ompt_scope_begin, my_parallel_data, my_task_data,
1851 return_address);
1852 }
1853 if (ompt_enabled.ompt_callback_sync_region_wait) {
1854 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
1855 barrier_kind, ompt_scope_begin, my_parallel_data, my_task_data,
1856 return_address);
1857 }
1858#endif
1859 // It is OK to report the barrier state after the barrier begin callback.
1860 // According to the OMPT specification, a compliant implementation may
1861 // even delay reporting this state until the barrier begins to wait.
1862 auto *ompt_thr_info = &this_thr->th.ompt_thread_info;
1863 switch (barrier_kind) {
1864 case ompt_sync_region_barrier_explicit:
1865 ompt_thr_info->state = ompt_state_wait_barrier_explicit;
1866 break;
1867 case ompt_sync_region_barrier_implicit_workshare:
1868 ompt_thr_info->state = ompt_state_wait_barrier_implicit_workshare;
1869 break;
1870 case ompt_sync_region_barrier_implicit_parallel:
1871 ompt_thr_info->state = ompt_state_wait_barrier_implicit_parallel;
1872 break;
1873 case ompt_sync_region_barrier_teams:
1874 ompt_thr_info->state = ompt_state_wait_barrier_teams;
1875 break;
1876 case ompt_sync_region_barrier_implementation:
1877 [[fallthrough]];
1878 default:
1879 ompt_thr_info->state = ompt_state_wait_barrier_implementation;
1880 }
1881 }
1882#endif
1883
1884#if ENABLE_LIBOMPTARGET
1885 // Give an opportunity to the offload runtime to make progress and create
1886 // proxy tasks if necessary
1887 if (UNLIKELY(kmp_target_sync_cb != NULL))
1888 (*kmp_target_sync_cb)(
1889 NULL, gtid, KMP_TASKDATA_TO_TASK(this_thr->th.th_current_task), NULL);
1890#endif
1891
1892 if (!team->t.t_serialized) {
1893#if USE_ITT_BUILD
1894 // This value will be used in itt notify events below.
1895 void *itt_sync_obj = NULL;
1896#if USE_ITT_NOTIFY
1897 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
1898 itt_sync_obj = __kmp_itt_barrier_object(gtid, bt, 1);
1899#endif
1900#endif /* USE_ITT_BUILD */
1902 __kmp_tasking_barrier(team, this_thr, gtid);
1903 KA_TRACE(15,
1904 ("__kmp_barrier: T#%d(%d:%d) past tasking barrier\n", gtid,
1905 __kmp_team_from_gtid(gtid)->t.t_id, __kmp_tid_from_gtid(gtid)));
1906 }
1907
1908 /* Copy the blocktime info to the thread, where __kmp_wait_template() can
1909 access it when the team struct is not guaranteed to exist. */
1910 // See note about the corresponding code in __kmp_join_barrier() being
1911 // performance-critical.
1913#if KMP_USE_MONITOR
1914 this_thr->th.th_team_bt_intervals =
1915 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
1916 this_thr->th.th_team_bt_set =
1917 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
1918#else
1919 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
1920#endif
1921 }
1922
1923#if USE_ITT_BUILD
1924 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
1925 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
1926#endif /* USE_ITT_BUILD */
1927#if USE_DEBUGGER
1928 // Let the debugger know: the thread arrived to the barrier and waiting.
1929 if (KMP_MASTER_TID(tid)) { // Primary thread counter stored in team struct
1930 team->t.t_bar[bt].b_master_arrived += 1;
1931 } else {
1932 this_thr->th.th_bar[bt].bb.b_worker_arrived += 1;
1933 } // if
1934#endif /* USE_DEBUGGER */
1935 if (reduce != NULL) {
1936 // KMP_DEBUG_ASSERT( is_split == TRUE ); // #C69956
1937 this_thr->th.th_local.reduce_data = reduce_data;
1938 }
1939
1941 __kmp_task_team_setup(this_thr, team);
1942
1943 if (cancellable) {
1945 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1946 } else {
1947 switch (__kmp_barrier_gather_pattern[bt]) {
1948 case bp_dist_bar: {
1949 __kmp_dist_barrier_gather(bt, this_thr, gtid, tid,
1950 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1951 break;
1952 }
1953 case bp_hyper_bar: {
1954 __kmp_hyper_barrier_gather(bt, this_thr, gtid, tid,
1955 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1956 break;
1957 }
1958 case bp_hierarchical_bar: {
1960 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1961 break;
1962 }
1963 case bp_tree_bar: {
1964 __kmp_tree_barrier_gather(bt, this_thr, gtid, tid,
1965 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1966 break;
1967 }
1968 default: {
1969 __kmp_linear_barrier_gather(bt, this_thr, gtid, tid,
1970 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1971 }
1972 }
1973 }
1974
1975 KMP_MB();
1976
1977 if (KMP_MASTER_TID(tid)) {
1978 status = 0;
1979 if (__kmp_tasking_mode != tskm_immediate_exec && !cancelled) {
1980 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
1981 }
1982#if USE_DEBUGGER
1983 // Let the debugger know: All threads are arrived and starting leaving the
1984 // barrier.
1985 team->t.t_bar[bt].b_team_arrived += 1;
1986#endif
1987
1989 kmp_int32 cancel_request = KMP_ATOMIC_LD_RLX(&team->t.t_cancel_request);
1990 // Reset cancellation flag for worksharing constructs
1991 if (cancel_request == cancel_loop ||
1992 cancel_request == cancel_sections) {
1993 KMP_ATOMIC_ST_RLX(&team->t.t_cancel_request, cancel_noreq);
1994 }
1995 }
1996#if USE_ITT_BUILD
1997 /* TODO: In case of split reduction barrier, primary thread may send
1998 acquired event early, before the final summation into the shared
1999 variable is done (final summation can be a long operation for array
2000 reductions). */
2001 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2002 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2003#endif /* USE_ITT_BUILD */
2004#if USE_ITT_BUILD && USE_ITT_NOTIFY
2005 // Barrier - report frame end (only if active_level == 1)
2006 if ((__itt_frame_submit_v3_ptr || KMP_ITT_DEBUG) &&
2007 __kmp_forkjoin_frames_mode &&
2008 (this_thr->th.th_teams_microtask == NULL || // either not in teams
2009 this_thr->th.th_teams_size.nteams == 1) && // or inside single team
2010 team->t.t_active_level == 1) {
2011 ident_t *loc = __kmp_threads[gtid]->th.th_ident;
2012 kmp_uint64 cur_time = __itt_get_timestamp();
2013 kmp_info_t **other_threads = team->t.t_threads;
2014 int nproc = this_thr->th.th_team_nproc;
2015 int i;
2016 switch (__kmp_forkjoin_frames_mode) {
2017 case 1:
2018 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2019 loc, nproc);
2020 this_thr->th.th_frame_time = cur_time;
2021 break;
2022 case 2: // AC 2015-01-19: currently does not work for hierarchical (to
2023 // be fixed)
2024 __kmp_itt_frame_submit(gtid, this_thr->th.th_bar_min_time, cur_time,
2025 1, loc, nproc);
2026 break;
2027 case 3:
2028 if (__itt_metadata_add_ptr) {
2029 // Initialize with primary thread's wait time
2030 kmp_uint64 delta = cur_time - this_thr->th.th_bar_arrive_time;
2031 // Set arrive time to zero to be able to check it in
2032 // __kmp_invoke_task(); the same is done inside the loop below
2033 this_thr->th.th_bar_arrive_time = 0;
2034 for (i = 1; i < nproc; ++i) {
2035 delta += (cur_time - other_threads[i]->th.th_bar_arrive_time);
2036 other_threads[i]->th.th_bar_arrive_time = 0;
2037 }
2038 __kmp_itt_metadata_imbalance(gtid, this_thr->th.th_frame_time,
2039 cur_time, delta,
2040 (kmp_uint64)(reduce != NULL));
2041 }
2042 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2043 loc, nproc);
2044 this_thr->th.th_frame_time = cur_time;
2045 break;
2046 }
2047 }
2048#endif /* USE_ITT_BUILD */
2049 } else {
2050 status = 1;
2051#if USE_ITT_BUILD
2052 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2053 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2054#endif /* USE_ITT_BUILD */
2055 }
2056 if ((status == 1 || !is_split) && !cancelled) {
2057 if (cancellable) {
2059 bt, this_thr, gtid, tid, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2060 } else {
2061 switch (__kmp_barrier_release_pattern[bt]) {
2062 case bp_dist_bar: {
2064 __kmp_dist_barrier_release(bt, this_thr, gtid, tid,
2065 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2066 break;
2067 }
2068 case bp_hyper_bar: {
2070 __kmp_hyper_barrier_release(bt, this_thr, gtid, tid,
2071 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2072 break;
2073 }
2074 case bp_hierarchical_bar: {
2076 bt, this_thr, gtid, tid, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2077 break;
2078 }
2079 case bp_tree_bar: {
2081 __kmp_tree_barrier_release(bt, this_thr, gtid, tid,
2082 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2083 break;
2084 }
2085 default: {
2086 __kmp_linear_barrier_release(bt, this_thr, gtid, tid,
2087 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2088 }
2089 }
2090 }
2091 if (__kmp_tasking_mode != tskm_immediate_exec && !cancelled) {
2092 __kmp_task_team_sync(this_thr, team);
2093 }
2094 }
2095
2096#if USE_ITT_BUILD
2097 /* GEH: TODO: Move this under if-condition above and also include in
2098 __kmp_end_split_barrier(). This will more accurately represent the actual
2099 release time of the threads for split barriers. */
2100 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2101 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2102#endif /* USE_ITT_BUILD */
2103 } else { // Team is serialized.
2104 status = 0;
2106 if (this_thr->th.th_task_team != NULL) {
2107#if USE_ITT_NOTIFY
2108 void *itt_sync_obj = NULL;
2109 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2110 itt_sync_obj = __kmp_itt_barrier_object(gtid, bt, 1);
2111 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
2112 }
2113#endif
2114
2116 this_thr->th.th_task_team->tt.tt_found_proxy_tasks == TRUE ||
2117 this_thr->th.th_task_team->tt.tt_hidden_helper_task_encountered ==
2118 TRUE);
2119 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
2120 __kmp_task_team_setup(this_thr, team);
2121
2122#if USE_ITT_BUILD
2123 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2124 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2125#endif /* USE_ITT_BUILD */
2126 }
2127 }
2128 }
2129 KA_TRACE(15, ("__kmp_barrier: T#%d(%d:%d) is leaving with return value %d\n",
2130 gtid, __kmp_team_from_gtid(gtid)->t.t_id,
2131 __kmp_tid_from_gtid(gtid), status));
2132
2133#if OMPT_SUPPORT
2134 if (ompt_enabled.enabled) {
2135#if OMPT_OPTIONAL
2136 if (ompt_enabled.ompt_callback_sync_region_wait) {
2137 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2138 barrier_kind, ompt_scope_end, my_parallel_data, my_task_data,
2139 return_address);
2140 }
2141 if (ompt_enabled.ompt_callback_sync_region) {
2142 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2143 barrier_kind, ompt_scope_end, my_parallel_data, my_task_data,
2144 return_address);
2145 }
2146#endif
2147 this_thr->th.ompt_thread_info.state = ompt_state_work_parallel;
2148 }
2149#endif
2150
2151 if (cancellable)
2152 return (int)cancelled;
2153 return status;
2154}
2155
2156// Returns 0 if primary thread, 1 if worker thread.
2157int __kmp_barrier(enum barrier_type bt, int gtid, int is_split,
2158 size_t reduce_size, void *reduce_data,
2159 void (*reduce)(void *, void *)) {
2160 return __kmp_barrier_template<>(bt, gtid, is_split, reduce_size, reduce_data,
2161 reduce);
2162}
2163
2164#if defined(KMP_GOMP_COMPAT)
2165// Returns 1 if cancelled, 0 otherwise
2166int __kmp_barrier_gomp_cancel(int gtid) {
2169 0, NULL, NULL);
2170 if (cancelled) {
2171 int tid = __kmp_tid_from_gtid(gtid);
2172 kmp_info_t *this_thr = __kmp_threads[gtid];
2173 if (KMP_MASTER_TID(tid)) {
2174 // Primary thread does not need to revert anything
2175 } else {
2176 // Workers need to revert their private b_arrived flag
2177 this_thr->th.th_bar[bs_plain_barrier].bb.b_arrived -=
2179 }
2180 }
2181 return cancelled;
2182 }
2183 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
2184 return FALSE;
2185}
2186#endif
2187
2188void __kmp_end_split_barrier(enum barrier_type bt, int gtid) {
2189 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_end_split_barrier);
2190 KMP_SET_THREAD_STATE_BLOCK(PLAIN_BARRIER);
2192 int tid = __kmp_tid_from_gtid(gtid);
2193 kmp_info_t *this_thr = __kmp_threads[gtid];
2194 kmp_team_t *team = this_thr->th.th_team;
2195
2196 if (!team->t.t_serialized) {
2197 if (KMP_MASTER_GTID(gtid)) {
2198 switch (__kmp_barrier_release_pattern[bt]) {
2199 case bp_dist_bar: {
2200 __kmp_dist_barrier_release(bt, this_thr, gtid, tid,
2201 FALSE USE_ITT_BUILD_ARG(NULL));
2202 break;
2203 }
2204 case bp_hyper_bar: {
2206 __kmp_hyper_barrier_release(bt, this_thr, gtid, tid,
2207 FALSE USE_ITT_BUILD_ARG(NULL));
2208 break;
2209 }
2210 case bp_hierarchical_bar: {
2211 __kmp_hierarchical_barrier_release(bt, this_thr, gtid, tid,
2212 FALSE USE_ITT_BUILD_ARG(NULL));
2213 break;
2214 }
2215 case bp_tree_bar: {
2217 __kmp_tree_barrier_release(bt, this_thr, gtid, tid,
2218 FALSE USE_ITT_BUILD_ARG(NULL));
2219 break;
2220 }
2221 default: {
2222 __kmp_linear_barrier_release(bt, this_thr, gtid, tid,
2223 FALSE USE_ITT_BUILD_ARG(NULL));
2224 }
2225 }
2227 __kmp_task_team_sync(this_thr, team);
2228 } // if
2229 }
2230 }
2231}
2232
2233void __kmp_join_barrier(int gtid) {
2234 KMP_TIME_PARTITIONED_BLOCK(OMP_join_barrier);
2235 KMP_SET_THREAD_STATE_BLOCK(FORK_JOIN_BARRIER);
2236
2238
2239 kmp_info_t *this_thr = __kmp_threads[gtid];
2240 kmp_team_t *team;
2241 int tid;
2242#ifdef KMP_DEBUG
2243 int team_id;
2244#endif /* KMP_DEBUG */
2245#if USE_ITT_BUILD
2246 void *itt_sync_obj = NULL;
2247#if USE_ITT_NOTIFY
2248 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) // Don't call routine without need
2249 // Get object created at fork_barrier
2250 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2251#endif
2252#endif /* USE_ITT_BUILD */
2253#if ((USE_ITT_BUILD && USE_ITT_NOTIFY) || defined KMP_DEBUG)
2254 int nproc = this_thr->th.th_team_nproc;
2255#endif
2256 KMP_MB();
2257
2258 // Get current info
2259 team = this_thr->th.th_team;
2260 KMP_DEBUG_ASSERT(nproc == team->t.t_nproc);
2261 tid = __kmp_tid_from_gtid(gtid);
2262#ifdef KMP_DEBUG
2263 team_id = team->t.t_id;
2264 kmp_info_t *master_thread = this_thr->th.th_team_master;
2265 if (master_thread != team->t.t_threads[0]) {
2267 }
2268#endif /* KMP_DEBUG */
2269 KMP_DEBUG_ASSERT(master_thread == team->t.t_threads[0]);
2270 KMP_MB();
2271
2272 // Verify state
2273 KMP_DEBUG_ASSERT(TCR_PTR(this_thr->th.th_team));
2274 KMP_DEBUG_ASSERT(TCR_PTR(this_thr->th.th_root));
2275 KMP_DEBUG_ASSERT(this_thr == team->t.t_threads[tid]);
2276 KA_TRACE(10, ("__kmp_join_barrier: T#%d(%d:%d) arrived at join barrier\n",
2277 gtid, team_id, tid));
2278
2279#if OMPT_SUPPORT
2280 if (ompt_enabled.enabled) {
2281#if OMPT_OPTIONAL
2282 ompt_data_t *my_task_data;
2283 ompt_data_t *my_parallel_data;
2284 void *codeptr = NULL;
2285 int ds_tid = this_thr->th.th_info.ds.ds_tid;
2286 if (KMP_MASTER_TID(ds_tid) &&
2287 (ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait) ||
2288 ompt_callbacks.ompt_callback(ompt_callback_sync_region)))
2289 codeptr = team->t.ompt_team_info.master_return_address;
2290 my_task_data = OMPT_CUR_TASK_DATA(this_thr);
2291 my_parallel_data = OMPT_CUR_TEAM_DATA(this_thr);
2292 ompt_sync_region_t sync_kind = ompt_sync_region_barrier_implicit_parallel;
2293 ompt_state_t ompt_state = ompt_state_wait_barrier_implicit_parallel;
2294 if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league) {
2295 sync_kind = ompt_sync_region_barrier_teams;
2296 ompt_state = ompt_state_wait_barrier_teams;
2297 }
2298 if (ompt_enabled.ompt_callback_sync_region) {
2299 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2300 sync_kind, ompt_scope_begin, my_parallel_data, my_task_data, codeptr);
2301 }
2302 if (ompt_enabled.ompt_callback_sync_region_wait) {
2303 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2304 sync_kind, ompt_scope_begin, my_parallel_data, my_task_data, codeptr);
2305 }
2306 if (!KMP_MASTER_TID(ds_tid))
2307 this_thr->th.ompt_thread_info.task_data = *OMPT_CUR_TASK_DATA(this_thr);
2308#endif
2309 this_thr->th.ompt_thread_info.state = ompt_state;
2310 }
2311#endif
2312
2314 __kmp_tasking_barrier(team, this_thr, gtid);
2315 KA_TRACE(10, ("__kmp_join_barrier: T#%d(%d:%d) past tasking barrier\n",
2316 gtid, team_id, tid));
2317 }
2318#ifdef KMP_DEBUG
2320 KA_TRACE(20, ("__kmp_join_barrier: T#%d, old team = %d, old task_team = "
2321 "%p, th_task_team = %p\n",
2322 __kmp_gtid_from_thread(this_thr), team_id,
2323 team->t.t_task_team[this_thr->th.th_task_state],
2324 this_thr->th.th_task_team));
2326 }
2327#endif /* KMP_DEBUG */
2328
2329 /* Copy the blocktime info to the thread, where __kmp_wait_template() can
2330 access it when the team struct is not guaranteed to exist. Doing these
2331 loads causes a cache miss slows down EPCC parallel by 2x. As a workaround,
2332 we do not perform the copy if blocktime=infinite, since the values are not
2333 used by __kmp_wait_template() in that case. */
2335#if KMP_USE_MONITOR
2336 this_thr->th.th_team_bt_intervals =
2337 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
2338 this_thr->th.th_team_bt_set =
2339 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
2340#else
2341 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
2342#endif
2343 }
2344
2345#if USE_ITT_BUILD
2346 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2347 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
2348#endif /* USE_ITT_BUILD */
2349
2351 case bp_dist_bar: {
2353 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2354 break;
2355 }
2356 case bp_hyper_bar: {
2358 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2359 break;
2360 }
2361 case bp_hierarchical_bar: {
2363 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2364 break;
2365 }
2366 case bp_tree_bar: {
2368 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2369 break;
2370 }
2371 default: {
2373 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2374 }
2375 }
2376
2377 /* From this point on, the team data structure may be deallocated at any time
2378 by the primary thread - it is unsafe to reference it in any of the worker
2379 threads. Any per-team data items that need to be referenced before the
2380 end of the barrier should be moved to the kmp_task_team_t structs. */
2381 if (KMP_MASTER_TID(tid)) {
2383 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
2384 }
2386 KMP_CHECK_UPDATE(team->t.t_display_affinity, 0);
2387 }
2388#if KMP_STATS_ENABLED
2389 // Have primary thread flag the workers to indicate they are now waiting for
2390 // next parallel region, Also wake them up so they switch their timers to
2391 // idle.
2392 for (int i = 0; i < team->t.t_nproc; ++i) {
2393 kmp_info_t *team_thread = team->t.t_threads[i];
2394 if (team_thread == this_thr)
2395 continue;
2396 team_thread->th.th_stats->setIdleFlag();
2398 team_thread->th.th_sleep_loc != NULL)
2399 __kmp_null_resume_wrapper(team_thread);
2400 }
2401#endif
2402#if USE_ITT_BUILD
2403 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2404 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2405#endif /* USE_ITT_BUILD */
2406
2407#if USE_ITT_BUILD && USE_ITT_NOTIFY
2408 // Join barrier - report frame end
2409 if ((__itt_frame_submit_v3_ptr || KMP_ITT_DEBUG) &&
2410 __kmp_forkjoin_frames_mode &&
2411 (this_thr->th.th_teams_microtask == NULL || // either not in teams
2412 this_thr->th.th_teams_size.nteams == 1) && // or inside single team
2413 team->t.t_active_level == 1) {
2414 kmp_uint64 cur_time = __itt_get_timestamp();
2415 ident_t *loc = team->t.t_ident;
2416 kmp_info_t **other_threads = team->t.t_threads;
2417 switch (__kmp_forkjoin_frames_mode) {
2418 case 1:
2419 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2420 loc, nproc);
2421 break;
2422 case 2:
2423 __kmp_itt_frame_submit(gtid, this_thr->th.th_bar_min_time, cur_time, 1,
2424 loc, nproc);
2425 break;
2426 case 3:
2427 if (__itt_metadata_add_ptr) {
2428 // Initialize with primary thread's wait time
2429 kmp_uint64 delta = cur_time - this_thr->th.th_bar_arrive_time;
2430 // Set arrive time to zero to be able to check it in
2431 // __kmp_invoke_task(); the same is done inside the loop below
2432 this_thr->th.th_bar_arrive_time = 0;
2433 for (int i = 1; i < nproc; ++i) {
2434 delta += (cur_time - other_threads[i]->th.th_bar_arrive_time);
2435 other_threads[i]->th.th_bar_arrive_time = 0;
2436 }
2437 __kmp_itt_metadata_imbalance(gtid, this_thr->th.th_frame_time,
2438 cur_time, delta, 0);
2439 }
2440 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2441 loc, nproc);
2442 this_thr->th.th_frame_time = cur_time;
2443 break;
2444 }
2445 }
2446#endif /* USE_ITT_BUILD */
2447 }
2448#if USE_ITT_BUILD
2449 else {
2450 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2451 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2452 }
2453#endif /* USE_ITT_BUILD */
2454
2455#if KMP_DEBUG
2456 if (KMP_MASTER_TID(tid)) {
2457 KA_TRACE(
2458 15,
2459 ("__kmp_join_barrier: T#%d(%d:%d) says all %d team threads arrived\n",
2460 gtid, team_id, tid, nproc));
2461 }
2462#endif /* KMP_DEBUG */
2463
2464 // TODO now, mark worker threads as done so they may be disbanded
2465 KMP_MB(); // Flush all pending memory write invalidates.
2466 KA_TRACE(10,
2467 ("__kmp_join_barrier: T#%d(%d:%d) leaving\n", gtid, team_id, tid));
2468
2469}
2470
2471// TODO release worker threads' fork barriers as we are ready instead of all at
2472// once
2473void __kmp_fork_barrier(int gtid, int tid) {
2474 KMP_TIME_PARTITIONED_BLOCK(OMP_fork_barrier);
2475 KMP_SET_THREAD_STATE_BLOCK(FORK_JOIN_BARRIER);
2476 kmp_info_t *this_thr = __kmp_threads[gtid];
2477 kmp_team_t *team = (tid == 0) ? this_thr->th.th_team : NULL;
2478#if USE_ITT_BUILD
2479 void *itt_sync_obj = NULL;
2480#endif /* USE_ITT_BUILD */
2481#ifdef KMP_DEBUG
2482 if (team)
2483 KA_TRACE(10, ("__kmp_fork_barrier: T#%d(%d:%d) has arrived\n", gtid,
2484 (team != NULL) ? team->t.t_id : -1, tid));
2485#endif
2486 // th_team pointer only valid for primary thread here
2487 if (KMP_MASTER_TID(tid)) {
2488#if USE_ITT_BUILD && USE_ITT_NOTIFY
2489 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2490 // Create itt barrier object
2491 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier, 1);
2492 __kmp_itt_barrier_middle(gtid, itt_sync_obj); // Call acquired/releasing
2493 }
2494#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2495
2496#ifdef KMP_DEBUG
2497 KMP_DEBUG_ASSERT(team);
2498 kmp_info_t **other_threads = team->t.t_threads;
2499 int i;
2500
2501 // Verify state
2502 KMP_MB();
2503
2504 for (i = 1; i < team->t.t_nproc; ++i) {
2505 KA_TRACE(500,
2506 ("__kmp_fork_barrier: T#%d(%d:0) checking T#%d(%d:%d) fork go "
2507 "== %u.\n",
2508 gtid, team->t.t_id, other_threads[i]->th.th_info.ds.ds_gtid,
2509 team->t.t_id, other_threads[i]->th.th_info.ds.ds_tid,
2510 other_threads[i]->th.th_bar[bs_forkjoin_barrier].bb.b_go));
2512 (TCR_4(other_threads[i]->th.th_bar[bs_forkjoin_barrier].bb.b_go) &
2514 KMP_DEBUG_ASSERT(other_threads[i]->th.th_team == team);
2515 }
2516#endif
2517
2519 __kmp_task_team_setup(this_thr, team);
2520
2521 /* The primary thread may have changed its blocktime between join barrier
2522 and fork barrier. Copy the blocktime info to the thread, where
2523 __kmp_wait_template() can access it when the team struct is not
2524 guaranteed to exist. */
2525 // See note about the corresponding code in __kmp_join_barrier() being
2526 // performance-critical
2528#if KMP_USE_MONITOR
2529 this_thr->th.th_team_bt_intervals =
2530 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
2531 this_thr->th.th_team_bt_set =
2532 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
2533#else
2534 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
2535#endif
2536 }
2537 } // primary thread
2538
2540 case bp_dist_bar: {
2542 TRUE USE_ITT_BUILD_ARG(NULL));
2543 break;
2544 }
2545 case bp_hyper_bar: {
2548 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2549 break;
2550 }
2551 case bp_hierarchical_bar: {
2553 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2554 break;
2555 }
2556 case bp_tree_bar: {
2559 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2560 break;
2561 }
2562 default: {
2564 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2565 }
2566 }
2567
2568#if OMPT_SUPPORT
2569 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
2570 if (ompt_enabled.enabled &&
2571 (ompt_state == ompt_state_wait_barrier_teams ||
2572 ompt_state == ompt_state_wait_barrier_implicit_parallel)) {
2573 int ds_tid = this_thr->th.th_info.ds.ds_tid;
2574 ompt_data_t *task_data = (team)
2575 ? OMPT_CUR_TASK_DATA(this_thr)
2576 : &(this_thr->th.ompt_thread_info.task_data);
2577 this_thr->th.ompt_thread_info.state = ompt_state_overhead;
2578#if OMPT_OPTIONAL
2579 void *codeptr = NULL;
2580 if (KMP_MASTER_TID(ds_tid) &&
2581 (ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait) ||
2582 ompt_callbacks.ompt_callback(ompt_callback_sync_region)))
2583 codeptr = team ? team->t.ompt_team_info.master_return_address : NULL;
2584 ompt_sync_region_t sync_kind = ompt_sync_region_barrier_implicit_parallel;
2585 if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league)
2586 sync_kind = ompt_sync_region_barrier_teams;
2587 if (ompt_enabled.ompt_callback_sync_region_wait) {
2588 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2589 sync_kind, ompt_scope_end, NULL, task_data, codeptr);
2590 }
2591 if (ompt_enabled.ompt_callback_sync_region) {
2592 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2593 sync_kind, ompt_scope_end, NULL, task_data, codeptr);
2594 }
2595#endif
2596 if (!KMP_MASTER_TID(ds_tid) && ompt_enabled.ompt_callback_implicit_task) {
2597 ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
2598 ompt_scope_end, NULL, task_data, 0, ds_tid,
2599 ompt_task_implicit); // TODO: Can this be ompt_task_initial?
2600 }
2601 }
2602#endif
2603
2604 // Early exit for reaping threads releasing forkjoin barrier
2605 if (TCR_4(__kmp_global.g.g_done)) {
2606 this_thr->th.th_task_team = NULL;
2607
2608#if USE_ITT_BUILD && USE_ITT_NOTIFY
2609 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2610 if (!KMP_MASTER_TID(tid)) {
2611 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2612 if (itt_sync_obj)
2613 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2614 }
2615 }
2616#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2617 KA_TRACE(10, ("__kmp_fork_barrier: T#%d is leaving early\n", gtid));
2618 return;
2619 }
2620
2621 /* We can now assume that a valid team structure has been allocated by the
2622 primary thread and propagated to all worker threads. The current thread,
2623 however, may not be part of the team, so we can't blindly assume that the
2624 team pointer is non-null. */
2625 team = (kmp_team_t *)TCR_PTR(this_thr->th.th_team);
2626 KMP_DEBUG_ASSERT(team != NULL);
2627 tid = __kmp_tid_from_gtid(gtid);
2628
2629#if KMP_BARRIER_ICV_PULL
2630 /* Primary thread's copy of the ICVs was set up on the implicit taskdata in
2631 __kmp_reinitialize_team. __kmp_fork_call() assumes the primary thread's
2632 implicit task has this data before this function is called. We cannot
2633 modify __kmp_fork_call() to look at the fixed ICVs in the primary thread's
2634 thread struct, because it is not always the case that the threads arrays
2635 have been allocated when __kmp_fork_call() is executed. */
2636 {
2638 if (!KMP_MASTER_TID(tid)) { // primary thread already has ICVs
2639 // Copy the initial ICVs from the primary thread's thread struct to the
2640 // implicit task for this tid.
2641 KA_TRACE(10,
2642 ("__kmp_fork_barrier: T#%d(%d) is PULLing ICVs\n", gtid, tid));
2643 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[tid], team,
2644 tid, FALSE);
2645 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
2646 &team->t.t_threads[0]
2647 ->th.th_bar[bs_forkjoin_barrier]
2648 .bb.th_fixed_icvs);
2649 }
2650 }
2651#endif // KMP_BARRIER_ICV_PULL
2652
2654 __kmp_task_team_sync(this_thr, team);
2655 }
2656
2657#if KMP_AFFINITY_SUPPORTED
2658 kmp_proc_bind_t proc_bind = team->t.t_proc_bind;
2659 if (proc_bind == proc_bind_intel) {
2660 // Call dynamic affinity settings
2661 if (__kmp_affinity.type == affinity_balanced && team->t.t_size_changed) {
2662 __kmp_balanced_affinity(this_thr, team->t.t_nproc);
2663 }
2664 } else if (proc_bind != proc_bind_false) {
2665 if (this_thr->th.th_new_place == this_thr->th.th_current_place) {
2666 KA_TRACE(100, ("__kmp_fork_barrier: T#%d already in correct place %d\n",
2667 __kmp_gtid_from_thread(this_thr),
2668 this_thr->th.th_current_place));
2669 } else {
2670 __kmp_affinity_bind_place(gtid);
2671 }
2672 }
2673#endif // KMP_AFFINITY_SUPPORTED
2674 // Perform the display affinity functionality
2676 if (team->t.t_display_affinity
2678 || (__kmp_affinity.type == affinity_balanced && team->t.t_size_changed)
2679#endif
2680 ) {
2681 // NULL means use the affinity-format-var ICV
2682 __kmp_aux_display_affinity(gtid, NULL);
2683 this_thr->th.th_prev_num_threads = team->t.t_nproc;
2684 this_thr->th.th_prev_level = team->t.t_level;
2685 }
2686 }
2687 if (!KMP_MASTER_TID(tid))
2688 KMP_CHECK_UPDATE(this_thr->th.th_def_allocator, team->t.t_def_allocator);
2689
2690#if USE_ITT_BUILD && USE_ITT_NOTIFY
2691 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2692 if (!KMP_MASTER_TID(tid)) {
2693 // Get correct barrier object
2694 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2695 __kmp_itt_barrier_finished(gtid, itt_sync_obj); // Workers call acquired
2696 } // (prepare called inside barrier_release)
2697 }
2698#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2699 KA_TRACE(10, ("__kmp_fork_barrier: T#%d(%d:%d) is leaving\n", gtid,
2700 team->t.t_id, tid));
2701}
2702
2703void __kmp_setup_icv_copy(kmp_team_t *team, int new_nproc,
2704 kmp_internal_control_t *new_icvs, ident_t *loc) {
2705 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_setup_icv_copy);
2706
2707 KMP_DEBUG_ASSERT(team && new_nproc && new_icvs);
2709
2710/* Primary thread's copy of the ICVs was set up on the implicit taskdata in
2711 __kmp_reinitialize_team. __kmp_fork_call() assumes the primary thread's
2712 implicit task has this data before this function is called. */
2713#if KMP_BARRIER_ICV_PULL
2714 /* Copy ICVs to primary thread's thread structure into th_fixed_icvs (which
2715 remains untouched), where all of the worker threads can access them and
2716 make their own copies after the barrier. */
2717 KMP_DEBUG_ASSERT(team->t.t_threads[0]); // The threads arrays should be
2718 // allocated at this point
2719 copy_icvs(
2720 &team->t.t_threads[0]->th.th_bar[bs_forkjoin_barrier].bb.th_fixed_icvs,
2721 new_icvs);
2722 KF_TRACE(10, ("__kmp_setup_icv_copy: PULL: T#%d this_thread=%p team=%p\n", 0,
2723 team->t.t_threads[0], team));
2724#elif KMP_BARRIER_ICV_PUSH
2725 // The ICVs will be propagated in the fork barrier, so nothing needs to be
2726 // done here.
2727 KF_TRACE(10, ("__kmp_setup_icv_copy: PUSH: T#%d this_thread=%p team=%p\n", 0,
2728 team->t.t_threads[0], team));
2729#else
2730 // Copy the ICVs to each of the non-primary threads. This takes O(nthreads)
2731 // time.
2732 ngo_load(new_icvs);
2733 KMP_DEBUG_ASSERT(team->t.t_threads[0]); // The threads arrays should be
2734 // allocated at this point
2735 for (int f = 1; f < new_nproc; ++f) { // Skip the primary thread
2736 // TODO: GEH - pass in better source location info since usually NULL here
2737 KF_TRACE(10, ("__kmp_setup_icv_copy: LINEAR: T#%d this_thread=%p team=%p\n",
2738 f, team->t.t_threads[f], team));
2739 __kmp_init_implicit_task(loc, team->t.t_threads[f], team, f, FALSE);
2740 ngo_store_icvs(&team->t.t_implicit_task_taskdata[f].td_icvs, new_icvs);
2741 KF_TRACE(10, ("__kmp_setup_icv_copy: LINEAR: T#%d this_thread=%p team=%p\n",
2742 f, team->t.t_threads[f], team));
2743 }
2744 ngo_sync();
2745#endif // KMP_BARRIER_ICV_PULL
2746}
char bool
size_t KMP_ALIGN_CACHE gos_per_group
kmp_uint64 go_release()
size_t KMP_ALIGN_CACHE num_groups
Definition kmp_barrier.h:99
size_t KMP_ALIGN_CACHE threads_per_group
size_t KMP_ALIGN_CACHE num_gos
Definition kmp_barrier.h:97
size_t KMP_ALIGN_CACHE threads_per_go
size_t KMP_ALIGN_CACHE num_threads
Definition kmp_barrier.h:94
size_t KMP_ALIGN_CACHE max_threads
Definition kmp_barrier.h:95
static void deallocate(distributedBarrier *db)
flags_s * flags[MAX_ITERS]
Definition kmp_barrier.h:89
distributedBarrier()=delete
bool KMP_ALIGN_CACHE fix_threads_per_go
bool wait(kmp_info_t *this_thr, int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj))
bool wait(kmp_info_t *this_thr, int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj))
bool wait(kmp_info_t *this_thr, int final_spin USE_ITT_BUILD_ARG(void *itt_sync_obj))
void set_waiter(kmp_info_t *thr)
void stop(char *errorMsg)
void
Definition ittnotify.h:3324
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 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
#define __kmp_free(ptr)
Definition kmp.h:3749
#define KMP_INTERNAL_MALLOC(sz)
Definition kmp.h:103
kmp_global_t __kmp_global
union kmp_task_team kmp_task_team_t
Definition kmp.h:243
void __kmp_teams_master(int gtid)
#define KMP_MAX_BLOCKTIME
Definition kmp.h:1245
#define KMP_INTERNAL_REALLOC(p, sz)
Definition kmp.h:105
void __kmp_task_team_sync(kmp_info_t *this_thr, kmp_team_t *team)
#define KMP_TASKDATA_TO_TASK(taskdata)
Definition kmp.h:2458
#define KMP_NOT_SAFE_TO_REAP
Definition kmp.h:2139
static kmp_team_t * __kmp_team_from_gtid(int gtid)
Definition kmp.h:3632
kmp_bar_pat_e __kmp_barrier_gather_pattern[bs_last_barrier]
kmp_tasking_mode_t __kmp_tasking_mode
void __kmp_abort_thread(void)
int __kmp_dflt_blocktime
void __kmp_get_hierarchy(kmp_uint32 nproc, kmp_bstate_t *thr_bar)
int __kmp_omp_cancellation
#define KMP_BARRIER_UNUSED_STATE
Definition kmp.h:2118
int __kmp_barrier_gomp_cancel(int gtid)
#define KMP_BARRIER_SLEEP_STATE
Definition kmp.h:2117
struct kmp_internal_control kmp_internal_control_t
static int __kmp_tid_from_gtid(int gtid)
Definition kmp.h:3612
#define KMP_MIN(x, y)
Definition kmp.h:290
#define KMP_DEBUG_ASSERT_TASKTEAM_INVARIANT(team, thr)
Definition kmp.h:4146
@ cancel_sections
Definition kmp.h:973
@ cancel_loop
Definition kmp.h:972
@ cancel_noreq
Definition kmp.h:970
#define KMP_CHECK_UPDATE(a, b)
Definition kmp.h:2374
#define KMP_MASTER_TID(tid)
Definition kmp.h:1332
kmp_uint32 __kmp_barrier_release_branch_bits[bs_last_barrier]
#define KMP_BARRIER_OWN_FLAG
Definition kmp.h:2130
void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr, kmp_team_t *team, int tid, int set_curr_task)
static void copy_icvs(kmp_internal_control_t *dst, kmp_internal_control_t *src)
Definition kmp.h:2205
#define KMP_TASKING_ENABLED(task_team)
Definition kmp.h:2462
kmp_info_t ** __kmp_threads
#define KMP_BARRIER_PARENT_FLAG
Definition kmp.h:2132
union kmp_team kmp_team_t
Definition kmp.h:241
#define KMP_MASTER_GTID(gtid)
Definition kmp.h:1335
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
void __kmp_tasking_barrier(kmp_team_t *team, kmp_info_t *thread, int gtid)
@ tskm_extra_barrier
Definition kmp.h:2439
@ tskm_immediate_exec
Definition kmp.h:2438
#define UNLIKELY(x)
Definition kmp.h:140
void __kmp_aux_display_affinity(int gtid, const char *format)
union kmp_barrier_team_union kmp_balign_team_t
Definition kmp.h:2269
#define KMP_INIT_BARRIER_STATE
Definition kmp.h:2112
kmp_uint32 __kmp_barrier_gather_branch_bits[bs_last_barrier]
#define KMP_BARRIER_NOT_WAITING
Definition kmp.h:2129
#define KMP_INTERNAL_FREE(p)
Definition kmp.h:104
static int __kmp_gtid_from_tid(int tid, const kmp_team_t *team)
Definition kmp.h:3617
#define KMP_BARRIER_SWITCHING
Definition kmp.h:2136
#define KMP_SAFE_TO_REAP
Definition kmp.h:2141
barrier_type
Definition kmp.h:2152
@ bs_plain_barrier
Definition kmp.h:2153
@ bs_last_barrier
Definition kmp.h:2159
@ bs_forkjoin_barrier
Definition kmp.h:2155
int __kmp_display_affinity
#define KMP_BLOCKTIME_INTERVAL(team, tid)
Definition kmp.h:1289
void __kmp_task_team_setup(kmp_info_t *this_thr, kmp_team_t *team)
int __kmp_atomic_execute_tasks_64(kmp_info_t *thread, kmp_int32 gtid, kmp_atomic_flag_64< C, S > *flag, int final_spin, int *thread_finished, kmp_int32 is_constrained)
kmp_proc_bind_t
Definition kmp.h:930
@ proc_bind_false
Definition kmp.h:931
@ proc_bind_intel
Definition kmp.h:936
@ KMP_HW_SOCKET
Definition kmp.h:593
@ KMP_HW_CORE
Definition kmp.h:603
#define KMP_BARRIER_STATE_BUMP
Definition kmp.h:2119
void __kmp_atomic_resume_64(int target_gtid, kmp_atomic_flag_64< C, S > *flag)
static int __kmp_gtid_from_thread(const kmp_info_t *thr)
Definition kmp.h:3622
static void __kmp_type_convert(T1 src, T2 *dest)
Definition kmp.h:4878
struct KMP_ALIGN_CACHE kmp_bstate kmp_bstate_t
kmp_bar_pat_e __kmp_barrier_release_pattern[bs_last_barrier]
@ bp_dist_bar
Definition kmp.h:2175
@ bp_tree_bar
Definition kmp.h:2170
@ bp_hierarchical_bar
Definition kmp.h:2174
@ bp_hyper_bar
Definition kmp.h:2172
union KMP_ALIGN_CACHE kmp_info kmp_info_t
void __kmp_task_team_wait(kmp_info_t *this_thr, kmp_team_t *team, int wait=1)
kmp_topology_t * __kmp_topology
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
static bool __kmp_linear_barrier_gather_template(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, void(*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj))
static void __kmp_dist_barrier_release(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj))
#define ngo_load(src)
static void __kmp_tree_barrier_release(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj))
#define ngo_store_icvs(dst, src)
static bool __kmp_linear_barrier_release_template(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj))
#define ngo_store_go(dst, src)
int __kmp_barrier(enum barrier_type bt, int gtid, int is_split, size_t reduce_size, void *reduce_data, void(*reduce)(void *, void *))
#define ngo_sync()
void __kmp_setup_icv_copy(kmp_team_t *team, int new_nproc, kmp_internal_control_t *new_icvs, ident_t *loc)
static void __kmp_hyper_barrier_gather(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, void(*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj))
void __kmp_join_barrier(int gtid)
static void __kmp_tree_barrier_gather(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, void(*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj))
void __kmp_end_split_barrier(enum barrier_type bt, int gtid)
static bool __kmp_linear_barrier_release_cancellable(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj))
static bool __kmp_linear_barrier_gather_cancellable(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, void(*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj))
static int __kmp_barrier_template(enum barrier_type bt, int gtid, int is_split, size_t reduce_size, void *reduce_data, void(*reduce)(void *, void *))
static void __kmp_linear_barrier_gather(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, void(*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj))
void __kmp_print_structure(void)
static void __kmp_hyper_barrier_release(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj))
void __kmp_dist_barrier_wakeup(enum barrier_type bt, kmp_team_t *team, size_t start, size_t stop, size_t inc, size_t tid)
static void __kmp_hierarchical_barrier_release(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj))
static bool __kmp_init_hierarchical_barrier_thread(enum barrier_type bt, kmp_bstate_t *thr_bar, kmp_uint32 nproc, int gtid, int tid, kmp_team_t *team)
#define __kmp_msb_byteoffset(offset)
void __kmp_fork_barrier(int gtid, int tid)
static void __kmp_dist_barrier_gather(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, void(*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj))
static void __kmp_hierarchical_barrier_gather(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, void(*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj))
static void __kmp_linear_barrier_release(enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid, int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj))
#define KMP_OPTIMIZE_FOR_REDUCTIONS
Definition kmp_barrier.h:57
#define KMP_ALIGNED_FREE(ptr)
Definition kmp_barrier.h:47
#define KA_TRACE(d, x)
Definition kmp_debug.h:157
#define KMP_ASSERT(cond)
Definition kmp_debug.h:59
#define KF_TRACE(d, x)
Definition kmp_debug.h:162
#define KMP_DEBUG_ASSERT(cond)
Definition kmp_debug.h:61
unsigned long long kmp_uint64
static volatile kmp_i18n_cat_status_t status
Definition kmp_i18n.cpp:48
#define USE_ITT_BUILD_ARG(x)
Definition kmp_itt.h:346
#define TCW_8(a, b)
Definition kmp_os.h:1146
void(* microtask_t)(int *gtid, int *npr,...)
Definition kmp_os.h:1189
#define KMP_TEST_THEN_AND64(p, v)
Definition kmp_os.h:802
#define TCR_PTR(a)
Definition kmp_os.h:1170
#define RCAST(type, var)
Definition kmp_os.h:294
#define KMP_CACHE_PREFETCH(ADDR)
Definition kmp_os.h:350
#define KMP_ATOMIC_ST_RLX(p, v)
Definition kmp_os.h:1266
#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
#define KMP_MFENCE()
Definition kmp_os.h:1103
#define KMP_AFFINITY_SUPPORTED
Definition kmp_os.h:88
#define KMP_COMPARE_AND_STORE_ACQ32(p, cv, sv)
Definition kmp_os.h:818
#define TCW_4(a, b)
Definition kmp_os.h:1142
#define TCR_SYNC_4(a)
Definition kmp_os.h:1149
Functions for collecting statistics.
#define KMP_SET_THREAD_STATE_BLOCK(state_name)
Definition kmp_stats.h:1018
#define KMP_TIME_PARTITIONED_BLOCK(name)
Definition kmp_stats.h:1013
#define KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(n)
Definition kmp_stats.h:1008
#define i
Definition kmp_stub.cpp:87
static void __kmp_null_resume_wrapper(kmp_info_t *thr)
int32_t kmp_int32
ompt_callbacks_active_t ompt_enabled
ompt_callbacks_internal_t ompt_callbacks
ompt_sync_region_t __ompt_get_barrier_kind(enum barrier_type bt, kmp_info_t *thr)
#define OMPT_REDUCTION_BEGIN
#define OMPT_REDUCTION_DECL(this_thr, gtid)
#define OMPT_REDUCTION_END
static id loc
volatile int flag
is_cancellable & operator=(bool b)
is_cancellable & operator=(bool b)
KMP_ALIGN_CACHE volatile kmp_uint32 tt_active
Definition kmp.h:2873
kmp_uint64 b_arrived
Definition kmp.h:2257
kmp_base_task_team_t tt
Definition kmp.h:2877
kmp_base_team_t t
Definition kmp.h:3227