LLVM OpenMP* Runtime Library
Loading...
Searching...
No Matches
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 // Checks to determine if (re-)initialization is needed
1334 bool uninitialized = thr_bar->team == NULL;
1335 bool team_changed = team != thr_bar->team;
1336 bool team_sz_changed = nproc != thr_bar->nproc;
1337 bool tid_changed = tid != thr_bar->old_tid;
1338 bool retval = false;
1339
1340 if (uninitialized || team_sz_changed) {
1341 __kmp_get_hierarchy(nproc, thr_bar);
1342 }
1343
1344 if (uninitialized || team_sz_changed || tid_changed) {
1345 thr_bar->my_level = thr_bar->depth - 1; // default for primary thread
1346 thr_bar->parent_tid = -1; // default for primary thread
1347 if (!KMP_MASTER_TID(tid)) {
1348 // if not primary thread, find parent thread in hierarchy
1349 kmp_uint32 d = 0;
1350 while (d < thr_bar->depth) { // find parent based on level of thread in
1351 // hierarchy, and note level
1352 kmp_uint32 rem;
1353 if (d == thr_bar->depth - 2) { // reached level right below the primary
1354 thr_bar->parent_tid = 0;
1355 thr_bar->my_level = d;
1356 break;
1357 } else if ((rem = tid % thr_bar->skip_per_level[d + 1]) != 0) {
1358 // TODO: can we make the above op faster?
1359 // thread is not a subtree root at next level, so this is max
1360 thr_bar->parent_tid = tid - rem;
1361 thr_bar->my_level = d;
1362 break;
1363 }
1364 ++d;
1365 }
1366 }
1367 __kmp_type_convert(7 - ((tid - thr_bar->parent_tid) /
1368 (thr_bar->skip_per_level[thr_bar->my_level])),
1369 &(thr_bar->offset));
1370 thr_bar->old_tid = tid;
1371 thr_bar->wait_flag = KMP_BARRIER_NOT_WAITING;
1372 thr_bar->team = team;
1373 thr_bar->parent_bar =
1374 &team->t.t_threads[thr_bar->parent_tid]->th.th_bar[bt].bb;
1375 }
1376 if (uninitialized || team_changed || tid_changed) {
1377 thr_bar->team = team;
1378 thr_bar->parent_bar =
1379 &team->t.t_threads[thr_bar->parent_tid]->th.th_bar[bt].bb;
1380 retval = true;
1381 }
1382 if (uninitialized || team_sz_changed || tid_changed) {
1383 thr_bar->nproc = nproc;
1384 thr_bar->leaf_kids = thr_bar->base_leaf_kids;
1385 if (thr_bar->my_level == 0)
1386 thr_bar->leaf_kids = 0;
1387 if (thr_bar->leaf_kids && (kmp_uint32)tid + thr_bar->leaf_kids + 1 > nproc)
1388 __kmp_type_convert(nproc - tid - 1, &(thr_bar->leaf_kids));
1389 thr_bar->leaf_state = 0;
1390 for (int i = 0; i < thr_bar->leaf_kids; ++i)
1391 ((char *)&(thr_bar->leaf_state))[7 - i] = 1;
1392 }
1393 return retval;
1394}
1395
1396static void __kmp_hierarchical_barrier_gather(
1397 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
1398 void (*reduce)(void *, void *) USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
1399 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_hier_gather);
1400 kmp_team_t *team = this_thr->th.th_team;
1401 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
1402 kmp_uint32 nproc = this_thr->th.th_team_nproc;
1403 kmp_info_t **other_threads = team->t.t_threads;
1404 kmp_uint64 new_state = 0;
1405
1406 int level = team->t.t_level;
1407 if (other_threads[0]
1408 ->th.th_teams_microtask) // are we inside the teams construct?
1409 if (this_thr->th.th_teams_size.nteams > 1)
1410 ++level; // level was not increased in teams construct for team_of_masters
1411 if (level == 1)
1412 thr_bar->use_oncore_barrier = 1;
1413 else
1414 thr_bar->use_oncore_barrier = 0; // Do not use oncore barrier when nested
1415
1416 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) enter for "
1417 "barrier type %d\n",
1418 gtid, team->t.t_id, tid, bt));
1419 KMP_DEBUG_ASSERT(this_thr == other_threads[this_thr->th.th_info.ds.ds_tid]);
1420
1421#if USE_ITT_BUILD && USE_ITT_NOTIFY
1422 // Barrier imbalance - save arrive time to the thread
1423 if (__kmp_forkjoin_frames_mode == 3 || __kmp_forkjoin_frames_mode == 2) {
1424 this_thr->th.th_bar_arrive_time = __itt_get_timestamp();
1425 }
1426#endif
1427
1428 (void)__kmp_init_hierarchical_barrier_thread(bt, thr_bar, nproc, gtid, tid,
1429 team);
1430
1431 if (thr_bar->my_level) { // not a leaf (my_level==0 means leaf)
1432 kmp_int32 child_tid;
1433 new_state =
1434 (kmp_uint64)team->t.t_bar[bt].b_arrived + KMP_BARRIER_STATE_BUMP;
1435 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
1436 thr_bar->use_oncore_barrier) {
1437 if (thr_bar->leaf_kids) {
1438 // First, wait for leaf children to check-in on my b_arrived flag
1439 kmp_uint64 leaf_state =
1440 KMP_MASTER_TID(tid)
1441 ? thr_bar->b_arrived | thr_bar->leaf_state
1442 : team->t.t_bar[bt].b_arrived | thr_bar->leaf_state;
1443 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) waiting "
1444 "for leaf kids\n",
1445 gtid, team->t.t_id, tid));
1446 kmp_flag_64<> flag(&thr_bar->b_arrived, leaf_state);
1447 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
1448 if (reduce) {
1449 OMPT_REDUCTION_DECL(this_thr, gtid);
1450 OMPT_REDUCTION_BEGIN;
1451 for (child_tid = tid + 1; child_tid <= tid + thr_bar->leaf_kids;
1452 ++child_tid) {
1453 KA_TRACE(100, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) += "
1454 "T#%d(%d:%d)\n",
1455 gtid, team->t.t_id, tid,
1456 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1457 child_tid));
1458 (*reduce)(this_thr->th.th_local.reduce_data,
1459 other_threads[child_tid]->th.th_local.reduce_data);
1460 }
1461 OMPT_REDUCTION_END;
1462 }
1463 // clear leaf_state bits
1464 KMP_TEST_THEN_AND64(&thr_bar->b_arrived, ~(thr_bar->leaf_state));
1465 }
1466 // Next, wait for higher level children on each child's b_arrived flag
1467 for (kmp_uint32 d = 1; d < thr_bar->my_level;
1468 ++d) { // gather lowest level threads first, but skip 0
1469 kmp_uint32 last = tid + thr_bar->skip_per_level[d + 1],
1470 skip = thr_bar->skip_per_level[d];
1471 if (last > nproc)
1472 last = nproc;
1473 for (child_tid = tid + skip; child_tid < (int)last; child_tid += skip) {
1474 kmp_info_t *child_thr = other_threads[child_tid];
1475 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1476 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) wait "
1477 "T#%d(%d:%d) "
1478 "arrived(%p) == %llu\n",
1479 gtid, team->t.t_id, tid,
1480 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1481 child_tid, &child_bar->b_arrived, new_state));
1482 kmp_flag_64<> flag(&child_bar->b_arrived, new_state);
1483 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
1484 if (reduce) {
1485 KA_TRACE(100, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) += "
1486 "T#%d(%d:%d)\n",
1487 gtid, team->t.t_id, tid,
1488 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1489 child_tid));
1490 (*reduce)(this_thr->th.th_local.reduce_data,
1491 child_thr->th.th_local.reduce_data);
1492 }
1493 }
1494 }
1495 } else { // Blocktime is not infinite
1496 for (kmp_uint32 d = 0; d < thr_bar->my_level;
1497 ++d) { // Gather lowest level threads first
1498 kmp_uint32 last = tid + thr_bar->skip_per_level[d + 1],
1499 skip = thr_bar->skip_per_level[d];
1500 if (last > nproc)
1501 last = nproc;
1502 for (child_tid = tid + skip; child_tid < (int)last; child_tid += skip) {
1503 kmp_info_t *child_thr = other_threads[child_tid];
1504 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1505 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) wait "
1506 "T#%d(%d:%d) "
1507 "arrived(%p) == %llu\n",
1508 gtid, team->t.t_id, tid,
1509 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1510 child_tid, &child_bar->b_arrived, new_state));
1511 kmp_flag_64<> flag(&child_bar->b_arrived, new_state);
1512 flag.wait(this_thr, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
1513 if (reduce) {
1514 KA_TRACE(100, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) += "
1515 "T#%d(%d:%d)\n",
1516 gtid, team->t.t_id, tid,
1517 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1518 child_tid));
1519 (*reduce)(this_thr->th.th_local.reduce_data,
1520 child_thr->th.th_local.reduce_data);
1521 }
1522 }
1523 }
1524 }
1525 }
1526 // All subordinates are gathered; now release parent if not primary thread
1527
1528 if (!KMP_MASTER_TID(tid)) { // worker threads release parent in hierarchy
1529 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) releasing"
1530 " T#%d(%d:%d) arrived(%p): %llu => %llu\n",
1531 gtid, team->t.t_id, tid,
1532 __kmp_gtid_from_tid(thr_bar->parent_tid, team), team->t.t_id,
1533 thr_bar->parent_tid, &thr_bar->b_arrived, thr_bar->b_arrived,
1534 thr_bar->b_arrived + KMP_BARRIER_STATE_BUMP));
1535 /* Mark arrival to parent: After performing this write, a worker thread may
1536 not assume that the team is valid any more - it could be deallocated by
1537 the primary thread at any time. */
1538 if (thr_bar->my_level || __kmp_dflt_blocktime != KMP_MAX_BLOCKTIME ||
1539 !thr_bar->use_oncore_barrier) { // Parent is waiting on my b_arrived
1540 // flag; release it
1541 kmp_flag_64<> flag(&thr_bar->b_arrived,
1542 other_threads[thr_bar->parent_tid]);
1543 flag.release();
1544 } else {
1545 // Leaf does special release on "offset" bits of parent's b_arrived flag
1546 thr_bar->b_arrived = team->t.t_bar[bt].b_arrived + KMP_BARRIER_STATE_BUMP;
1547 kmp_flag_oncore flag(&thr_bar->parent_bar->b_arrived,
1548 thr_bar->offset + 1);
1549 flag.set_waiter(other_threads[thr_bar->parent_tid]);
1550 flag.release();
1551 }
1552 } else { // Primary thread needs to update the team's b_arrived value
1553 team->t.t_bar[bt].b_arrived = new_state;
1554 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) set team %d "
1555 "arrived(%p) = %llu\n",
1556 gtid, team->t.t_id, tid, team->t.t_id,
1557 &team->t.t_bar[bt].b_arrived, team->t.t_bar[bt].b_arrived));
1558 }
1559 // Is the team access below unsafe or just technically invalid?
1560 KA_TRACE(20, ("__kmp_hierarchical_barrier_gather: T#%d(%d:%d) exit for "
1561 "barrier type %d\n",
1562 gtid, team->t.t_id, tid, bt));
1563}
1564
1565static void __kmp_hierarchical_barrier_release(
1566 enum barrier_type bt, kmp_info_t *this_thr, int gtid, int tid,
1567 int propagate_icvs USE_ITT_BUILD_ARG(void *itt_sync_obj)) {
1568 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_hier_release);
1569 kmp_team_t *team;
1570 kmp_bstate_t *thr_bar = &this_thr->th.th_bar[bt].bb;
1571 kmp_uint32 nproc;
1572 bool team_change = false; // indicates on-core barrier shouldn't be used
1573
1574 if (KMP_MASTER_TID(tid)) {
1575 team = __kmp_threads[gtid]->th.th_team;
1576 KMP_DEBUG_ASSERT(team != NULL);
1577 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) primary "
1578 "entered barrier type %d\n",
1579 gtid, team->t.t_id, tid, bt));
1580 } else { // Worker threads
1581 // Wait for parent thread to release me
1582 if (!thr_bar->use_oncore_barrier ||
1583 __kmp_dflt_blocktime != KMP_MAX_BLOCKTIME || thr_bar->my_level != 0 ||
1584 thr_bar->team == NULL) {
1585 // Use traditional method of waiting on my own b_go flag
1586 thr_bar->wait_flag = KMP_BARRIER_OWN_FLAG;
1587 kmp_flag_64<> flag(&thr_bar->b_go, KMP_BARRIER_STATE_BUMP);
1588 flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
1589 TCW_8(thr_bar->b_go,
1590 KMP_INIT_BARRIER_STATE); // Reset my b_go flag for next time
1591 } else { // Thread barrier data is initialized, this is a leaf, blocktime is
1592 // infinite, not nested
1593 // Wait on my "offset" bits on parent's b_go flag
1594 thr_bar->wait_flag = KMP_BARRIER_PARENT_FLAG;
1595 kmp_flag_oncore flag(&thr_bar->parent_bar->b_go, KMP_BARRIER_STATE_BUMP,
1596 thr_bar->offset + 1, bt,
1597 this_thr USE_ITT_BUILD_ARG(itt_sync_obj));
1598 flag.wait(this_thr, TRUE);
1599 if (thr_bar->wait_flag ==
1600 KMP_BARRIER_SWITCHING) { // Thread was switched to own b_go
1601 TCW_8(thr_bar->b_go,
1602 KMP_INIT_BARRIER_STATE); // Reset my b_go flag for next time
1603 } else { // Reset my bits on parent's b_go flag
1604 (RCAST(volatile char *,
1605 &(thr_bar->parent_bar->b_go)))[thr_bar->offset + 1] = 0;
1606 }
1607 }
1608 thr_bar->wait_flag = KMP_BARRIER_NOT_WAITING;
1609 // Early exit for reaping threads releasing forkjoin barrier
1610 if (bt == bs_forkjoin_barrier && TCR_4(__kmp_global.g.g_done))
1611 return;
1612 // The worker thread may now assume that the team is valid.
1613 team = __kmp_threads[gtid]->th.th_team;
1614 KMP_DEBUG_ASSERT(team != NULL);
1615 tid = __kmp_tid_from_gtid(gtid);
1616
1617 KA_TRACE(
1618 20,
1619 ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) set go(%p) = %u\n",
1620 gtid, team->t.t_id, tid, &thr_bar->b_go, KMP_INIT_BARRIER_STATE));
1621 KMP_MB(); // Flush all pending memory write invalidates.
1622 }
1623
1624 nproc = this_thr->th.th_team_nproc;
1625 int level = team->t.t_level;
1626 if (team->t.t_threads[0]
1627 ->th.th_teams_microtask) { // are we inside the teams construct?
1628 if (team->t.t_pkfn != (microtask_t)__kmp_teams_master &&
1629 this_thr->th.th_teams_level == level)
1630 ++level; // level was not increased in teams construct for team_of_workers
1631 if (this_thr->th.th_teams_size.nteams > 1)
1632 ++level; // level was not increased in teams construct for team_of_masters
1633 }
1634 if (level == 1)
1635 thr_bar->use_oncore_barrier = 1;
1636 else
1637 thr_bar->use_oncore_barrier = 0; // Do not use oncore barrier when nested
1638
1639 // If the team size has increased, we still communicate with old leaves via
1640 // oncore barrier.
1641 unsigned short int old_leaf_kids = thr_bar->leaf_kids;
1642 kmp_uint64 old_leaf_state = thr_bar->leaf_state;
1643 team_change = __kmp_init_hierarchical_barrier_thread(bt, thr_bar, nproc, gtid,
1644 tid, team);
1645 // But if the entire team changes, we won't use oncore barrier at all
1646 if (team_change)
1647 old_leaf_kids = 0;
1648
1649#if KMP_BARRIER_ICV_PUSH
1650 if (propagate_icvs) {
1651 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[tid], team, tid,
1652 FALSE);
1653 if (KMP_MASTER_TID(
1654 tid)) { // primary already has copy in final destination; copy
1655 copy_icvs(&thr_bar->th_fixed_icvs,
1656 &team->t.t_implicit_task_taskdata[tid].td_icvs);
1657 } else if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
1658 thr_bar->use_oncore_barrier) { // optimization for inf blocktime
1659 if (!thr_bar->my_level) // I'm a leaf in the hierarchy (my_level==0)
1660 // leaves (on-core children) pull parent's fixed ICVs directly to local
1661 // ICV store
1662 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
1663 &thr_bar->parent_bar->th_fixed_icvs);
1664 // non-leaves will get ICVs piggybacked with b_go via NGO store
1665 } else { // blocktime is not infinite; pull ICVs from parent's fixed ICVs
1666 if (thr_bar->my_level) // not a leaf; copy ICVs to my fixed ICVs child can
1667 // access
1668 copy_icvs(&thr_bar->th_fixed_icvs, &thr_bar->parent_bar->th_fixed_icvs);
1669 else // leaves copy parent's fixed ICVs directly to local ICV store
1670 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
1671 &thr_bar->parent_bar->th_fixed_icvs);
1672 }
1673 }
1674#endif // KMP_BARRIER_ICV_PUSH
1675
1676 // Now, release my children
1677 if (thr_bar->my_level) { // not a leaf
1678 kmp_int32 child_tid;
1679 kmp_uint32 last;
1680 if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
1681 thr_bar->use_oncore_barrier) {
1682 if (KMP_MASTER_TID(tid)) { // do a flat release
1683 // Set local b_go to bump children via NGO store of the cache line
1684 // containing IVCs and b_go.
1685 thr_bar->b_go = KMP_BARRIER_STATE_BUMP;
1686 // Use ngo stores if available; b_go piggybacks in the last 8 bytes of
1687 // the cache line
1688 ngo_load(&thr_bar->th_fixed_icvs);
1689 // This loops over all the threads skipping only the leaf nodes in the
1690 // hierarchy
1691 for (child_tid = thr_bar->skip_per_level[1]; child_tid < (int)nproc;
1692 child_tid += thr_bar->skip_per_level[1]) {
1693 kmp_bstate_t *child_bar =
1694 &team->t.t_threads[child_tid]->th.th_bar[bt].bb;
1695 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) "
1696 "releasing T#%d(%d:%d)"
1697 " go(%p): %u => %u\n",
1698 gtid, team->t.t_id, tid,
1699 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1700 child_tid, &child_bar->b_go, child_bar->b_go,
1701 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1702 // Use ngo store (if available) to both store ICVs and release child
1703 // via child's b_go
1704 ngo_store_go(&child_bar->th_fixed_icvs, &thr_bar->th_fixed_icvs);
1705 }
1706 ngo_sync();
1707 }
1708 TCW_8(thr_bar->b_go,
1709 KMP_INIT_BARRIER_STATE); // Reset my b_go flag for next time
1710 // Now, release leaf children
1711 if (thr_bar->leaf_kids) { // if there are any
1712 // We test team_change on the off-chance that the level 1 team changed.
1713 if (team_change ||
1714 old_leaf_kids < thr_bar->leaf_kids) { // some old, some new
1715 if (old_leaf_kids) { // release old leaf kids
1716 thr_bar->b_go |= old_leaf_state;
1717 }
1718 // Release new leaf kids
1719 last = tid + thr_bar->skip_per_level[1];
1720 if (last > nproc)
1721 last = nproc;
1722 for (child_tid = tid + 1 + old_leaf_kids; child_tid < (int)last;
1723 ++child_tid) { // skip_per_level[0]=1
1724 kmp_info_t *child_thr = team->t.t_threads[child_tid];
1725 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1726 KA_TRACE(
1727 20,
1728 ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) releasing"
1729 " T#%d(%d:%d) go(%p): %u => %u\n",
1730 gtid, team->t.t_id, tid, __kmp_gtid_from_tid(child_tid, team),
1731 team->t.t_id, child_tid, &child_bar->b_go, child_bar->b_go,
1732 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1733 // Release child using child's b_go flag
1734 kmp_flag_64<> flag(&child_bar->b_go, child_thr);
1735 flag.release();
1736 }
1737 } else { // Release all children at once with leaf_state bits on my own
1738 // b_go flag
1739 thr_bar->b_go |= thr_bar->leaf_state;
1740 }
1741 }
1742 } else { // Blocktime is not infinite; do a simple hierarchical release
1743 for (int d = thr_bar->my_level - 1; d >= 0;
1744 --d) { // Release highest level threads first
1745 last = tid + thr_bar->skip_per_level[d + 1];
1746 kmp_uint32 skip = thr_bar->skip_per_level[d];
1747 if (last > nproc)
1748 last = nproc;
1749 for (child_tid = tid + skip; child_tid < (int)last; child_tid += skip) {
1750 kmp_info_t *child_thr = team->t.t_threads[child_tid];
1751 kmp_bstate_t *child_bar = &child_thr->th.th_bar[bt].bb;
1752 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) "
1753 "releasing T#%d(%d:%d) go(%p): %u => %u\n",
1754 gtid, team->t.t_id, tid,
1755 __kmp_gtid_from_tid(child_tid, team), team->t.t_id,
1756 child_tid, &child_bar->b_go, child_bar->b_go,
1757 child_bar->b_go + KMP_BARRIER_STATE_BUMP));
1758 // Release child using child's b_go flag
1759 kmp_flag_64<> flag(&child_bar->b_go, child_thr);
1760 flag.release();
1761 }
1762 }
1763 }
1764#if KMP_BARRIER_ICV_PUSH
1765 if (propagate_icvs && !KMP_MASTER_TID(tid))
1766 // non-leaves copy ICVs from fixed ICVs to local dest
1767 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
1768 &thr_bar->th_fixed_icvs);
1769#endif // KMP_BARRIER_ICV_PUSH
1770 }
1771 KA_TRACE(20, ("__kmp_hierarchical_barrier_release: T#%d(%d:%d) exit for "
1772 "barrier type %d\n",
1773 gtid, team->t.t_id, tid, bt));
1774}
1775
1776// End of Barrier Algorithms
1777
1778// type traits for cancellable value
1779// if cancellable is true, then is_cancellable is a normal boolean variable
1780// if cancellable is false, then is_cancellable is a compile time constant
1781template <bool cancellable> struct is_cancellable {};
1782template <> struct is_cancellable<true> {
1783 bool value;
1784 is_cancellable() : value(false) {}
1785 is_cancellable(bool b) : value(b) {}
1786 is_cancellable &operator=(bool b) {
1787 value = b;
1788 return *this;
1789 }
1790 operator bool() const { return value; }
1791};
1792template <> struct is_cancellable<false> {
1793 is_cancellable &operator=(bool b) { return *this; }
1794 constexpr operator bool() const { return false; }
1795};
1796
1797// Internal function to do a barrier.
1798/* If is_split is true, do a split barrier, otherwise, do a plain barrier
1799 If reduce is non-NULL, do a split reduction barrier, otherwise, do a split
1800 barrier
1801 When cancellable = false,
1802 Returns 0 if primary thread, 1 if worker thread.
1803 When cancellable = true
1804 Returns 0 if not cancelled, 1 if cancelled. */
1805template <bool cancellable = false>
1806static int __kmp_barrier_template(enum barrier_type bt, int gtid, int is_split,
1807 size_t reduce_size, void *reduce_data,
1808 void (*reduce)(void *, void *)) {
1809 KMP_TIME_PARTITIONED_BLOCK(OMP_plain_barrier);
1810 KMP_SET_THREAD_STATE_BLOCK(PLAIN_BARRIER);
1811 int tid = __kmp_tid_from_gtid(gtid);
1812 kmp_info_t *this_thr = __kmp_threads[gtid];
1813 kmp_team_t *team = this_thr->th.th_team;
1814 int status = 0;
1815 is_cancellable<cancellable> cancelled;
1816#if OMPT_SUPPORT && OMPT_OPTIONAL
1817 ompt_data_t *my_task_data;
1818 ompt_data_t *my_parallel_data;
1819 void *return_address;
1820 ompt_sync_region_t barrier_kind;
1821#endif
1822
1823 KA_TRACE(15, ("__kmp_barrier: T#%d(%d:%d) has arrived\n", gtid,
1824 __kmp_team_from_gtid(gtid)->t.t_id, __kmp_tid_from_gtid(gtid)));
1825
1826#if OMPT_SUPPORT
1827 if (ompt_enabled.enabled) {
1828#if OMPT_OPTIONAL
1829 my_task_data = OMPT_CUR_TASK_DATA(this_thr);
1830 my_parallel_data = OMPT_CUR_TEAM_DATA(this_thr);
1831 return_address = OMPT_LOAD_RETURN_ADDRESS(gtid);
1832 barrier_kind = __ompt_get_barrier_kind(bt, this_thr);
1833 if (ompt_enabled.ompt_callback_sync_region) {
1834 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
1835 barrier_kind, ompt_scope_begin, my_parallel_data, my_task_data,
1836 return_address);
1837 }
1838 if (ompt_enabled.ompt_callback_sync_region_wait) {
1839 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
1840 barrier_kind, ompt_scope_begin, my_parallel_data, my_task_data,
1841 return_address);
1842 }
1843#endif
1844 // It is OK to report the barrier state after the barrier begin callback.
1845 // According to the OMPT specification, a compliant implementation may
1846 // even delay reporting this state until the barrier begins to wait.
1847 auto *ompt_thr_info = &this_thr->th.ompt_thread_info;
1848 switch (barrier_kind) {
1849 case ompt_sync_region_barrier_explicit:
1850 ompt_thr_info->state = ompt_state_wait_barrier_explicit;
1851 break;
1852 case ompt_sync_region_barrier_implicit_workshare:
1853 ompt_thr_info->state = ompt_state_wait_barrier_implicit_workshare;
1854 break;
1855 case ompt_sync_region_barrier_implicit_parallel:
1856 ompt_thr_info->state = ompt_state_wait_barrier_implicit_parallel;
1857 break;
1858 case ompt_sync_region_barrier_teams:
1859 ompt_thr_info->state = ompt_state_wait_barrier_teams;
1860 break;
1861 case ompt_sync_region_barrier_implementation:
1862 [[fallthrough]];
1863 default:
1864 ompt_thr_info->state = ompt_state_wait_barrier_implementation;
1865 }
1866 }
1867#endif
1868
1869#if ENABLE_LIBOMPTARGET
1870 // Give an opportunity to the offload runtime to make progress and create
1871 // proxy tasks if necessary
1872 if (UNLIKELY(kmp_target_sync_cb != NULL))
1873 (*kmp_target_sync_cb)(
1874 NULL, gtid, KMP_TASKDATA_TO_TASK(this_thr->th.th_current_task), NULL);
1875#endif
1876
1877 if (!team->t.t_serialized) {
1878#if USE_ITT_BUILD
1879 // This value will be used in itt notify events below.
1880 void *itt_sync_obj = NULL;
1881#if USE_ITT_NOTIFY
1882 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
1883 itt_sync_obj = __kmp_itt_barrier_object(gtid, bt, 1);
1884#endif
1885#endif /* USE_ITT_BUILD */
1886 if (__kmp_tasking_mode == tskm_extra_barrier) {
1887 __kmp_tasking_barrier(team, this_thr, gtid);
1888 KA_TRACE(15,
1889 ("__kmp_barrier: T#%d(%d:%d) past tasking barrier\n", gtid,
1890 __kmp_team_from_gtid(gtid)->t.t_id, __kmp_tid_from_gtid(gtid)));
1891 }
1892
1893 /* Copy the blocktime info to the thread, where __kmp_wait_template() can
1894 access it when the team struct is not guaranteed to exist. */
1895 // See note about the corresponding code in __kmp_join_barrier() being
1896 // performance-critical.
1897 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
1898#if KMP_USE_MONITOR
1899 this_thr->th.th_team_bt_intervals =
1900 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
1901 this_thr->th.th_team_bt_set =
1902 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
1903#else
1904 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
1905#endif
1906 }
1907
1908#if USE_ITT_BUILD
1909 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
1910 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
1911#endif /* USE_ITT_BUILD */
1912#if USE_DEBUGGER
1913 // Let the debugger know: the thread arrived to the barrier and waiting.
1914 if (KMP_MASTER_TID(tid)) { // Primary thread counter stored in team struct
1915 team->t.t_bar[bt].b_master_arrived += 1;
1916 } else {
1917 this_thr->th.th_bar[bt].bb.b_worker_arrived += 1;
1918 } // if
1919#endif /* USE_DEBUGGER */
1920 if (reduce != NULL) {
1921 // KMP_DEBUG_ASSERT( is_split == TRUE ); // #C69956
1922 this_thr->th.th_local.reduce_data = reduce_data;
1923 }
1924
1925 if (KMP_MASTER_TID(tid) && __kmp_tasking_mode != tskm_immediate_exec)
1926 __kmp_task_team_setup(this_thr, team);
1927
1928 if (cancellable) {
1929 cancelled = __kmp_linear_barrier_gather_cancellable(
1930 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1931 } else {
1932 switch (__kmp_barrier_gather_pattern[bt]) {
1933 case bp_dist_bar: {
1934 __kmp_dist_barrier_gather(bt, this_thr, gtid, tid,
1935 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1936 break;
1937 }
1938 case bp_hyper_bar: {
1939 __kmp_hyper_barrier_gather(bt, this_thr, gtid, tid,
1940 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1941 break;
1942 }
1943 case bp_hierarchical_bar: {
1944 __kmp_hierarchical_barrier_gather(
1945 bt, this_thr, gtid, tid, reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1946 break;
1947 }
1948 case bp_tree_bar: {
1949 __kmp_tree_barrier_gather(bt, this_thr, gtid, tid,
1950 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1951 break;
1952 }
1953 default: {
1954 __kmp_linear_barrier_gather(bt, this_thr, gtid, tid,
1955 reduce USE_ITT_BUILD_ARG(itt_sync_obj));
1956 }
1957 }
1958 }
1959
1960 KMP_MB();
1961
1962 if (KMP_MASTER_TID(tid)) {
1963 status = 0;
1964 if (__kmp_tasking_mode != tskm_immediate_exec && !cancelled) {
1965 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
1966 }
1967#if USE_DEBUGGER
1968 // Let the debugger know: All threads are arrived and starting leaving the
1969 // barrier.
1970 team->t.t_bar[bt].b_team_arrived += 1;
1971#endif
1972
1973 if (__kmp_omp_cancellation) {
1974 kmp_int32 cancel_request = KMP_ATOMIC_LD_RLX(&team->t.t_cancel_request);
1975 // Reset cancellation flag for worksharing constructs
1976 if (cancel_request == cancel_loop ||
1977 cancel_request == cancel_sections) {
1978 KMP_ATOMIC_ST_RLX(&team->t.t_cancel_request, cancel_noreq);
1979 }
1980 }
1981#if USE_ITT_BUILD
1982 /* TODO: In case of split reduction barrier, primary thread may send
1983 acquired event early, before the final summation into the shared
1984 variable is done (final summation can be a long operation for array
1985 reductions). */
1986 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
1987 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
1988#endif /* USE_ITT_BUILD */
1989#if USE_ITT_BUILD && USE_ITT_NOTIFY
1990 // Barrier - report frame end (only if active_level == 1)
1991 if ((__itt_frame_submit_v3_ptr || KMP_ITT_DEBUG) &&
1992 __kmp_forkjoin_frames_mode &&
1993 (this_thr->th.th_teams_microtask == NULL || // either not in teams
1994 this_thr->th.th_teams_size.nteams == 1) && // or inside single team
1995 team->t.t_active_level == 1) {
1996 ident_t *loc = __kmp_threads[gtid]->th.th_ident;
1997 kmp_uint64 cur_time = __itt_get_timestamp();
1998 kmp_info_t **other_threads = team->t.t_threads;
1999 int nproc = this_thr->th.th_team_nproc;
2000 int i;
2001 switch (__kmp_forkjoin_frames_mode) {
2002 case 1:
2003 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2004 loc, nproc);
2005 this_thr->th.th_frame_time = cur_time;
2006 break;
2007 case 2: // AC 2015-01-19: currently does not work for hierarchical (to
2008 // be fixed)
2009 __kmp_itt_frame_submit(gtid, this_thr->th.th_bar_min_time, cur_time,
2010 1, loc, nproc);
2011 break;
2012 case 3:
2013 if (__itt_metadata_add_ptr) {
2014 // Initialize with primary thread's wait time
2015 kmp_uint64 delta = cur_time - this_thr->th.th_bar_arrive_time;
2016 // Set arrive time to zero to be able to check it in
2017 // __kmp_invoke_task(); the same is done inside the loop below
2018 this_thr->th.th_bar_arrive_time = 0;
2019 for (i = 1; i < nproc; ++i) {
2020 delta += (cur_time - other_threads[i]->th.th_bar_arrive_time);
2021 other_threads[i]->th.th_bar_arrive_time = 0;
2022 }
2023 __kmp_itt_metadata_imbalance(gtid, this_thr->th.th_frame_time,
2024 cur_time, delta,
2025 (kmp_uint64)(reduce != NULL));
2026 }
2027 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2028 loc, nproc);
2029 this_thr->th.th_frame_time = cur_time;
2030 break;
2031 }
2032 }
2033#endif /* USE_ITT_BUILD */
2034 } else {
2035 status = 1;
2036#if USE_ITT_BUILD
2037 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2038 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2039#endif /* USE_ITT_BUILD */
2040 }
2041 if ((status == 1 || !is_split) && !cancelled) {
2042 if (cancellable) {
2043 cancelled = __kmp_linear_barrier_release_cancellable(
2044 bt, this_thr, gtid, tid, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2045 } else {
2046 switch (__kmp_barrier_release_pattern[bt]) {
2047 case bp_dist_bar: {
2048 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2049 __kmp_dist_barrier_release(bt, this_thr, gtid, tid,
2050 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2051 break;
2052 }
2053 case bp_hyper_bar: {
2054 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2055 __kmp_hyper_barrier_release(bt, this_thr, gtid, tid,
2056 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2057 break;
2058 }
2059 case bp_hierarchical_bar: {
2060 __kmp_hierarchical_barrier_release(
2061 bt, this_thr, gtid, tid, FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2062 break;
2063 }
2064 case bp_tree_bar: {
2065 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2066 __kmp_tree_barrier_release(bt, this_thr, gtid, tid,
2067 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2068 break;
2069 }
2070 default: {
2071 __kmp_linear_barrier_release(bt, this_thr, gtid, tid,
2072 FALSE USE_ITT_BUILD_ARG(itt_sync_obj));
2073 }
2074 }
2075 }
2076 if (__kmp_tasking_mode != tskm_immediate_exec && !cancelled) {
2077 __kmp_task_team_sync(this_thr, team);
2078 }
2079 }
2080
2081#if USE_ITT_BUILD
2082 /* GEH: TODO: Move this under if-condition above and also include in
2083 __kmp_end_split_barrier(). This will more accurately represent the actual
2084 release time of the threads for split barriers. */
2085 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2086 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2087#endif /* USE_ITT_BUILD */
2088 } else { // Team is serialized.
2089 status = 0;
2090 if (__kmp_tasking_mode != tskm_immediate_exec) {
2091 if (this_thr->th.th_task_team != NULL) {
2092#if USE_ITT_NOTIFY
2093 void *itt_sync_obj = NULL;
2094 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2095 itt_sync_obj = __kmp_itt_barrier_object(gtid, bt, 1);
2096 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
2097 }
2098#endif
2099
2100 KMP_DEBUG_ASSERT(
2101 this_thr->th.th_task_team->tt.tt_found_proxy_tasks == TRUE ||
2102 this_thr->th.th_task_team->tt.tt_hidden_helper_task_encountered ==
2103 TRUE);
2104 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
2105 __kmp_task_team_setup(this_thr, team);
2106
2107#if USE_ITT_BUILD
2108 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2109 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2110#endif /* USE_ITT_BUILD */
2111 }
2112 }
2113 }
2114 KA_TRACE(15, ("__kmp_barrier: T#%d(%d:%d) is leaving with return value %d\n",
2115 gtid, __kmp_team_from_gtid(gtid)->t.t_id,
2116 __kmp_tid_from_gtid(gtid), status));
2117
2118#if OMPT_SUPPORT
2119 if (ompt_enabled.enabled) {
2120#if OMPT_OPTIONAL
2121 if (ompt_enabled.ompt_callback_sync_region_wait) {
2122 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2123 barrier_kind, ompt_scope_end, my_parallel_data, my_task_data,
2124 return_address);
2125 }
2126 if (ompt_enabled.ompt_callback_sync_region) {
2127 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2128 barrier_kind, ompt_scope_end, my_parallel_data, my_task_data,
2129 return_address);
2130 }
2131#endif
2132 this_thr->th.ompt_thread_info.state = ompt_state_work_parallel;
2133 }
2134#endif
2135
2136 if (cancellable)
2137 return (int)cancelled;
2138 return status;
2139}
2140
2141// Returns 0 if primary thread, 1 if worker thread.
2142int __kmp_barrier(enum barrier_type bt, int gtid, int is_split,
2143 size_t reduce_size, void *reduce_data,
2144 void (*reduce)(void *, void *)) {
2145 return __kmp_barrier_template<>(bt, gtid, is_split, reduce_size, reduce_data,
2146 reduce);
2147}
2148
2149#if defined(KMP_GOMP_COMPAT)
2150// Returns 1 if cancelled, 0 otherwise
2151int __kmp_barrier_gomp_cancel(int gtid) {
2152 if (__kmp_omp_cancellation) {
2153 int cancelled = __kmp_barrier_template<true>(bs_plain_barrier, gtid, FALSE,
2154 0, NULL, NULL);
2155 if (cancelled) {
2156 int tid = __kmp_tid_from_gtid(gtid);
2157 kmp_info_t *this_thr = __kmp_threads[gtid];
2158 if (KMP_MASTER_TID(tid)) {
2159 // Primary thread does not need to revert anything
2160 } else {
2161 // Workers need to revert their private b_arrived flag
2162 this_thr->th.th_bar[bs_plain_barrier].bb.b_arrived -=
2163 KMP_BARRIER_STATE_BUMP;
2164 }
2165 }
2166 return cancelled;
2167 }
2168 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
2169 return FALSE;
2170}
2171#endif
2172
2173void __kmp_end_split_barrier(enum barrier_type bt, int gtid) {
2174 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_end_split_barrier);
2175 KMP_SET_THREAD_STATE_BLOCK(PLAIN_BARRIER);
2176 KMP_DEBUG_ASSERT(bt < bs_last_barrier);
2177 int tid = __kmp_tid_from_gtid(gtid);
2178 kmp_info_t *this_thr = __kmp_threads[gtid];
2179 kmp_team_t *team = this_thr->th.th_team;
2180
2181 if (!team->t.t_serialized) {
2182 if (KMP_MASTER_GTID(gtid)) {
2183 switch (__kmp_barrier_release_pattern[bt]) {
2184 case bp_dist_bar: {
2185 __kmp_dist_barrier_release(bt, this_thr, gtid, tid,
2186 FALSE USE_ITT_BUILD_ARG(NULL));
2187 break;
2188 }
2189 case bp_hyper_bar: {
2190 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2191 __kmp_hyper_barrier_release(bt, this_thr, gtid, tid,
2192 FALSE USE_ITT_BUILD_ARG(NULL));
2193 break;
2194 }
2195 case bp_hierarchical_bar: {
2196 __kmp_hierarchical_barrier_release(bt, this_thr, gtid, tid,
2197 FALSE USE_ITT_BUILD_ARG(NULL));
2198 break;
2199 }
2200 case bp_tree_bar: {
2201 KMP_ASSERT(__kmp_barrier_release_branch_bits[bt]);
2202 __kmp_tree_barrier_release(bt, this_thr, gtid, tid,
2203 FALSE USE_ITT_BUILD_ARG(NULL));
2204 break;
2205 }
2206 default: {
2207 __kmp_linear_barrier_release(bt, this_thr, gtid, tid,
2208 FALSE USE_ITT_BUILD_ARG(NULL));
2209 }
2210 }
2211 if (__kmp_tasking_mode != tskm_immediate_exec) {
2212 __kmp_task_team_sync(this_thr, team);
2213 } // if
2214 }
2215 }
2216}
2217
2218void __kmp_join_barrier(int gtid) {
2219 KMP_TIME_PARTITIONED_BLOCK(OMP_join_barrier);
2220 KMP_SET_THREAD_STATE_BLOCK(FORK_JOIN_BARRIER);
2221
2222 KMP_DEBUG_ASSERT(__kmp_threads && __kmp_threads[gtid]);
2223
2224 kmp_info_t *this_thr = __kmp_threads[gtid];
2225 kmp_team_t *team;
2226 int tid;
2227#ifdef KMP_DEBUG
2228 int team_id;
2229#endif /* KMP_DEBUG */
2230#if USE_ITT_BUILD
2231 void *itt_sync_obj = NULL;
2232#if USE_ITT_NOTIFY
2233 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) // Don't call routine without need
2234 // Get object created at fork_barrier
2235 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2236#endif
2237#endif /* USE_ITT_BUILD */
2238#if ((USE_ITT_BUILD && USE_ITT_NOTIFY) || defined KMP_DEBUG)
2239 int nproc = this_thr->th.th_team_nproc;
2240#endif
2241 KMP_MB();
2242
2243 // Get current info
2244 team = this_thr->th.th_team;
2245 KMP_DEBUG_ASSERT(nproc == team->t.t_nproc);
2246 tid = __kmp_tid_from_gtid(gtid);
2247#ifdef KMP_DEBUG
2248 team_id = team->t.t_id;
2249 kmp_info_t *master_thread = this_thr->th.th_team_master;
2250 if (master_thread != team->t.t_threads[0]) {
2251 __kmp_print_structure();
2252 }
2253#endif /* KMP_DEBUG */
2254 KMP_DEBUG_ASSERT(master_thread == team->t.t_threads[0]);
2255 KMP_MB();
2256
2257 // Verify state
2258 KMP_DEBUG_ASSERT(TCR_PTR(this_thr->th.th_team));
2259 KMP_DEBUG_ASSERT(TCR_PTR(this_thr->th.th_root));
2260 KMP_DEBUG_ASSERT(this_thr == team->t.t_threads[tid]);
2261 KA_TRACE(10, ("__kmp_join_barrier: T#%d(%d:%d) arrived at join barrier\n",
2262 gtid, team_id, tid));
2263
2264#if OMPT_SUPPORT
2265 if (ompt_enabled.enabled) {
2266#if OMPT_OPTIONAL
2267 ompt_data_t *my_task_data;
2268 ompt_data_t *my_parallel_data;
2269 void *codeptr = NULL;
2270 int ds_tid = this_thr->th.th_info.ds.ds_tid;
2271 if (KMP_MASTER_TID(ds_tid) &&
2272 (ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait) ||
2273 ompt_callbacks.ompt_callback(ompt_callback_sync_region)))
2274 codeptr = team->t.ompt_team_info.master_return_address;
2275 my_task_data = OMPT_CUR_TASK_DATA(this_thr);
2276 my_parallel_data = OMPT_CUR_TEAM_DATA(this_thr);
2277 ompt_sync_region_t sync_kind = ompt_sync_region_barrier_implicit_parallel;
2278 ompt_state_t ompt_state = ompt_state_wait_barrier_implicit_parallel;
2279 if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league) {
2280 sync_kind = ompt_sync_region_barrier_teams;
2281 ompt_state = ompt_state_wait_barrier_teams;
2282 }
2283 if (ompt_enabled.ompt_callback_sync_region) {
2284 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2285 sync_kind, ompt_scope_begin, my_parallel_data, my_task_data, codeptr);
2286 }
2287 if (ompt_enabled.ompt_callback_sync_region_wait) {
2288 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2289 sync_kind, ompt_scope_begin, my_parallel_data, my_task_data, codeptr);
2290 }
2291 if (!KMP_MASTER_TID(ds_tid))
2292 this_thr->th.ompt_thread_info.task_data = *OMPT_CUR_TASK_DATA(this_thr);
2293#endif
2294 this_thr->th.ompt_thread_info.state = ompt_state;
2295 }
2296#endif
2297
2298 if (__kmp_tasking_mode == tskm_extra_barrier) {
2299 __kmp_tasking_barrier(team, this_thr, gtid);
2300 KA_TRACE(10, ("__kmp_join_barrier: T#%d(%d:%d) past tasking barrier\n",
2301 gtid, team_id, tid));
2302 }
2303#ifdef KMP_DEBUG
2304 if (__kmp_tasking_mode != tskm_immediate_exec) {
2305 KA_TRACE(20, ("__kmp_join_barrier: T#%d, old team = %d, old task_team = "
2306 "%p, th_task_team = %p\n",
2307 __kmp_gtid_from_thread(this_thr), team_id,
2308 team->t.t_task_team[this_thr->th.th_task_state],
2309 this_thr->th.th_task_team));
2310 KMP_DEBUG_ASSERT_TASKTEAM_INVARIANT(team, this_thr);
2311 }
2312#endif /* KMP_DEBUG */
2313
2314 /* Copy the blocktime info to the thread, where __kmp_wait_template() can
2315 access it when the team struct is not guaranteed to exist. Doing these
2316 loads causes a cache miss slows down EPCC parallel by 2x. As a workaround,
2317 we do not perform the copy if blocktime=infinite, since the values are not
2318 used by __kmp_wait_template() in that case. */
2319 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
2320#if KMP_USE_MONITOR
2321 this_thr->th.th_team_bt_intervals =
2322 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
2323 this_thr->th.th_team_bt_set =
2324 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
2325#else
2326 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
2327#endif
2328 }
2329
2330#if USE_ITT_BUILD
2331 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2332 __kmp_itt_barrier_starting(gtid, itt_sync_obj);
2333#endif /* USE_ITT_BUILD */
2334
2335 switch (__kmp_barrier_gather_pattern[bs_forkjoin_barrier]) {
2336 case bp_dist_bar: {
2337 __kmp_dist_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2338 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2339 break;
2340 }
2341 case bp_hyper_bar: {
2342 __kmp_hyper_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2343 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2344 break;
2345 }
2346 case bp_hierarchical_bar: {
2347 __kmp_hierarchical_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2348 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2349 break;
2350 }
2351 case bp_tree_bar: {
2352 __kmp_tree_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2353 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2354 break;
2355 }
2356 default: {
2357 __kmp_linear_barrier_gather(bs_forkjoin_barrier, this_thr, gtid, tid,
2358 NULL USE_ITT_BUILD_ARG(itt_sync_obj));
2359 }
2360 }
2361
2362 /* From this point on, the team data structure may be deallocated at any time
2363 by the primary thread - it is unsafe to reference it in any of the worker
2364 threads. Any per-team data items that need to be referenced before the
2365 end of the barrier should be moved to the kmp_task_team_t structs. */
2366 if (KMP_MASTER_TID(tid)) {
2367 if (__kmp_tasking_mode != tskm_immediate_exec) {
2368 __kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
2369 }
2370 if (__kmp_display_affinity) {
2371 KMP_CHECK_UPDATE(team->t.t_display_affinity, 0);
2372 }
2373#if KMP_STATS_ENABLED
2374 // Have primary thread flag the workers to indicate they are now waiting for
2375 // next parallel region, Also wake them up so they switch their timers to
2376 // idle.
2377 for (int i = 0; i < team->t.t_nproc; ++i) {
2378 kmp_info_t *team_thread = team->t.t_threads[i];
2379 if (team_thread == this_thr)
2380 continue;
2381 team_thread->th.th_stats->setIdleFlag();
2382 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME &&
2383 team_thread->th.th_sleep_loc != NULL)
2384 __kmp_null_resume_wrapper(team_thread);
2385 }
2386#endif
2387#if USE_ITT_BUILD
2388 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2389 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2390#endif /* USE_ITT_BUILD */
2391
2392#if USE_ITT_BUILD && USE_ITT_NOTIFY
2393 // Join barrier - report frame end
2394 if ((__itt_frame_submit_v3_ptr || KMP_ITT_DEBUG) &&
2395 __kmp_forkjoin_frames_mode &&
2396 (this_thr->th.th_teams_microtask == NULL || // either not in teams
2397 this_thr->th.th_teams_size.nteams == 1) && // or inside single team
2398 team->t.t_active_level == 1) {
2399 kmp_uint64 cur_time = __itt_get_timestamp();
2400 ident_t *loc = team->t.t_ident;
2401 kmp_info_t **other_threads = team->t.t_threads;
2402 switch (__kmp_forkjoin_frames_mode) {
2403 case 1:
2404 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2405 loc, nproc);
2406 break;
2407 case 2:
2408 __kmp_itt_frame_submit(gtid, this_thr->th.th_bar_min_time, cur_time, 1,
2409 loc, nproc);
2410 break;
2411 case 3:
2412 if (__itt_metadata_add_ptr) {
2413 // Initialize with primary thread's wait time
2414 kmp_uint64 delta = cur_time - this_thr->th.th_bar_arrive_time;
2415 // Set arrive time to zero to be able to check it in
2416 // __kmp_invoke_task(); the same is done inside the loop below
2417 this_thr->th.th_bar_arrive_time = 0;
2418 for (int i = 1; i < nproc; ++i) {
2419 delta += (cur_time - other_threads[i]->th.th_bar_arrive_time);
2420 other_threads[i]->th.th_bar_arrive_time = 0;
2421 }
2422 __kmp_itt_metadata_imbalance(gtid, this_thr->th.th_frame_time,
2423 cur_time, delta, 0);
2424 }
2425 __kmp_itt_frame_submit(gtid, this_thr->th.th_frame_time, cur_time, 0,
2426 loc, nproc);
2427 this_thr->th.th_frame_time = cur_time;
2428 break;
2429 }
2430 }
2431#endif /* USE_ITT_BUILD */
2432 }
2433#if USE_ITT_BUILD
2434 else {
2435 if (__itt_sync_create_ptr || KMP_ITT_DEBUG)
2436 __kmp_itt_barrier_middle(gtid, itt_sync_obj);
2437 }
2438#endif /* USE_ITT_BUILD */
2439
2440#if KMP_DEBUG
2441 if (KMP_MASTER_TID(tid)) {
2442 KA_TRACE(
2443 15,
2444 ("__kmp_join_barrier: T#%d(%d:%d) says all %d team threads arrived\n",
2445 gtid, team_id, tid, nproc));
2446 }
2447#endif /* KMP_DEBUG */
2448
2449 // TODO now, mark worker threads as done so they may be disbanded
2450 KMP_MB(); // Flush all pending memory write invalidates.
2451 KA_TRACE(10,
2452 ("__kmp_join_barrier: T#%d(%d:%d) leaving\n", gtid, team_id, tid));
2453
2454}
2455
2456// TODO release worker threads' fork barriers as we are ready instead of all at
2457// once
2458void __kmp_fork_barrier(int gtid, int tid) {
2459 KMP_TIME_PARTITIONED_BLOCK(OMP_fork_barrier);
2460 KMP_SET_THREAD_STATE_BLOCK(FORK_JOIN_BARRIER);
2461 kmp_info_t *this_thr = __kmp_threads[gtid];
2462 kmp_team_t *team = (tid == 0) ? this_thr->th.th_team : NULL;
2463#if USE_ITT_BUILD
2464 void *itt_sync_obj = NULL;
2465#endif /* USE_ITT_BUILD */
2466#ifdef KMP_DEBUG
2467 if (team)
2468 KA_TRACE(10, ("__kmp_fork_barrier: T#%d(%d:%d) has arrived\n", gtid,
2469 (team != NULL) ? team->t.t_id : -1, tid));
2470#endif
2471 // th_team pointer only valid for primary thread here
2472 if (KMP_MASTER_TID(tid)) {
2473#if USE_ITT_BUILD && USE_ITT_NOTIFY
2474 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2475 // Create itt barrier object
2476 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier, 1);
2477 __kmp_itt_barrier_middle(gtid, itt_sync_obj); // Call acquired/releasing
2478 }
2479#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2480
2481#ifdef KMP_DEBUG
2482 KMP_DEBUG_ASSERT(team);
2483 kmp_info_t **other_threads = team->t.t_threads;
2484 int i;
2485
2486 // Verify state
2487 KMP_MB();
2488
2489 for (i = 1; i < team->t.t_nproc; ++i) {
2490 KA_TRACE(500,
2491 ("__kmp_fork_barrier: T#%d(%d:0) checking T#%d(%d:%d) fork go "
2492 "== %u.\n",
2493 gtid, team->t.t_id, other_threads[i]->th.th_info.ds.ds_gtid,
2494 team->t.t_id, other_threads[i]->th.th_info.ds.ds_tid,
2495 other_threads[i]->th.th_bar[bs_forkjoin_barrier].bb.b_go));
2496 KMP_DEBUG_ASSERT(
2497 (TCR_4(other_threads[i]->th.th_bar[bs_forkjoin_barrier].bb.b_go) &
2498 ~(KMP_BARRIER_SLEEP_STATE)) == KMP_INIT_BARRIER_STATE);
2499 KMP_DEBUG_ASSERT(other_threads[i]->th.th_team == team);
2500 }
2501#endif
2502
2503 if (__kmp_tasking_mode != tskm_immediate_exec)
2504 __kmp_task_team_setup(this_thr, team);
2505
2506 /* The primary thread may have changed its blocktime between join barrier
2507 and fork barrier. Copy the blocktime info to the thread, where
2508 __kmp_wait_template() can access it when the team struct is not
2509 guaranteed to exist. */
2510 // See note about the corresponding code in __kmp_join_barrier() being
2511 // performance-critical
2512 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
2513#if KMP_USE_MONITOR
2514 this_thr->th.th_team_bt_intervals =
2515 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_intervals;
2516 this_thr->th.th_team_bt_set =
2517 team->t.t_implicit_task_taskdata[tid].td_icvs.bt_set;
2518#else
2519 this_thr->th.th_team_bt_intervals = KMP_BLOCKTIME_INTERVAL(team, tid);
2520#endif
2521 }
2522 } // primary thread
2523
2524 switch (__kmp_barrier_release_pattern[bs_forkjoin_barrier]) {
2525 case bp_dist_bar: {
2526 __kmp_dist_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2527 TRUE USE_ITT_BUILD_ARG(NULL));
2528 break;
2529 }
2530 case bp_hyper_bar: {
2531 KMP_ASSERT(__kmp_barrier_release_branch_bits[bs_forkjoin_barrier]);
2532 __kmp_hyper_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2533 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2534 break;
2535 }
2536 case bp_hierarchical_bar: {
2537 __kmp_hierarchical_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2538 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2539 break;
2540 }
2541 case bp_tree_bar: {
2542 KMP_ASSERT(__kmp_barrier_release_branch_bits[bs_forkjoin_barrier]);
2543 __kmp_tree_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2544 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2545 break;
2546 }
2547 default: {
2548 __kmp_linear_barrier_release(bs_forkjoin_barrier, this_thr, gtid, tid,
2549 TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
2550 }
2551 }
2552
2553#if OMPT_SUPPORT
2554 ompt_state_t ompt_state = this_thr->th.ompt_thread_info.state;
2555 if (ompt_enabled.enabled &&
2556 (ompt_state == ompt_state_wait_barrier_teams ||
2557 ompt_state == ompt_state_wait_barrier_implicit_parallel)) {
2558 int ds_tid = this_thr->th.th_info.ds.ds_tid;
2559 ompt_data_t *task_data = (team)
2560 ? OMPT_CUR_TASK_DATA(this_thr)
2561 : &(this_thr->th.ompt_thread_info.task_data);
2562 this_thr->th.ompt_thread_info.state = ompt_state_overhead;
2563#if OMPT_OPTIONAL
2564 void *codeptr = NULL;
2565 if (KMP_MASTER_TID(ds_tid) &&
2566 (ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait) ||
2567 ompt_callbacks.ompt_callback(ompt_callback_sync_region)))
2568 codeptr = team ? team->t.ompt_team_info.master_return_address : NULL;
2569 ompt_sync_region_t sync_kind = ompt_sync_region_barrier_implicit_parallel;
2570 if (this_thr->th.ompt_thread_info.parallel_flags & ompt_parallel_league)
2571 sync_kind = ompt_sync_region_barrier_teams;
2572 if (ompt_enabled.ompt_callback_sync_region_wait) {
2573 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2574 sync_kind, ompt_scope_end, NULL, task_data, codeptr);
2575 }
2576 if (ompt_enabled.ompt_callback_sync_region) {
2577 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2578 sync_kind, ompt_scope_end, NULL, task_data, codeptr);
2579 }
2580#endif
2581 if (!KMP_MASTER_TID(ds_tid) && ompt_enabled.ompt_callback_implicit_task) {
2582 ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
2583 ompt_scope_end, NULL, task_data, 0, ds_tid,
2584 ompt_task_implicit); // TODO: Can this be ompt_task_initial?
2585 }
2586 }
2587#endif
2588
2589 // Early exit for reaping threads releasing forkjoin barrier
2590 if (TCR_4(__kmp_global.g.g_done)) {
2591 this_thr->th.th_task_team = NULL;
2592
2593#if USE_ITT_BUILD && USE_ITT_NOTIFY
2594 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2595 if (!KMP_MASTER_TID(tid)) {
2596 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2597 if (itt_sync_obj)
2598 __kmp_itt_barrier_finished(gtid, itt_sync_obj);
2599 }
2600 }
2601#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2602 KA_TRACE(10, ("__kmp_fork_barrier: T#%d is leaving early\n", gtid));
2603 return;
2604 }
2605
2606 /* We can now assume that a valid team structure has been allocated by the
2607 primary thread and propagated to all worker threads. The current thread,
2608 however, may not be part of the team, so we can't blindly assume that the
2609 team pointer is non-null. */
2610 team = (kmp_team_t *)TCR_PTR(this_thr->th.th_team);
2611 KMP_DEBUG_ASSERT(team != NULL);
2612 tid = __kmp_tid_from_gtid(gtid);
2613
2614#if KMP_BARRIER_ICV_PULL
2615 /* Primary thread's copy of the ICVs was set up on the implicit taskdata in
2616 __kmp_reinitialize_team. __kmp_fork_call() assumes the primary thread's
2617 implicit task has this data before this function is called. We cannot
2618 modify __kmp_fork_call() to look at the fixed ICVs in the primary thread's
2619 thread struct, because it is not always the case that the threads arrays
2620 have been allocated when __kmp_fork_call() is executed. */
2621 {
2622 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_icv_copy);
2623 if (!KMP_MASTER_TID(tid)) { // primary thread already has ICVs
2624 // Copy the initial ICVs from the primary thread's thread struct to the
2625 // implicit task for this tid.
2626 KA_TRACE(10,
2627 ("__kmp_fork_barrier: T#%d(%d) is PULLing ICVs\n", gtid, tid));
2628 __kmp_init_implicit_task(team->t.t_ident, team->t.t_threads[tid], team,
2629 tid, FALSE);
2630 copy_icvs(&team->t.t_implicit_task_taskdata[tid].td_icvs,
2631 &team->t.t_threads[0]
2632 ->th.th_bar[bs_forkjoin_barrier]
2633 .bb.th_fixed_icvs);
2634 }
2635 }
2636#endif // KMP_BARRIER_ICV_PULL
2637
2638 if (__kmp_tasking_mode != tskm_immediate_exec) {
2639 __kmp_task_team_sync(this_thr, team);
2640 }
2641
2642#if KMP_AFFINITY_SUPPORTED
2643 kmp_proc_bind_t proc_bind = team->t.t_proc_bind;
2644 if (proc_bind == proc_bind_intel) {
2645 // Call dynamic affinity settings
2646 if (__kmp_affinity.type == affinity_balanced && team->t.t_size_changed) {
2647 __kmp_balanced_affinity(this_thr, team->t.t_nproc);
2648 }
2649 } else if (proc_bind != proc_bind_false) {
2650 if (this_thr->th.th_new_place == this_thr->th.th_current_place) {
2651 KA_TRACE(100, ("__kmp_fork_barrier: T#%d already in correct place %d\n",
2652 __kmp_gtid_from_thread(this_thr),
2653 this_thr->th.th_current_place));
2654 } else {
2655 __kmp_affinity_bind_place(gtid);
2656 }
2657 }
2658#endif // KMP_AFFINITY_SUPPORTED
2659 // Perform the display affinity functionality
2660 if (__kmp_display_affinity) {
2661 if (team->t.t_display_affinity
2662#if KMP_AFFINITY_SUPPORTED
2663 || (__kmp_affinity.type == affinity_balanced && team->t.t_size_changed)
2664#endif
2665 ) {
2666 // NULL means use the affinity-format-var ICV
2667 __kmp_aux_display_affinity(gtid, NULL);
2668 this_thr->th.th_prev_num_threads = team->t.t_nproc;
2669 this_thr->th.th_prev_level = team->t.t_level;
2670 }
2671 }
2672 if (!KMP_MASTER_TID(tid))
2673 KMP_CHECK_UPDATE(this_thr->th.th_def_allocator, team->t.t_def_allocator);
2674
2675#if USE_ITT_BUILD && USE_ITT_NOTIFY
2676 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2677 if (!KMP_MASTER_TID(tid)) {
2678 // Get correct barrier object
2679 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
2680 __kmp_itt_barrier_finished(gtid, itt_sync_obj); // Workers call acquired
2681 } // (prepare called inside barrier_release)
2682 }
2683#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
2684 KA_TRACE(10, ("__kmp_fork_barrier: T#%d(%d:%d) is leaving\n", gtid,
2685 team->t.t_id, tid));
2686}
2687
2688void __kmp_setup_icv_copy(kmp_team_t *team, int new_nproc,
2689 kmp_internal_control_t *new_icvs, ident_t *loc) {
2690 KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(KMP_setup_icv_copy);
2691
2692 KMP_DEBUG_ASSERT(team && new_nproc && new_icvs);
2693 KMP_DEBUG_ASSERT((!TCR_4(__kmp_init_parallel)) || new_icvs->nproc);
2694
2695/* Primary thread's copy of the ICVs was set up on the implicit taskdata in
2696 __kmp_reinitialize_team. __kmp_fork_call() assumes the primary thread's
2697 implicit task has this data before this function is called. */
2698#if KMP_BARRIER_ICV_PULL
2699 /* Copy ICVs to primary thread's thread structure into th_fixed_icvs (which
2700 remains untouched), where all of the worker threads can access them and
2701 make their own copies after the barrier. */
2702 KMP_DEBUG_ASSERT(team->t.t_threads[0]); // The threads arrays should be
2703 // allocated at this point
2704 copy_icvs(
2705 &team->t.t_threads[0]->th.th_bar[bs_forkjoin_barrier].bb.th_fixed_icvs,
2706 new_icvs);
2707 KF_TRACE(10, ("__kmp_setup_icv_copy: PULL: T#%d this_thread=%p team=%p\n", 0,
2708 team->t.t_threads[0], team));
2709#elif KMP_BARRIER_ICV_PUSH
2710 // The ICVs will be propagated in the fork barrier, so nothing needs to be
2711 // done here.
2712 KF_TRACE(10, ("__kmp_setup_icv_copy: PUSH: T#%d this_thread=%p team=%p\n", 0,
2713 team->t.t_threads[0], team));
2714#else
2715 // Copy the ICVs to each of the non-primary threads. This takes O(nthreads)
2716 // time.
2717 ngo_load(new_icvs);
2718 KMP_DEBUG_ASSERT(team->t.t_threads[0]); // The threads arrays should be
2719 // allocated at this point
2720 for (int f = 1; f < new_nproc; ++f) { // Skip the primary thread
2721 // TODO: GEH - pass in better source location info since usually NULL here
2722 KF_TRACE(10, ("__kmp_setup_icv_copy: LINEAR: T#%d this_thread=%p team=%p\n",
2723 f, team->t.t_threads[f], team));
2724 __kmp_init_implicit_task(loc, team->t.t_threads[f], team, f, FALSE);
2725 ngo_store_icvs(&team->t.t_implicit_task_taskdata[f].td_icvs, new_icvs);
2726 KF_TRACE(10, ("__kmp_setup_icv_copy: LINEAR: T#%d this_thread=%p team=%p\n",
2727 f, team->t.t_threads[f], team));
2728 }
2729 ngo_sync();
2730#endif // KMP_BARRIER_ICV_PULL
2731}
struct ident ident_t