LLVM OpenMP* Runtime Library
kmp_barrier.cpp
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) {
65 if (KMP_OPTIMIZE_FOR_REDUCTIONS) {
66 threads_per_go = threads_per_go >> 1;
67 }
68 if (threads_per_go > 4 && nsockets == 1)
69 threads_per_go = threads_per_go >> 1;
70 }
71 }
72 if (threads_per_go == 0)
73 threads_per_go = 1;
74 fix_threads_per_go = true;
75 num_gos = n / threads_per_go;
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;
87 gos_per_group = num_gos / num_groups;
88 if (num_gos % num_groups)
89 gos_per_group++;
90 threads_per_group = threads_per_go * gos_per_group;
91 } else {
92 num_gos = n / threads_per_go;
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 }
102 gos_per_group = num_gos / num_groups;
103 if (num_gos % num_groups)
104 gos_per_group++;
105 threads_per_group = threads_per_go * gos_per_group;
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;
114 threads_per_go = n / num_gos;
115 if (n % num_gos)
116 threads_per_go++;
117 while (num_gos > MAX_GOS) {
118 threads_per_go++;
119 num_gos = n / threads_per_go;
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) {
129 KMP_DEBUG_ASSERT(nthr > max_threads);
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
163kmp_uint64 distributedBarrier::go_release() {
164 kmp_uint64 next_go = iter[0].iter + distributedBarrier::MAX_ITERS;
165 for (size_t j = 0; j < num_gos; j++) {
166 go[j].go.store(next_go);
167 }
168 return next_go;
169}
170
171void distributedBarrier::go_reset() {
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)
205 team_icvs = __kmp_allocate(sizeof(kmp_internal_control_t));
206}
207
208void distributedBarrier::deallocate(distributedBarrier *db) {
209 for (int i = 0; i < MAX_ITERS; ++i) {
210 if (db->flags[i])
211 KMP_INTERNAL_FREE(db->flags[i]);
212 db->flags[i] = NULL;
213 }
214 if (db->go) {
215 KMP_INTERNAL_FREE(db->go);
216 db->go = NULL;
217 }
218 if (db->iter) {
219 KMP_INTERNAL_FREE(db->iter);
220 db->iter = NULL;
221 }
222 if (db->sleep) {
223 KMP_INTERNAL_FREE(db->sleep);
224 db->sleep = NULL;
225 }
226 if (db->team_icvs) {
227 __kmp_free(db->team_icvs);
228 db->team_icvs = NULL;
229 }
230 KMP_ALIGNED_FREE(db);
231}
232
233// This function is used only when KMP_BLOCKTIME is not infinite.
234// static
235void __kmp_dist_barrier_wakeup(enum barrier_type bt, kmp_team_t *team,
236 size_t start, size_t stop, size_t inc,
237 size_t tid) {
238 KMP_DEBUG_ASSERT(__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME);
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
247 __kmp_atomic_resume_64(gtid, (kmp_atomic_flag_64<> *)NULL);
248 }
249}
250
251static void __kmp_dist_barrier_gather(
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)) {
254 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_dist_gather);
255 kmp_team_t *team;
256 distributedBarrier *b;
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
301 if (__kmp_tasking_mode != tskm_immediate_exec) {
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;
307 __kmp_atomic_execute_tasks_64(
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)
319 __kmp_abort_thread();
320 break;
321 } else if (__kmp_tasking_mode != tskm_immediate_exec &&
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);
332 OMPT_REDUCTION_BEGIN;
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 }
338 OMPT_REDUCTION_END;
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
356 if (__kmp_tasking_mode != tskm_immediate_exec) {
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;
362 __kmp_atomic_execute_tasks_64(
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)
374 __kmp_abort_thread();
375 break;
376 } else if (__kmp_tasking_mode != tskm_immediate_exec &&
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);
387 OMPT_REDUCTION_BEGIN;
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 }
393 OMPT_REDUCTION_END;
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
413static void __kmp_dist_barrier_release(
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;
418 distributedBarrier *b;
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
491 kmp_atomic_flag_64<false, true> my_flag(
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
560 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
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
575 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
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>
595static bool __kmp_linear_barrier_gather_template(
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) {
653 kmp_flag_64<true, false> flag(
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);
676 OMPT_REDUCTION_BEGIN;
677 (*reduce)(this_thr->th.th_local.reduce_data,
678 other_threads[i]->th.th_local.reduce_data);
679 OMPT_REDUCTION_END;
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>
697static bool __kmp_linear_barrier_release_template(
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 {
720 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_icv_copy);
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) {
758 kmp_flag_64<true, false> flag(&thr_bar->b_go, KMP_BARRIER_STATE_BUMP);
759 if (flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj)))
760 return true;
761 } else {
762 kmp_flag_64<> flag(&thr_bar->b_go, KMP_BARRIER_STATE_BUMP);
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
804static void __kmp_linear_barrier_gather(
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)) {
807 __kmp_linear_barrier_gather_template<false>(
808 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
809}
810
811static bool __kmp_linear_barrier_gather_cancellable(
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)) {
814 return __kmp_linear_barrier_gather_template<true>(
815 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
816}
817
818static void __kmp_linear_barrier_release(
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)) {
821 __kmp_linear_barrier_release_template<false>(
822 bt, this_thr, gtid, tid, propagate_icvs USE_ITT_BUILD_ARG(itt_sync_obj));
823}
824
825static bool __kmp_linear_barrier_release_cancellable(
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)) {
828 return __kmp_linear_barrier_release_template<true>(
829 bt, this_thr, gtid, tid, propagate_icvs USE_ITT_BUILD_ARG(itt_sync_obj));
830}
831
832// Tree barrier
833static void __kmp_tree_barrier_gather(
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)) {
836 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_tree_gather);
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;
841 kmp_uint32 branch_bits = __kmp_barrier_gather_branch_bits[bt];
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)
872 KMP_CACHE_PREFETCH(
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);
897 OMPT_REDUCTION_BEGIN;
898 (*reduce)(this_thr->th.th_local.reduce_data,
899 child_thr->th.th_local.reduce_data);
900 OMPT_REDUCTION_END;
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
939static void __kmp_tree_barrier_release(
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;
946 kmp_uint32 branch_bits = __kmp_barrier_release_branch_bits[bt];
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
957 kmp_flag_64<> flag(&thr_bar->b_go, KMP_BARRIER_STATE_BUMP);
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)
1010 KMP_CACHE_PREFETCH(
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 {
1016 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_icv_copy);
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
1045static void __kmp_hyper_barrier_gather(
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;
1052 kmp_uint64 new_state = KMP_BARRIER_UNUSED_STATE;
1053 kmp_uint32 num_threads = this_thr->th.th_team_nproc;
1054 kmp_uint32 branch_bits = __kmp_barrier_gather_branch_bits[bt];
1055 kmp_uint32 branch_factor = 1 << branch_bits;
1056 kmp_uint32 offset;
1057 kmp_uint32 level;
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)
1112 KMP_CACHE_PREFETCH(
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);
1138 OMPT_REDUCTION_BEGIN;
1139 (*reduce)(this_thr->th.th_local.reduce_data,
1140 child_thr->th.th_local.reduce_data);
1141 OMPT_REDUCTION_END;
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
1164static void __kmp_hyper_barrier_release(
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;
1172 kmp_uint32 branch_bits = __kmp_barrier_release_branch_bits[bt];
1173 kmp_uint32 branch_factor = 1 << branch_bits;
1174 kmp_uint32 child;
1175 kmp_uint32 child_tid;
1176 kmp_uint32 offset;
1177 kmp_uint32 level;
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
1282 KMP_CACHE_PREFETCH(
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. */
1329static bool __kmp_init_hierarchical_barrier_thread(enum barrier_type bt,
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
1412static void __kmp_hierarchical_barrier_gather(
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;
1451 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
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);
1466 OMPT_REDUCTION_BEGIN;
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 }
1477 OMPT_REDUCTION_END;
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
1580static void __kmp_hierarchical_barrier_release(
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);
1672 } else if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
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;
1695 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
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) {}
1800 is_cancellable(bool b) : value(b) {}
1801 is_cancellable &operator=(bool b) {
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;
1830 is_cancellable<cancellable> cancelled;
1831#if OMPT_SUPPORT
1832 ompt_sync_region_t barrier_kind;
1833#if OMPT_OPTIONAL
1834 ompt_data_t *my_task_data;
1835 ompt_data_t *my_parallel_data;
1836 void *return_address;
1837#endif
1838#endif
1839
1840 KA_TRACE(15, ("__kmp_barrier: T#%d(%d:%d) has arrived\n", gtid,
1841 __kmp_team_from_gtid(gtid)->t.t_id, __kmp_tid_from_gtid(gtid)));
1842
1843#if OMPT_SUPPORT
1844 if (ompt_enabled.enabled) {
1845 barrier_kind = __ompt_get_barrier_kind(bt, this_thr);
1846#if OMPT_OPTIONAL
1847 my_task_data = OMPT_CUR_TASK_DATA(this_thr);
1848 my_parallel_data = OMPT_CUR_TEAM_DATA(this_thr);
1849 return_address = OMPT_LOAD_RETURN_ADDRESS(gtid);
1850 if (ompt_enabled.ompt_callback_sync_region) {
1851 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
1852 barrier_kind, ompt_scope_begin, my_parallel_data, my_task_data,
1853 return_address);
1854 }
1855 if (ompt_enabled.ompt_callback_sync_region_wait) {
1856 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
1857 barrier_kind, ompt_scope_begin, my_parallel_data, my_task_data,
1858 return_address);
1859 }
1860#endif
1861 // It is OK to report the barrier state after the barrier begin callback.
1862 // According to the OMPT specification, a compliant implementation may
1863 // even delay reporting this state until the barrier begins to wait.
1864 auto *ompt_thr_info = &this_thr->th.ompt_thread_info;
1865 switch (barrier_kind) {
1866 case ompt_sync_region_barrier_explicit:
1867 ompt_thr_info->state = ompt_state_wait_barrier_explicit;
1868 break;
1869 case ompt_sync_region_barrier_implicit_workshare:
1870 ompt_thr_info->state = ompt_state_wait_barrier_implicit_workshare;
1871 break;
1872 case ompt_sync_region_barrier_implicit_parallel:
1873 ompt_thr_info->state = ompt_state_wait_barrier_implicit_parallel;
1874 break;
1875 case ompt_sync_region_barrier_teams:
1876 ompt_thr_info->state = ompt_state_wait_barrier_teams;
1877 break;
1878 case ompt_sync_region_barrier_implementation:
1879 [[fallthrough]];
1880 default:
1881 ompt_thr_info->state = ompt_state_wait_barrier_implementation;
1882 }
1883 }
1884#endif
1885
1886#if ENABLE_LIBOMPTARGET
1887 // Give an opportunity to the offload runtime to make progress and create
1888 // proxy tasks if necessary
1889 if (UNLIKELY(kmp_target_sync_cb != NULL))
1890 (*kmp_target_sync_cb)(
1891 NULL, gtid, KMP_TASKDATA_TO_TASK(this_thr->th.th_current_task), NULL);
1892#endif
1893
1894 if (!team->t.t_serialized) {
1895#if USE_ITT_BUILD
1896 // This value will be used in itt notify events below.
1897 void *itt_sync_obj = NULL;
1898#if USE_ITT_NOTIFY
1899 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
1900 itt_sync_obj = __kmp_itt_barrier_object(gtid, bt, 1);
1901#endif
1902#endif /* USE_ITT_BUILD */
1903 if (__kmp_tasking_mode == tskm_extra_barrier) {
1904 __kmp_tasking_barrier(team, this_thr, gtid);
1905 KA_TRACE(15,
1906 ("__kmp_barrier: T#%d(%d:%d) past tasking barrier\n", gtid,
1907 __kmp_team_from_gtid(gtid)->t.t_id, __kmp_tid_from_gtid(gtid)));
1908 }
1909
1910 /* Copy the blocktime info to the thread, where __kmp_wait_template() can
1911 access it when the team struct is not guaranteed to exist. */
1912 // See note about the corresponding code in __kmp_join_barrier() being
1913 // performance-critical.
1914 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
1915#if KMP_USE_MONITOR
1916 this_thr->th.th_team_bt_intervals =
1917 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
1918 this_thr->th.th_team_bt_set =
1919 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
1920#else
1921 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
1922#endif
1923 }
1924
1925#if USE_ITT_BUILD
1926 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
1927 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
1928#endif /* USE_ITT_BUILD */
1929#if USE_DEBUGGER
1930 // Let the debugger know: the thread arrived to the barrier and waiting.
1931 if (KMP_MASTER_TID(tid)) { // Primary thread counter stored in team struct
1932 team->t.t_bar[bt].b_master_arrived += 1;
1933 } else {
1934 this_thr->th.th_bar[bt].bb.b_worker_arrived += 1;
1935 } // if
1936#endif /* USE_DEBUGGER */
1937 if (reduce != NULL) {
1938 // KMP_DEBUG_ASSERT( is_split == TRUE ); // #C69956
1939 this_thr->th.th_local.reduce_data = reduce_data;
1940 }
1941
1942 if (KMP_MASTER_TID(tid) && __kmp_tasking_mode != tskm_immediate_exec)
1943 __kmp_task_team_setup(this_thr, team);
1944
1945 if (cancellable) {
1946 cancelled = __kmp_linear_barrier_gather_cancellable(
1947 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1948 } else {
1949 switch (__kmp_barrier_gather_pattern[bt]) {
1950 case bp_dist_bar: {
1951 __kmp_dist_barrier_gather(bt, this_thr, gtid, tid,
1952 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1953 break;
1954 }
1955 case bp_hyper_bar: {
1956 __kmp_hyper_barrier_gather(bt, this_thr, gtid, tid,
1957 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1958 break;
1959 }
1960 case bp_hierarchical_bar: {
1961 __kmp_hierarchical_barrier_gather(
1962 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1963 break;
1964 }
1965 case bp_tree_bar: {
1966 __kmp_tree_barrier_gather(bt, this_thr, gtid, tid,
1967 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1968 break;
1969 }
1970 default: {
1971 __kmp_linear_barrier_gather(bt, this_thr, gtid, tid,
1972 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1973 }
1974 }
1975 }
1976
1977 KMP_MB();
1978
1979 if (KMP_MASTER_TID(tid)) {
1980 status = 0;
1981 if (__kmp_tasking_mode != tskm_immediate_exec && !cancelled) {
1982 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
1983 }
1984#if USE_DEBUGGER
1985 // Let the debugger know: All threads are arrived and starting leaving the
1986 // barrier.
1987 team->t.t_bar[bt].b_team_arrived += 1;
1988#endif
1989
1990 if (__kmp_omp_cancellation) {
1991 kmp_int32 cancel_request = KMP_ATOMIC_LD_RLX(&team->t.t_cancel_request);
1992 // Reset cancellation flag for worksharing constructs
1993 if (cancel_request == cancel_loop ||
1994 cancel_request == cancel_sections) {
1995 KMP_ATOMIC_ST_RLX(&team->t.t_cancel_request, cancel_noreq);
1996 }
1997 }
1998#if USE_ITT_BUILD
1999 /* TODO: In case of split reduction barrier, primary thread may send
2000 acquired event early, before the final summation into the shared
2001 variable is done (final summation can be a long operation for array
2002 reductions). */
2003 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2004 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2005#endif /* USE_ITT_BUILD */
2006#if USE_ITT_BUILD && USE_ITT_NOTIFY
2007 // Barrier - report frame end (only if active_level == 1)
2008 if ((__itt_frame_submit_v3_ptr || KMP_ITT_DEBUG) &&
2009 __kmp_forkjoin_frames_mode &&
2010 (this_thr->th.th_teams_microtask == NULL || // either not in teams
2011 this_thr->th.th_teams_size.nteams == 1) && // or inside single team
2012 team->t.t_active_level == 1) {
2013 ident_t *loc = __kmp_threads[gtid]->th.th_ident;
2014 kmp_uint64 cur_time = __itt_get_timestamp();
2015 kmp_info_t **other_threads = team->t.t_threads;
2016 int nproc = this_thr->th.th_team_nproc;
2017 int i;
2018 switch (__kmp_forkjoin_frames_mode) {
2019 case 1:
2020 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2021 loc, nproc);
2022 this_thr->th.th_frame_time = cur_time;
2023 break;
2024 case 2: // AC 2015-01-19: currently does not work for hierarchical (to
2025 // be fixed)
2026 __kmp_itt_frame_submit(gtid, this_thr->th.th_bar_min_time, cur_time,
2027 1, loc, nproc);
2028 break;
2029 case 3:
2030 if (__itt_metadata_add_ptr) {
2031 // Initialize with primary thread's wait time
2032 kmp_uint64 delta = cur_time - this_thr->th.th_bar_arrive_time;
2033 // Set arrive time to zero to be able to check it in
2034 // __kmp_invoke_task(); the same is done inside the loop below
2035 this_thr->th.th_bar_arrive_time = 0;
2036 for (i = 1; i < nproc; ++i) {
2037 delta += (cur_time - other_threads[i]->th.th_bar_arrive_time);
2038 other_threads[i]->th.th_bar_arrive_time = 0;
2039 }
2040 __kmp_itt_metadata_imbalance(gtid, this_thr->th.th_frame_time,
2041 cur_time, delta,
2042 (kmp_uint64)(reduce != NULL));
2043 }
2044 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2045 loc, nproc);
2046 this_thr->th.th_frame_time = cur_time;
2047 break;
2048 }
2049 }
2050#endif /* USE_ITT_BUILD */
2051 } else {
2052 status = 1;
2053#if USE_ITT_BUILD
2054 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2055 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2056#endif /* USE_ITT_BUILD */
2057 }
2058 if ((status == 1 || !is_split) && !cancelled) {
2059 if (cancellable) {
2060 cancelled = __kmp_linear_barrier_release_cancellable(
2061 bt, this_thr, gtid, tid, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2062 } else {
2063 switch (__kmp_barrier_release_pattern[bt]) {
2064 case bp_dist_bar: {
2065 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2066 __kmp_dist_barrier_release(bt, this_thr, gtid, tid,
2067 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2068 break;
2069 }
2070 case bp_hyper_bar: {
2071 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2072 __kmp_hyper_barrier_release(bt, this_thr, gtid, tid,
2073 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2074 break;
2075 }
2076 case bp_hierarchical_bar: {
2077 __kmp_hierarchical_barrier_release(
2078 bt, this_thr, gtid, tid, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2079 break;
2080 }
2081 case bp_tree_bar: {
2082 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2083 __kmp_tree_barrier_release(bt, this_thr, gtid, tid,
2084 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2085 break;
2086 }
2087 default: {
2088 __kmp_linear_barrier_release(bt, this_thr, gtid, tid,
2089 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2090 }
2091 }
2092 }
2093 if (__kmp_tasking_mode != tskm_immediate_exec && !cancelled) {
2094 __kmp_task_team_sync(this_thr, team);
2095 }
2096 }
2097
2098#if USE_ITT_BUILD
2099 /* GEH: TODO: Move this under if-condition above and also include in
2100 __kmp_end_split_barrier(). This will more accurately represent the actual
2101 release time of the threads for split barriers. */
2102 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2103 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2104#endif /* USE_ITT_BUILD */
2105 } else { // Team is serialized.
2106 status = 0;
2107 if (__kmp_tasking_mode != tskm_immediate_exec) {
2108 if (this_thr->th.th_task_team != NULL) {
2109#if USE_ITT_NOTIFY
2110 void *itt_sync_obj = NULL;
2111 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2112 itt_sync_obj = __kmp_itt_barrier_object(gtid, bt, 1);
2113 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
2114 }
2115#endif
2116
2117 KMP_DEBUG_ASSERT(
2118 this_thr->th.th_task_team->tt.tt_found_proxy_tasks == TRUE ||
2119 this_thr->th.th_task_team->tt.tt_hidden_helper_task_encountered ==
2120 TRUE);
2121 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
2122 __kmp_task_team_setup(this_thr, team);
2123
2124#if USE_ITT_BUILD
2125 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2126 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2127#endif /* USE_ITT_BUILD */
2128 }
2129 }
2130 }
2131 KA_TRACE(15, ("__kmp_barrier: T#%d(%d:%d) is leaving with return value %d\n",
2132 gtid, __kmp_team_from_gtid(gtid)->t.t_id,
2133 __kmp_tid_from_gtid(gtid), status));
2134
2135#if OMPT_SUPPORT
2136 if (ompt_enabled.enabled) {
2137#if OMPT_OPTIONAL
2138 if (ompt_enabled.ompt_callback_sync_region_wait) {
2139 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2140 barrier_kind, ompt_scope_end, my_parallel_data, my_task_data,
2141 return_address);
2142 }
2143 if (ompt_enabled.ompt_callback_sync_region) {
2144 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2145 barrier_kind, ompt_scope_end, my_parallel_data, my_task_data,
2146 return_address);
2147 }
2148#endif
2149 this_thr->th.ompt_thread_info.state = ompt_state_work_parallel;
2150 }
2151#endif
2152
2153 if (cancellable)
2154 return (int)cancelled;
2155 return status;
2156}
2157
2158// Returns 0 if primary thread, 1 if worker thread.
2159int __kmp_barrier(enum barrier_type bt, int gtid, int is_split,
2160 size_t reduce_size, void *reduce_data,
2161 void (*reduce)(void *, void *)) {
2162 return __kmp_barrier_template<>(bt, gtid, is_split, reduce_size, reduce_data,
2163 reduce);
2164}
2165
2166#if defined(KMP_GOMP_COMPAT)
2167// Returns 1 if cancelled, 0 otherwise
2168int __kmp_barrier_gomp_cancel(int gtid) {
2169 if (__kmp_omp_cancellation) {
2170 int cancelled = __kmp_barrier_template<true>(bs_plain_barrier, gtid, FALSE,
2171 0, NULL, NULL);
2172 if (cancelled) {
2173 int tid = __kmp_tid_from_gtid(gtid);
2174 kmp_info_t *this_thr = __kmp_threads[gtid];
2175 if (KMP_MASTER_TID(tid)) {
2176 // Primary thread does not need to revert anything
2177 } else {
2178 // Workers need to revert their private b_arrived flag
2179 this_thr->th.th_bar[bs_plain_barrier].bb.b_arrived -=
2180 KMP_BARRIER_STATE_BUMP;
2181 }
2182 }
2183 return cancelled;
2184 }
2185 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
2186 return FALSE;
2187}
2188#endif
2189
2190void __kmp_end_split_barrier(enum barrier_type bt, int gtid) {
2191 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_end_split_barrier);
2192 KMP_SET_THREAD_STATE_BLOCK(PLAIN_BARRIER);
2193 KMP_DEBUG_ASSERT(bt < bs_last_barrier);
2194 int tid = __kmp_tid_from_gtid(gtid);
2195 kmp_info_t *this_thr = __kmp_threads[gtid];
2196 kmp_team_t *team = this_thr->th.th_team;
2197
2198 if (!team->t.t_serialized) {
2199 if (KMP_MASTER_GTID(gtid)) {
2200 switch (__kmp_barrier_release_pattern[bt]) {
2201 case bp_dist_bar: {
2202 __kmp_dist_barrier_release(bt, this_thr, gtid, tid,
2203 FALSE USE_ITT_BUILD_ARG(NULL));
2204 break;
2205 }
2206 case bp_hyper_bar: {
2207 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2208 __kmp_hyper_barrier_release(bt, this_thr, gtid, tid,
2209 FALSE USE_ITT_BUILD_ARG(NULL));
2210 break;
2211 }
2212 case bp_hierarchical_bar: {
2213 __kmp_hierarchical_barrier_release(bt, this_thr, gtid, tid,
2214 FALSE USE_ITT_BUILD_ARG(NULL));
2215 break;
2216 }
2217 case bp_tree_bar: {
2218 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2219 __kmp_tree_barrier_release(bt, this_thr, gtid, tid,
2220 FALSE USE_ITT_BUILD_ARG(NULL));
2221 break;
2222 }
2223 default: {
2224 __kmp_linear_barrier_release(bt, this_thr, gtid, tid,
2225 FALSE USE_ITT_BUILD_ARG(NULL));
2226 }
2227 }
2228 if (__kmp_tasking_mode != tskm_immediate_exec) {
2229 __kmp_task_team_sync(this_thr, team);
2230 } // if
2231 }
2232 }
2233}
2234
2235void __kmp_join_barrier(int gtid) {
2236 KMP_TIME_PARTITIONED_BLOCK(OMP_join_barrier);
2237 KMP_SET_THREAD_STATE_BLOCK(FORK_JOIN_BARRIER);
2238
2239 KMP_DEBUG_ASSERT(__kmp_threads && __kmp_threads[gtid]);
2240
2241 kmp_info_t *this_thr = __kmp_threads[gtid];
2242 kmp_team_t *team;
2243 int tid;
2244#ifdef KMP_DEBUG
2245 int team_id;
2246#endif /* KMP_DEBUG */
2247#if USE_ITT_BUILD
2248 void *itt_sync_obj = NULL;
2249#if USE_ITT_NOTIFY
2250 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) // Don't call routine without need
2251 // Get object created at fork_barrier
2252 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2253#endif
2254#endif /* USE_ITT_BUILD */
2255#if ((USE_ITT_BUILD && USE_ITT_NOTIFY) || defined KMP_DEBUG)
2256 int nproc = this_thr->th.th_team_nproc;
2257#endif
2258 KMP_MB();
2259
2260 // Get current info
2261 team = this_thr->th.th_team;
2262 KMP_DEBUG_ASSERT(nproc == team->t.t_nproc);
2263 tid = __kmp_tid_from_gtid(gtid);
2264#ifdef KMP_DEBUG
2265 team_id = team->t.t_id;
2266 kmp_info_t *master_thread = this_thr->th.th_team_master;
2267 if (master_thread != team->t.t_threads[0]) {
2268 __kmp_print_structure();
2269 }
2270#endif /* KMP_DEBUG */
2271 KMP_DEBUG_ASSERT(master_thread == team->t.t_threads[0]);
2272 KMP_MB();
2273
2274 // Verify state
2275 KMP_DEBUG_ASSERT(TCR_PTR(this_thr->th.th_team));
2276 KMP_DEBUG_ASSERT(TCR_PTR(this_thr->th.th_root));
2277 KMP_DEBUG_ASSERT(this_thr == team->t.t_threads[tid]);
2278 KA_TRACE(10, ("__kmp_join_barrier: T#%d(%d:%d) arrived at join barrier\n",
2279 gtid, team_id, tid));
2280
2281#if OMPT_SUPPORT
2282 if (ompt_enabled.enabled) {
2283 ompt_state_t ompt_state = ompt_state_wait_barrier_implicit_parallel;
2284 if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league)
2285 ompt_state = ompt_state_wait_barrier_teams;
2286#if OMPT_OPTIONAL
2287 ompt_data_t *my_task_data;
2288 ompt_data_t *my_parallel_data;
2289 void *codeptr = NULL;
2290 int ds_tid = this_thr->th.th_info.ds.ds_tid;
2291 if (KMP_MASTER_TID(ds_tid) &&
2292 (ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait) ||
2293 ompt_callbacks.ompt_callback(ompt_callback_sync_region)))
2294 codeptr = team->t.ompt_team_info.master_return_address;
2295 my_task_data = OMPT_CUR_TASK_DATA(this_thr);
2296 my_parallel_data = OMPT_CUR_TEAM_DATA(this_thr);
2297 ompt_sync_region_t sync_kind = ompt_sync_region_barrier_implicit_parallel;
2298 if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league)
2299 sync_kind = ompt_sync_region_barrier_teams;
2300 if (ompt_enabled.ompt_callback_sync_region) {
2301 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2302 sync_kind, ompt_scope_begin, my_parallel_data, my_task_data, codeptr);
2303 }
2304 if (ompt_enabled.ompt_callback_sync_region_wait) {
2305 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2306 sync_kind, ompt_scope_begin, my_parallel_data, my_task_data, codeptr);
2307 }
2308 if (!KMP_MASTER_TID(ds_tid))
2309 this_thr->th.ompt_thread_info.task_data = *OMPT_CUR_TASK_DATA(this_thr);
2310#endif
2311 this_thr->th.ompt_thread_info.state = ompt_state;
2312 }
2313#endif
2314
2315 if (__kmp_tasking_mode == tskm_extra_barrier) {
2316 __kmp_tasking_barrier(team, this_thr, gtid);
2317 KA_TRACE(10, ("__kmp_join_barrier: T#%d(%d:%d) past tasking barrier\n",
2318 gtid, team_id, tid));
2319 }
2320#ifdef KMP_DEBUG
2321 if (__kmp_tasking_mode != tskm_immediate_exec) {
2322 KA_TRACE(20, ("__kmp_join_barrier: T#%d, old team = %d, old task_team = "
2323 "%p, th_task_team = %p\n",
2324 __kmp_gtid_from_thread(this_thr), team_id,
2325 team->t.t_task_team[this_thr->th.th_task_state],
2326 this_thr->th.th_task_team));
2327 KMP_DEBUG_ASSERT_TASKTEAM_INVARIANT(team, this_thr);
2328 }
2329#endif /* KMP_DEBUG */
2330
2331 /* Copy the blocktime info to the thread, where __kmp_wait_template() can
2332 access it when the team struct is not guaranteed to exist. Doing these
2333 loads causes a cache miss slows down EPCC parallel by 2x. As a workaround,
2334 we do not perform the copy if blocktime=infinite, since the values are not
2335 used by __kmp_wait_template() in that case. */
2336 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
2337#if KMP_USE_MONITOR
2338 this_thr->th.th_team_bt_intervals =
2339 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
2340 this_thr->th.th_team_bt_set =
2341 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
2342#else
2343 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
2344#endif
2345 }
2346
2347#if USE_ITT_BUILD
2348 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2349 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
2350#endif /* USE_ITT_BUILD */
2351
2352 switch (__kmp_barrier_gather_pattern[bs_forkjoin_barrier]) {
2353 case bp_dist_bar: {
2354 __kmp_dist_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2355 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2356 break;
2357 }
2358 case bp_hyper_bar: {
2359 __kmp_hyper_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2360 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2361 break;
2362 }
2363 case bp_hierarchical_bar: {
2364 __kmp_hierarchical_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2365 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2366 break;
2367 }
2368 case bp_tree_bar: {
2369 __kmp_tree_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2370 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2371 break;
2372 }
2373 default: {
2374 __kmp_linear_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2375 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2376 }
2377 }
2378
2379 /* From this point on, the team data structure may be deallocated at any time
2380 by the primary thread - it is unsafe to reference it in any of the worker
2381 threads. Any per-team data items that need to be referenced before the
2382 end of the barrier should be moved to the kmp_task_team_t structs. */
2383 if (KMP_MASTER_TID(tid)) {
2384 if (__kmp_tasking_mode != tskm_immediate_exec) {
2385 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
2386 }
2387 if (__kmp_display_affinity) {
2388 KMP_CHECK_UPDATE(team->t.t_display_affinity, 0);
2389 }
2390#if KMP_STATS_ENABLED
2391 // Have primary thread flag the workers to indicate they are now waiting for
2392 // next parallel region, Also wake them up so they switch their timers to
2393 // idle.
2394 for (int i = 0; i < team->t.t_nproc; ++i) {
2395 kmp_info_t *team_thread = team->t.t_threads[i];
2396 if (team_thread == this_thr)
2397 continue;
2398 team_thread->th.th_stats->setIdleFlag();
2399 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME &&
2400 team_thread->th.th_sleep_loc != NULL)
2401 __kmp_null_resume_wrapper(team_thread);
2402 }
2403#endif
2404#if USE_ITT_BUILD
2405 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2406 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2407#endif /* USE_ITT_BUILD */
2408
2409#if USE_ITT_BUILD && USE_ITT_NOTIFY
2410 // Join barrier - report frame end
2411 if ((__itt_frame_submit_v3_ptr || KMP_ITT_DEBUG) &&
2412 __kmp_forkjoin_frames_mode &&
2413 (this_thr->th.th_teams_microtask == NULL || // either not in teams
2414 this_thr->th.th_teams_size.nteams == 1) && // or inside single team
2415 team->t.t_active_level == 1) {
2416 kmp_uint64 cur_time = __itt_get_timestamp();
2417 ident_t *loc = team->t.t_ident;
2418 kmp_info_t **other_threads = team->t.t_threads;
2419 switch (__kmp_forkjoin_frames_mode) {
2420 case 1:
2421 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2422 loc, nproc);
2423 break;
2424 case 2:
2425 __kmp_itt_frame_submit(gtid, this_thr->th.th_bar_min_time, cur_time, 1,
2426 loc, nproc);
2427 break;
2428 case 3:
2429 if (__itt_metadata_add_ptr) {
2430 // Initialize with primary thread's wait time
2431 kmp_uint64 delta = cur_time - this_thr->th.th_bar_arrive_time;
2432 // Set arrive time to zero to be able to check it in
2433 // __kmp_invoke_task(); the same is done inside the loop below
2434 this_thr->th.th_bar_arrive_time = 0;
2435 for (int i = 1; i < nproc; ++i) {
2436 delta += (cur_time - other_threads[i]->th.th_bar_arrive_time);
2437 other_threads[i]->th.th_bar_arrive_time = 0;
2438 }
2439 __kmp_itt_metadata_imbalance(gtid, this_thr->th.th_frame_time,
2440 cur_time, delta, 0);
2441 }
2442 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2443 loc, nproc);
2444 this_thr->th.th_frame_time = cur_time;
2445 break;
2446 }
2447 }
2448#endif /* USE_ITT_BUILD */
2449 }
2450#if USE_ITT_BUILD
2451 else {
2452 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2453 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2454 }
2455#endif /* USE_ITT_BUILD */
2456
2457#if KMP_DEBUG
2458 if (KMP_MASTER_TID(tid)) {
2459 KA_TRACE(
2460 15,
2461 ("__kmp_join_barrier: T#%d(%d:%d) says all %d team threads arrived\n",
2462 gtid, team_id, tid, nproc));
2463 }
2464#endif /* KMP_DEBUG */
2465
2466 // TODO now, mark worker threads as done so they may be disbanded
2467 KMP_MB(); // Flush all pending memory write invalidates.
2468 KA_TRACE(10,
2469 ("__kmp_join_barrier: T#%d(%d:%d) leaving\n", gtid, team_id, tid));
2470
2471}
2472
2473// TODO release worker threads' fork barriers as we are ready instead of all at
2474// once
2475void __kmp_fork_barrier(int gtid, int tid) {
2476 KMP_TIME_PARTITIONED_BLOCK(OMP_fork_barrier);
2477 KMP_SET_THREAD_STATE_BLOCK(FORK_JOIN_BARRIER);
2478 kmp_info_t *this_thr = __kmp_threads[gtid];
2479 kmp_team_t *team = (tid == 0) ? this_thr->th.th_team : NULL;
2480#if USE_ITT_BUILD
2481 void *itt_sync_obj = NULL;
2482#endif /* USE_ITT_BUILD */
2483#ifdef KMP_DEBUG
2484 if (team)
2485 KA_TRACE(10, ("__kmp_fork_barrier: T#%d(%d:%d) has arrived\n", gtid,
2486 (team != NULL) ? team->t.t_id : -1, tid));
2487#endif
2488 // th_team pointer only valid for primary thread here
2489 if (KMP_MASTER_TID(tid)) {
2490#if USE_ITT_BUILD && USE_ITT_NOTIFY
2491 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2492 // Create itt barrier object
2493 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier, 1);
2494 __kmp_itt_barrier_middle(gtid, itt_sync_obj); // Call acquired/releasing
2495 }
2496#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2497
2498#ifdef KMP_DEBUG
2499 KMP_DEBUG_ASSERT(team);
2500 kmp_info_t **other_threads = team->t.t_threads;
2501 int i;
2502
2503 // Verify state
2504 KMP_MB();
2505
2506 for (i = 1; i < team->t.t_nproc; ++i) {
2507 KA_TRACE(500,
2508 ("__kmp_fork_barrier: T#%d(%d:0) checking T#%d(%d:%d) fork go "
2509 "== %u.\n",
2510 gtid, team->t.t_id, other_threads[i]->th.th_info.ds.ds_gtid,
2511 team->t.t_id, other_threads[i]->th.th_info.ds.ds_tid,
2512 other_threads[i]->th.th_bar[bs_forkjoin_barrier].bb.b_go));
2513 KMP_DEBUG_ASSERT(
2514 (TCR_4(other_threads[i]->th.th_bar[bs_forkjoin_barrier].bb.b_go) &
2515 ~(KMP_BARRIER_SLEEP_STATE)) == KMP_INIT_BARRIER_STATE);
2516 KMP_DEBUG_ASSERT(other_threads[i]->th.th_team == team);
2517 }
2518#endif
2519
2520 if (__kmp_tasking_mode != tskm_immediate_exec)
2521 __kmp_task_team_setup(this_thr, team);
2522
2523 /* The primary thread may have changed its blocktime between join barrier
2524 and fork barrier. Copy the blocktime info to the thread, where
2525 __kmp_wait_template() can access it when the team struct is not
2526 guaranteed to exist. */
2527 // See note about the corresponding code in __kmp_join_barrier() being
2528 // performance-critical
2529 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
2530#if KMP_USE_MONITOR
2531 this_thr->th.th_team_bt_intervals =
2532 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
2533 this_thr->th.th_team_bt_set =
2534 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
2535#else
2536 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
2537#endif
2538 }
2539 } // primary thread
2540
2541 switch (__kmp_barrier_release_pattern[bs_forkjoin_barrier]) {
2542 case bp_dist_bar: {
2543 __kmp_dist_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2544 TRUE USE_ITT_BUILD_ARG(NULL));
2545 break;
2546 }
2547 case bp_hyper_bar: {
2548 KMP_ASSERT(__kmp_barrier_release_branch_bits[bs_forkjoin_barrier]);
2549 __kmp_hyper_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2550 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2551 break;
2552 }
2553 case bp_hierarchical_bar: {
2554 __kmp_hierarchical_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2555 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2556 break;
2557 }
2558 case bp_tree_bar: {
2559 KMP_ASSERT(__kmp_barrier_release_branch_bits[bs_forkjoin_barrier]);
2560 __kmp_tree_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2561 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2562 break;
2563 }
2564 default: {
2565 __kmp_linear_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2566 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2567 }
2568 }
2569
2570#if OMPT_SUPPORT
2571 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
2572 if (ompt_enabled.enabled &&
2573 (ompt_state == ompt_state_wait_barrier_teams ||
2574 ompt_state == ompt_state_wait_barrier_implicit_parallel)) {
2575 int ds_tid = this_thr->th.th_info.ds.ds_tid;
2576 ompt_data_t *task_data = (team)
2577 ? OMPT_CUR_TASK_DATA(this_thr)
2578 : &(this_thr->th.ompt_thread_info.task_data);
2579 this_thr->th.ompt_thread_info.state = ompt_state_overhead;
2580#if OMPT_OPTIONAL
2581 void *codeptr = NULL;
2582 if (KMP_MASTER_TID(ds_tid) &&
2583 (ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait) ||
2584 ompt_callbacks.ompt_callback(ompt_callback_sync_region)))
2585 codeptr = team ? team->t.ompt_team_info.master_return_address : NULL;
2586 ompt_sync_region_t sync_kind = ompt_sync_region_barrier_implicit_parallel;
2587 if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league)
2588 sync_kind = ompt_sync_region_barrier_teams;
2589 if (ompt_enabled.ompt_callback_sync_region_wait) {
2590 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2591 sync_kind, ompt_scope_end, NULL, task_data, codeptr);
2592 }
2593 if (ompt_enabled.ompt_callback_sync_region) {
2594 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2595 sync_kind, ompt_scope_end, NULL, task_data, codeptr);
2596 }
2597#endif
2598 if (!KMP_MASTER_TID(ds_tid) && ompt_enabled.ompt_callback_implicit_task) {
2599 ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
2600 ompt_scope_end, NULL, task_data, 0, ds_tid,
2601 ompt_task_implicit); // TODO: Can this be ompt_task_initial?
2602 }
2603 }
2604#endif
2605
2606 // Early exit for reaping threads releasing forkjoin barrier
2607 if (TCR_4(__kmp_global.g.g_done)) {
2608 this_thr->th.th_task_team = NULL;
2609
2610#if USE_ITT_BUILD && USE_ITT_NOTIFY
2611 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2612 if (!KMP_MASTER_TID(tid)) {
2613 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2614 if (itt_sync_obj)
2615 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2616 }
2617 }
2618#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2619 KA_TRACE(10, ("__kmp_fork_barrier: T#%d is leaving early\n", gtid));
2620 return;
2621 }
2622
2623 /* We can now assume that a valid team structure has been allocated by the
2624 primary thread and propagated to all worker threads. The current thread,
2625 however, may not be part of the team, so we can't blindly assume that the
2626 team pointer is non-null. */
2627 team = (kmp_team_t *)TCR_PTR(this_thr->th.th_team);
2628 KMP_DEBUG_ASSERT(team != NULL);
2629 tid = __kmp_tid_from_gtid(gtid);
2630
2631#if KMP_BARRIER_ICV_PULL
2632 /* Primary thread's copy of the ICVs was set up on the implicit taskdata in
2633 __kmp_reinitialize_team. __kmp_fork_call() assumes the primary thread's
2634 implicit task has this data before this function is called. We cannot
2635 modify __kmp_fork_call() to look at the fixed ICVs in the primary thread's
2636 thread struct, because it is not always the case that the threads arrays
2637 have been allocated when __kmp_fork_call() is executed. */
2638 {
2639 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_icv_copy);
2640 if (!KMP_MASTER_TID(tid)) { // primary thread already has ICVs
2641 // Copy the initial ICVs from the primary thread's thread struct to the
2642 // implicit task for this tid.
2643 KA_TRACE(10,
2644 ("__kmp_fork_barrier: T#%d(%d) is PULLing ICVs\n", gtid, tid));
2645 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[tid], team,
2646 tid, FALSE);
2647 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
2648 &team->t.t_threads[0]
2649 ->th.th_bar[bs_forkjoin_barrier]
2650 .bb.th_fixed_icvs);
2651 }
2652 }
2653#endif // KMP_BARRIER_ICV_PULL
2654
2655 if (__kmp_tasking_mode != tskm_immediate_exec) {
2656 __kmp_task_team_sync(this_thr, team);
2657 }
2658
2659#if KMP_AFFINITY_SUPPORTED
2660 kmp_proc_bind_t proc_bind = team->t.t_proc_bind;
2661 if (proc_bind == proc_bind_intel) {
2662 // Call dynamic affinity settings
2663 if (__kmp_affinity.type == affinity_balanced && team->t.t_size_changed) {
2664 __kmp_balanced_affinity(this_thr, team->t.t_nproc);
2665 }
2666 } else if (proc_bind != proc_bind_false) {
2667 if (this_thr->th.th_new_place == this_thr->th.th_current_place) {
2668 KA_TRACE(100, ("__kmp_fork_barrier: T#%d already in correct place %d\n",
2669 __kmp_gtid_from_thread(this_thr),
2670 this_thr->th.th_current_place));
2671 } else {
2672 __kmp_affinity_bind_place(gtid);
2673 }
2674 }
2675#endif // KMP_AFFINITY_SUPPORTED
2676 // Perform the display affinity functionality
2677 if (__kmp_display_affinity) {
2678 if (team->t.t_display_affinity
2679#if KMP_AFFINITY_SUPPORTED
2680 || (__kmp_affinity.type == affinity_balanced && team->t.t_size_changed)
2681#endif
2682 ) {
2683 // NULL means use the affinity-format-var ICV
2684 __kmp_aux_display_affinity(gtid, NULL);
2685 this_thr->th.th_prev_num_threads = team->t.t_nproc;
2686 this_thr->th.th_prev_level = team->t.t_level;
2687 }
2688 }
2689 if (!KMP_MASTER_TID(tid))
2690 KMP_CHECK_UPDATE(this_thr->th.th_def_allocator, team->t.t_def_allocator);
2691
2692#if USE_ITT_BUILD && USE_ITT_NOTIFY
2693 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2694 if (!KMP_MASTER_TID(tid)) {
2695 // Get correct barrier object
2696 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2697 __kmp_itt_barrier_finished(gtid, itt_sync_obj); // Workers call acquired
2698 } // (prepare called inside barrier_release)
2699 }
2700#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2701 KA_TRACE(10, ("__kmp_fork_barrier: T#%d(%d:%d) is leaving\n", gtid,
2702 team->t.t_id, tid));
2703}
2704
2705void __kmp_setup_icv_copy(kmp_team_t *team, int new_nproc,
2706 kmp_internal_control_t *new_icvs, ident_t *loc) {
2707 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_setup_icv_copy);
2708
2709 KMP_DEBUG_ASSERT(team && new_nproc && new_icvs);
2710 KMP_DEBUG_ASSERT((!TCR_4(__kmp_init_parallel)) || new_icvs->nproc);
2711
2712/* Primary thread's copy of the ICVs was set up on the implicit taskdata in
2713 __kmp_reinitialize_team. __kmp_fork_call() assumes the primary thread's
2714 implicit task has this data before this function is called. */
2715#if KMP_BARRIER_ICV_PULL
2716 /* Copy ICVs to primary thread's thread structure into th_fixed_icvs (which
2717 remains untouched), where all of the worker threads can access them and
2718 make their own copies after the barrier. */
2719 KMP_DEBUG_ASSERT(team->t.t_threads[0]); // The threads arrays should be
2720 // allocated at this point
2721 copy_icvs(
2722 &team->t.t_threads[0]->th.th_bar[bs_forkjoin_barrier].bb.th_fixed_icvs,
2723 new_icvs);
2724 KF_TRACE(10, ("__kmp_setup_icv_copy: PULL: T#%d this_thread=%p team=%p\n", 0,
2725 team->t.t_threads[0], team));
2726#elif KMP_BARRIER_ICV_PUSH
2727 // The ICVs will be propagated in the fork barrier, so nothing needs to be
2728 // done here.
2729 KF_TRACE(10, ("__kmp_setup_icv_copy: PUSH: T#%d this_thread=%p team=%p\n", 0,
2730 team->t.t_threads[0], team));
2731#else
2732 // Copy the ICVs to each of the non-primary threads. This takes O(nthreads)
2733 // time.
2734 ngo_load(new_icvs);
2735 KMP_DEBUG_ASSERT(team->t.t_threads[0]); // The threads arrays should be
2736 // allocated at this point
2737 for (int f = 1; f < new_nproc; ++f) { // Skip the primary thread
2738 // TODO: GEH - pass in better source location info since usually NULL here
2739 KF_TRACE(10, ("__kmp_setup_icv_copy: LINEAR: T#%d this_thread=%p team=%p\n",
2740 f, team->t.t_threads[f], team));
2741 __kmp_init_implicit_task(loc, team->t.t_threads[f], team, f, FALSE);
2742 ngo_store_icvs(&team->t.t_implicit_task_taskdata[f].td_icvs, new_icvs);
2743 KF_TRACE(10, ("__kmp_setup_icv_copy: LINEAR: T#%d this_thread=%p team=%p\n",
2744 f, team->t.t_threads[f], team));
2745 }
2746 ngo_sync();
2747#endif // KMP_BARRIER_ICV_PULL
2748}
Definition: kmp.h:217