1 /* 2 * kmp_dispatch_hier.h -- hierarchical scheduling methods and data structures 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 #ifndef KMP_DISPATCH_HIER_H 14 #define KMP_DISPATCH_HIER_H 15 #include "kmp.h" 16 #include "kmp_dispatch.h" 17 18 // Layer type for scheduling hierarchy 19 enum kmp_hier_layer_e { 20 LAYER_THREAD = -1, 21 LAYER_L1, 22 LAYER_L2, 23 LAYER_L3, 24 LAYER_NUMA, 25 LAYER_LOOP, 26 LAYER_LAST 27 }; 28 29 // Convert hierarchy type (LAYER_L1, LAYER_L2, etc.) to C-style string 30 static inline const char *__kmp_get_hier_str(kmp_hier_layer_e type) { 31 switch (type) { 32 case kmp_hier_layer_e::LAYER_THREAD: 33 return "THREAD"; 34 case kmp_hier_layer_e::LAYER_L1: 35 return "L1"; 36 case kmp_hier_layer_e::LAYER_L2: 37 return "L2"; 38 case kmp_hier_layer_e::LAYER_L3: 39 return "L3"; 40 case kmp_hier_layer_e::LAYER_NUMA: 41 return "NUMA"; 42 case kmp_hier_layer_e::LAYER_LOOP: 43 return "WHOLE_LOOP"; 44 case kmp_hier_layer_e::LAYER_LAST: 45 return "LAST"; 46 } 47 KMP_ASSERT(0); 48 // Appease compilers, should never get here 49 return "ERROR"; 50 } 51 52 // Structure to store values parsed from OMP_SCHEDULE for scheduling hierarchy 53 typedef struct kmp_hier_sched_env_t { 54 int size; 55 int capacity; 56 enum sched_type *scheds; 57 kmp_int32 *small_chunks; 58 kmp_int64 *large_chunks; 59 kmp_hier_layer_e *layers; 60 // Append a level of the hierarchy 61 void append(enum sched_type sched, kmp_int32 chunk, kmp_hier_layer_e layer) { 62 if (capacity == 0) { 63 scheds = (enum sched_type *)__kmp_allocate(sizeof(enum sched_type) * 64 kmp_hier_layer_e::LAYER_LAST); 65 small_chunks = (kmp_int32 *)__kmp_allocate(sizeof(kmp_int32) * 66 kmp_hier_layer_e::LAYER_LAST); 67 large_chunks = (kmp_int64 *)__kmp_allocate(sizeof(kmp_int64) * 68 kmp_hier_layer_e::LAYER_LAST); 69 layers = (kmp_hier_layer_e *)__kmp_allocate(sizeof(kmp_hier_layer_e) * 70 kmp_hier_layer_e::LAYER_LAST); 71 capacity = kmp_hier_layer_e::LAYER_LAST; 72 } 73 int current_size = size; 74 KMP_DEBUG_ASSERT(current_size < kmp_hier_layer_e::LAYER_LAST); 75 scheds[current_size] = sched; 76 layers[current_size] = layer; 77 small_chunks[current_size] = chunk; 78 large_chunks[current_size] = (kmp_int64)chunk; 79 size++; 80 } 81 // Sort the hierarchy using selection sort, size will always be small 82 // (less than LAYER_LAST) so it is not necessary to use an nlog(n) algorithm 83 void sort() { 84 if (size <= 1) 85 return; 86 for (int i = 0; i < size; ++i) { 87 int switch_index = i; 88 for (int j = i + 1; j < size; ++j) { 89 if (layers[j] < layers[switch_index]) 90 switch_index = j; 91 } 92 if (switch_index != i) { 93 kmp_hier_layer_e temp1 = layers[i]; 94 enum sched_type temp2 = scheds[i]; 95 kmp_int32 temp3 = small_chunks[i]; 96 kmp_int64 temp4 = large_chunks[i]; 97 layers[i] = layers[switch_index]; 98 scheds[i] = scheds[switch_index]; 99 small_chunks[i] = small_chunks[switch_index]; 100 large_chunks[i] = large_chunks[switch_index]; 101 layers[switch_index] = temp1; 102 scheds[switch_index] = temp2; 103 small_chunks[switch_index] = temp3; 104 large_chunks[switch_index] = temp4; 105 } 106 } 107 } 108 // Free all memory 109 void deallocate() { 110 if (capacity > 0) { 111 __kmp_free(scheds); 112 __kmp_free(layers); 113 __kmp_free(small_chunks); 114 __kmp_free(large_chunks); 115 scheds = NULL; 116 layers = NULL; 117 small_chunks = NULL; 118 large_chunks = NULL; 119 } 120 size = 0; 121 capacity = 0; 122 } 123 } kmp_hier_sched_env_t; 124 125 extern int __kmp_dispatch_hand_threading; 126 extern kmp_hier_sched_env_t __kmp_hier_scheds; 127 128 // Sizes of layer arrays bounded by max number of detected L1s, L2s, etc. 129 extern int __kmp_hier_max_units[kmp_hier_layer_e::LAYER_LAST + 1]; 130 extern int __kmp_hier_threads_per[kmp_hier_layer_e::LAYER_LAST + 1]; 131 132 extern int __kmp_dispatch_get_index(int tid, kmp_hier_layer_e type); 133 extern int __kmp_dispatch_get_id(int gtid, kmp_hier_layer_e type); 134 extern int __kmp_dispatch_get_t1_per_t2(kmp_hier_layer_e t1, 135 kmp_hier_layer_e t2); 136 extern void __kmp_dispatch_free_hierarchies(kmp_team_t *team); 137 138 template <typename T> struct kmp_hier_shared_bdata_t { 139 typedef typename traits_t<T>::signed_t ST; 140 volatile kmp_uint64 val[2]; 141 kmp_int32 status[2]; 142 T lb[2]; 143 T ub[2]; 144 ST st[2]; 145 dispatch_shared_info_template<T> sh[2]; 146 void zero() { 147 val[0] = val[1] = 0; 148 status[0] = status[1] = 0; 149 lb[0] = lb[1] = 0; 150 ub[0] = ub[1] = 0; 151 st[0] = st[1] = 0; 152 sh[0].u.s.iteration = sh[1].u.s.iteration = 0; 153 } 154 void set_next_hand_thread(T nlb, T nub, ST nst, kmp_int32 nstatus, 155 kmp_uint64 index) { 156 lb[1 - index] = nlb; 157 ub[1 - index] = nub; 158 st[1 - index] = nst; 159 status[1 - index] = nstatus; 160 } 161 void set_next(T nlb, T nub, ST nst, kmp_int32 nstatus, kmp_uint64 index) { 162 lb[1 - index] = nlb; 163 ub[1 - index] = nub; 164 st[1 - index] = nst; 165 status[1 - index] = nstatus; 166 sh[1 - index].u.s.iteration = 0; 167 } 168 169 kmp_int32 get_next_status(kmp_uint64 index) const { 170 return status[1 - index]; 171 } 172 T get_next_lb(kmp_uint64 index) const { return lb[1 - index]; } 173 T get_next_ub(kmp_uint64 index) const { return ub[1 - index]; } 174 ST get_next_st(kmp_uint64 index) const { return st[1 - index]; } 175 dispatch_shared_info_template<T> volatile *get_next_sh(kmp_uint64 index) { 176 return &(sh[1 - index]); 177 } 178 179 kmp_int32 get_curr_status(kmp_uint64 index) const { return status[index]; } 180 T get_curr_lb(kmp_uint64 index) const { return lb[index]; } 181 T get_curr_ub(kmp_uint64 index) const { return ub[index]; } 182 ST get_curr_st(kmp_uint64 index) const { return st[index]; } 183 dispatch_shared_info_template<T> volatile *get_curr_sh(kmp_uint64 index) { 184 return &(sh[index]); 185 } 186 }; 187 188 /* 189 * In the barrier implementations, num_active is the number of threads that are 190 * attached to the kmp_hier_top_unit_t structure in the scheduling hierarchy. 191 * bdata is the shared barrier data that resides on the kmp_hier_top_unit_t 192 * structure. tdata is the thread private data that resides on the thread 193 * data structure. 194 * 195 * The reset_shared() method is used to initialize the barrier data on the 196 * kmp_hier_top_unit_t hierarchy structure 197 * 198 * The reset_private() method is used to initialize the barrier data on the 199 * thread's private dispatch buffer structure 200 * 201 * The barrier() method takes an id, which is that thread's id for the 202 * kmp_hier_top_unit_t structure, and implements the barrier. All threads wait 203 * inside barrier() until all fellow threads who are attached to that 204 * kmp_hier_top_unit_t structure have arrived. 205 */ 206 207 // Core barrier implementation 208 // Can be used in a unit with between 2 to 8 threads 209 template <typename T> class core_barrier_impl { 210 static inline kmp_uint64 get_wait_val(int num_active) { 211 kmp_uint64 wait_val = 0LL; 212 switch (num_active) { 213 case 2: 214 wait_val = 0x0101LL; 215 break; 216 case 3: 217 wait_val = 0x010101LL; 218 break; 219 case 4: 220 wait_val = 0x01010101LL; 221 break; 222 case 5: 223 wait_val = 0x0101010101LL; 224 break; 225 case 6: 226 wait_val = 0x010101010101LL; 227 break; 228 case 7: 229 wait_val = 0x01010101010101LL; 230 break; 231 case 8: 232 wait_val = 0x0101010101010101LL; 233 break; 234 default: 235 // don't use the core_barrier_impl for more than 8 threads 236 KMP_ASSERT(0); 237 } 238 return wait_val; 239 } 240 241 public: 242 static void reset_private(kmp_int32 num_active, 243 kmp_hier_private_bdata_t *tdata); 244 static void reset_shared(kmp_int32 num_active, 245 kmp_hier_shared_bdata_t<T> *bdata); 246 static void barrier(kmp_int32 id, kmp_hier_shared_bdata_t<T> *bdata, 247 kmp_hier_private_bdata_t *tdata); 248 }; 249 250 template <typename T> 251 void core_barrier_impl<T>::reset_private(kmp_int32 num_active, 252 kmp_hier_private_bdata_t *tdata) { 253 tdata->num_active = num_active; 254 tdata->index = 0; 255 tdata->wait_val[0] = tdata->wait_val[1] = get_wait_val(num_active); 256 } 257 template <typename T> 258 void core_barrier_impl<T>::reset_shared(kmp_int32 num_active, 259 kmp_hier_shared_bdata_t<T> *bdata) { 260 bdata->val[0] = bdata->val[1] = 0LL; 261 bdata->status[0] = bdata->status[1] = 0LL; 262 } 263 template <typename T> 264 void core_barrier_impl<T>::barrier(kmp_int32 id, 265 kmp_hier_shared_bdata_t<T> *bdata, 266 kmp_hier_private_bdata_t *tdata) { 267 kmp_uint64 current_index = tdata->index; 268 kmp_uint64 next_index = 1 - current_index; 269 kmp_uint64 current_wait_value = tdata->wait_val[current_index]; 270 kmp_uint64 next_wait_value = 271 (current_wait_value ? 0 : get_wait_val(tdata->num_active)); 272 KD_TRACE(10, ("core_barrier_impl::barrier(): T#%d current_index:%llu " 273 "next_index:%llu curr_wait:%llu next_wait:%llu\n", 274 __kmp_get_gtid(), current_index, next_index, current_wait_value, 275 next_wait_value)); 276 char v = (current_wait_value ? '\1' : '\0'); 277 (RCAST(volatile char *, &(bdata->val[current_index])))[id] = v; 278 __kmp_wait<kmp_uint64>(&(bdata->val[current_index]), current_wait_value, 279 __kmp_eq<kmp_uint64> USE_ITT_BUILD_ARG(NULL)); 280 tdata->wait_val[current_index] = next_wait_value; 281 tdata->index = next_index; 282 } 283 284 // Counter barrier implementation 285 // Can be used in a unit with arbitrary number of active threads 286 template <typename T> class counter_barrier_impl { 287 public: 288 static void reset_private(kmp_int32 num_active, 289 kmp_hier_private_bdata_t *tdata); 290 static void reset_shared(kmp_int32 num_active, 291 kmp_hier_shared_bdata_t<T> *bdata); 292 static void barrier(kmp_int32 id, kmp_hier_shared_bdata_t<T> *bdata, 293 kmp_hier_private_bdata_t *tdata); 294 }; 295 296 template <typename T> 297 void counter_barrier_impl<T>::reset_private(kmp_int32 num_active, 298 kmp_hier_private_bdata_t *tdata) { 299 tdata->num_active = num_active; 300 tdata->index = 0; 301 tdata->wait_val[0] = tdata->wait_val[1] = (kmp_uint64)num_active; 302 } 303 template <typename T> 304 void counter_barrier_impl<T>::reset_shared(kmp_int32 num_active, 305 kmp_hier_shared_bdata_t<T> *bdata) { 306 bdata->val[0] = bdata->val[1] = 0LL; 307 bdata->status[0] = bdata->status[1] = 0LL; 308 } 309 template <typename T> 310 void counter_barrier_impl<T>::barrier(kmp_int32 id, 311 kmp_hier_shared_bdata_t<T> *bdata, 312 kmp_hier_private_bdata_t *tdata) { 313 volatile kmp_int64 *val; 314 kmp_uint64 current_index = tdata->index; 315 kmp_uint64 next_index = 1 - current_index; 316 kmp_uint64 current_wait_value = tdata->wait_val[current_index]; 317 kmp_uint64 next_wait_value = current_wait_value + tdata->num_active; 318 319 KD_TRACE(10, ("counter_barrier_impl::barrier(): T#%d current_index:%llu " 320 "next_index:%llu curr_wait:%llu next_wait:%llu\n", 321 __kmp_get_gtid(), current_index, next_index, current_wait_value, 322 next_wait_value)); 323 val = RCAST(volatile kmp_int64 *, &(bdata->val[current_index])); 324 KMP_TEST_THEN_INC64(val); 325 __kmp_wait<kmp_uint64>(&(bdata->val[current_index]), current_wait_value, 326 __kmp_ge<kmp_uint64> USE_ITT_BUILD_ARG(NULL)); 327 tdata->wait_val[current_index] = next_wait_value; 328 tdata->index = next_index; 329 } 330 331 // Data associated with topology unit within a layer 332 // For example, one kmp_hier_top_unit_t corresponds to one L1 cache 333 template <typename T> struct kmp_hier_top_unit_t { 334 typedef typename traits_t<T>::signed_t ST; 335 typedef typename traits_t<T>::unsigned_t UT; 336 kmp_int32 active; // number of topology units that communicate with this unit 337 // chunk information (lower/upper bound, stride, etc.) 338 dispatch_private_info_template<T> hier_pr; 339 kmp_hier_top_unit_t<T> *hier_parent; // pointer to parent unit 340 kmp_hier_shared_bdata_t<T> hier_barrier; // shared barrier data for this unit 341 342 kmp_int32 get_hier_id() const { return hier_pr.hier_id; } 343 void reset_shared_barrier() { 344 KMP_DEBUG_ASSERT(active > 0); 345 if (active == 1) 346 return; 347 hier_barrier.zero(); 348 if (active >= 2 && active <= 8) { 349 core_barrier_impl<T>::reset_shared(active, &hier_barrier); 350 } else { 351 counter_barrier_impl<T>::reset_shared(active, &hier_barrier); 352 } 353 } 354 void reset_private_barrier(kmp_hier_private_bdata_t *tdata) { 355 KMP_DEBUG_ASSERT(tdata); 356 KMP_DEBUG_ASSERT(active > 0); 357 if (active == 1) 358 return; 359 if (active >= 2 && active <= 8) { 360 core_barrier_impl<T>::reset_private(active, tdata); 361 } else { 362 counter_barrier_impl<T>::reset_private(active, tdata); 363 } 364 } 365 void barrier(kmp_int32 id, kmp_hier_private_bdata_t *tdata) { 366 KMP_DEBUG_ASSERT(tdata); 367 KMP_DEBUG_ASSERT(active > 0); 368 KMP_DEBUG_ASSERT(id >= 0 && id < active); 369 if (active == 1) { 370 tdata->index = 1 - tdata->index; 371 return; 372 } 373 if (active >= 2 && active <= 8) { 374 core_barrier_impl<T>::barrier(id, &hier_barrier, tdata); 375 } else { 376 counter_barrier_impl<T>::barrier(id, &hier_barrier, tdata); 377 } 378 } 379 380 kmp_int32 get_next_status(kmp_uint64 index) const { 381 return hier_barrier.get_next_status(index); 382 } 383 T get_next_lb(kmp_uint64 index) const { 384 return hier_barrier.get_next_lb(index); 385 } 386 T get_next_ub(kmp_uint64 index) const { 387 return hier_barrier.get_next_ub(index); 388 } 389 ST get_next_st(kmp_uint64 index) const { 390 return hier_barrier.get_next_st(index); 391 } 392 dispatch_shared_info_template<T> volatile *get_next_sh(kmp_uint64 index) { 393 return hier_barrier.get_next_sh(index); 394 } 395 396 kmp_int32 get_curr_status(kmp_uint64 index) const { 397 return hier_barrier.get_curr_status(index); 398 } 399 T get_curr_lb(kmp_uint64 index) const { 400 return hier_barrier.get_curr_lb(index); 401 } 402 T get_curr_ub(kmp_uint64 index) const { 403 return hier_barrier.get_curr_ub(index); 404 } 405 ST get_curr_st(kmp_uint64 index) const { 406 return hier_barrier.get_curr_st(index); 407 } 408 dispatch_shared_info_template<T> volatile *get_curr_sh(kmp_uint64 index) { 409 return hier_barrier.get_curr_sh(index); 410 } 411 412 void set_next_hand_thread(T lb, T ub, ST st, kmp_int32 status, 413 kmp_uint64 index) { 414 hier_barrier.set_next_hand_thread(lb, ub, st, status, index); 415 } 416 void set_next(T lb, T ub, ST st, kmp_int32 status, kmp_uint64 index) { 417 hier_barrier.set_next(lb, ub, st, status, index); 418 } 419 dispatch_private_info_template<T> *get_my_pr() { return &hier_pr; } 420 kmp_hier_top_unit_t<T> *get_parent() { return hier_parent; } 421 dispatch_private_info_template<T> *get_parent_pr() { 422 return &(hier_parent->hier_pr); 423 } 424 425 kmp_int32 is_active() const { return active; } 426 kmp_int32 get_num_active() const { return active; } 427 #ifdef KMP_DEBUG 428 void print() { 429 KD_TRACE( 430 10, 431 (" kmp_hier_top_unit_t: active:%d pr:%p lb:%d ub:%d st:%d tc:%d\n", 432 active, &hier_pr, hier_pr.u.p.lb, hier_pr.u.p.ub, hier_pr.u.p.st, 433 hier_pr.u.p.tc)); 434 } 435 #endif 436 }; 437 438 // Information regarding a single layer within the scheduling hierarchy 439 template <typename T> struct kmp_hier_layer_info_t { 440 int num_active; // number of threads active in this level 441 kmp_hier_layer_e type; // LAYER_L1, LAYER_L2, etc. 442 enum sched_type sched; // static, dynamic, guided, etc. 443 typename traits_t<T>::signed_t chunk; // chunk size associated with schedule 444 int length; // length of the kmp_hier_top_unit_t array 445 446 #ifdef KMP_DEBUG 447 // Print this layer's information 448 void print() { 449 const char *t = __kmp_get_hier_str(type); 450 KD_TRACE( 451 10, 452 (" kmp_hier_layer_info_t: num_active:%d type:%s sched:%d chunk:%d " 453 "length:%d\n", 454 num_active, t, sched, chunk, length)); 455 } 456 #endif 457 }; 458 459 /* 460 * Structure to implement entire hierarchy 461 * 462 * The hierarchy is kept as an array of arrays to represent the different 463 * layers. Layer 0 is the lowest layer to layer num_layers - 1 which is the 464 * highest layer. 465 * Example: 466 * [ 2 ] -> [ L3 | L3 ] 467 * [ 1 ] -> [ L2 | L2 | L2 | L2 ] 468 * [ 0 ] -> [ L1 | L1 | L1 | L1 | L1 | L1 | L1 | L1 ] 469 * There is also an array of layer_info_t which has information regarding 470 * each layer 471 */ 472 template <typename T> struct kmp_hier_t { 473 public: 474 typedef typename traits_t<T>::unsigned_t UT; 475 typedef typename traits_t<T>::signed_t ST; 476 477 private: 478 int next_recurse(ident_t *loc, int gtid, kmp_hier_top_unit_t<T> *current, 479 kmp_int32 *p_last, T *p_lb, T *p_ub, ST *p_st, 480 kmp_int32 previous_id, int hier_level) { 481 int status; 482 kmp_info_t *th = __kmp_threads[gtid]; 483 auto parent = current->get_parent(); 484 bool last_layer = (hier_level == get_num_layers() - 1); 485 KMP_DEBUG_ASSERT(th); 486 kmp_hier_private_bdata_t *tdata = &(th->th.th_hier_bar_data[hier_level]); 487 KMP_DEBUG_ASSERT(current); 488 KMP_DEBUG_ASSERT(hier_level >= 0); 489 KMP_DEBUG_ASSERT(hier_level < get_num_layers()); 490 KMP_DEBUG_ASSERT(tdata); 491 KMP_DEBUG_ASSERT(parent || last_layer); 492 493 KD_TRACE( 494 1, ("kmp_hier_t.next_recurse(): T#%d (%d) called\n", gtid, hier_level)); 495 496 T hier_id = (T)current->get_hier_id(); 497 // Attempt to grab next iteration range for this level 498 if (previous_id == 0) { 499 KD_TRACE(1, ("kmp_hier_t.next_recurse(): T#%d (%d) is primary of unit\n", 500 gtid, hier_level)); 501 kmp_int32 contains_last; 502 T my_lb, my_ub; 503 ST my_st; 504 T nproc; 505 dispatch_shared_info_template<T> volatile *my_sh; 506 dispatch_private_info_template<T> *my_pr; 507 if (last_layer) { 508 // last layer below the very top uses the single shared buffer 509 // from the team struct. 510 KD_TRACE(10, 511 ("kmp_hier_t.next_recurse(): T#%d (%d) using top level sh\n", 512 gtid, hier_level)); 513 my_sh = reinterpret_cast<dispatch_shared_info_template<T> volatile *>( 514 th->th.th_dispatch->th_dispatch_sh_current); 515 nproc = (T)get_top_level_nproc(); 516 } else { 517 // middle layers use the shared buffer inside the kmp_hier_top_unit_t 518 // structure 519 KD_TRACE(10, ("kmp_hier_t.next_recurse(): T#%d (%d) using hier sh\n", 520 gtid, hier_level)); 521 my_sh = 522 parent->get_curr_sh(th->th.th_hier_bar_data[hier_level + 1].index); 523 nproc = (T)parent->get_num_active(); 524 } 525 my_pr = current->get_my_pr(); 526 KMP_DEBUG_ASSERT(my_sh); 527 KMP_DEBUG_ASSERT(my_pr); 528 enum sched_type schedule = get_sched(hier_level); 529 ST chunk = (ST)get_chunk(hier_level); 530 status = __kmp_dispatch_next_algorithm<T>(gtid, my_pr, my_sh, 531 &contains_last, &my_lb, &my_ub, 532 &my_st, nproc, hier_id); 533 KD_TRACE( 534 10, 535 ("kmp_hier_t.next_recurse(): T#%d (%d) next_pr_sh() returned %d\n", 536 gtid, hier_level, status)); 537 // When no iterations are found (status == 0) and this is not the last 538 // layer, attempt to go up the hierarchy for more iterations 539 if (status == 0 && !last_layer) { 540 kmp_int32 hid; 541 __kmp_type_convert(hier_id, &hid); 542 status = next_recurse(loc, gtid, parent, &contains_last, &my_lb, &my_ub, 543 &my_st, hid, hier_level + 1); 544 KD_TRACE( 545 10, 546 ("kmp_hier_t.next_recurse(): T#%d (%d) hier_next() returned %d\n", 547 gtid, hier_level, status)); 548 if (status == 1) { 549 kmp_hier_private_bdata_t *upper_tdata = 550 &(th->th.th_hier_bar_data[hier_level + 1]); 551 my_sh = parent->get_curr_sh(upper_tdata->index); 552 KD_TRACE(10, ("kmp_hier_t.next_recurse(): T#%d (%d) about to init\n", 553 gtid, hier_level)); 554 __kmp_dispatch_init_algorithm(loc, gtid, my_pr, schedule, 555 parent->get_curr_lb(upper_tdata->index), 556 parent->get_curr_ub(upper_tdata->index), 557 parent->get_curr_st(upper_tdata->index), 558 #if USE_ITT_BUILD 559 NULL, 560 #endif 561 chunk, nproc, hier_id); 562 status = __kmp_dispatch_next_algorithm<T>( 563 gtid, my_pr, my_sh, &contains_last, &my_lb, &my_ub, &my_st, nproc, 564 hier_id); 565 if (!status) { 566 KD_TRACE(10, ("kmp_hier_t.next_recurse(): T#%d (%d) status not 1 " 567 "setting to 2!\n", 568 gtid, hier_level)); 569 status = 2; 570 } 571 } 572 } 573 current->set_next(my_lb, my_ub, my_st, status, tdata->index); 574 // Propagate whether a unit holds the actual global last iteration 575 // The contains_last attribute is sent downwards from the top to the 576 // bottom of the hierarchy via the contains_last flag inside the 577 // private dispatch buffers in the hierarchy's middle layers 578 if (contains_last) { 579 // If the next_algorithm() method returns 1 for p_last and it is the 580 // last layer or our parent contains the last serial chunk, then the 581 // chunk must contain the last serial iteration. 582 if (last_layer || parent->hier_pr.flags.contains_last) { 583 KD_TRACE(10, ("kmp_hier_t.next_recurse(): T#%d (%d) Setting this pr " 584 "to contain last.\n", 585 gtid, hier_level)); 586 current->hier_pr.flags.contains_last = contains_last; 587 } 588 if (!current->hier_pr.flags.contains_last) 589 contains_last = FALSE; 590 } 591 if (p_last) 592 *p_last = contains_last; 593 } // if primary thread of this unit 594 if (hier_level > 0 || !__kmp_dispatch_hand_threading) { 595 KD_TRACE(10, 596 ("kmp_hier_t.next_recurse(): T#%d (%d) going into barrier.\n", 597 gtid, hier_level)); 598 current->barrier(previous_id, tdata); 599 KD_TRACE(10, 600 ("kmp_hier_t.next_recurse(): T#%d (%d) released and exit %d\n", 601 gtid, hier_level, current->get_curr_status(tdata->index))); 602 } else { 603 KMP_DEBUG_ASSERT(previous_id == 0); 604 return status; 605 } 606 return current->get_curr_status(tdata->index); 607 } 608 609 public: 610 int top_level_nproc; 611 int num_layers; 612 bool valid; 613 int type_size; 614 kmp_hier_layer_info_t<T> *info; 615 kmp_hier_top_unit_t<T> **layers; 616 // Deallocate all memory from this hierarchy 617 void deallocate() { 618 for (int i = 0; i < num_layers; ++i) 619 if (layers[i] != NULL) { 620 __kmp_free(layers[i]); 621 } 622 if (layers != NULL) { 623 __kmp_free(layers); 624 layers = NULL; 625 } 626 if (info != NULL) { 627 __kmp_free(info); 628 info = NULL; 629 } 630 num_layers = 0; 631 valid = false; 632 } 633 // Returns true if reallocation is needed else false 634 bool need_to_reallocate(int n, const kmp_hier_layer_e *new_layers, 635 const enum sched_type *new_scheds, 636 const ST *new_chunks) const { 637 if (!valid || layers == NULL || info == NULL || 638 traits_t<T>::type_size != type_size || n != num_layers) 639 return true; 640 for (int i = 0; i < n; ++i) { 641 if (info[i].type != new_layers[i]) 642 return true; 643 if (info[i].sched != new_scheds[i]) 644 return true; 645 if (info[i].chunk != new_chunks[i]) 646 return true; 647 } 648 return false; 649 } 650 // A single thread should call this function while the other threads wait 651 // create a new scheduling hierarchy consisting of new_layers, new_scheds 652 // and new_chunks. These should come pre-sorted according to 653 // kmp_hier_layer_e value. This function will try to avoid reallocation 654 // if it can 655 void allocate_hier(int n, const kmp_hier_layer_e *new_layers, 656 const enum sched_type *new_scheds, const ST *new_chunks) { 657 top_level_nproc = 0; 658 if (!need_to_reallocate(n, new_layers, new_scheds, new_chunks)) { 659 KD_TRACE( 660 10, 661 ("kmp_hier_t<T>::allocate_hier: T#0 do not need to reallocate\n")); 662 for (int i = 0; i < n; ++i) { 663 info[i].num_active = 0; 664 for (int j = 0; j < get_length(i); ++j) 665 layers[i][j].active = 0; 666 } 667 return; 668 } 669 KD_TRACE(10, ("kmp_hier_t<T>::allocate_hier: T#0 full alloc\n")); 670 deallocate(); 671 type_size = traits_t<T>::type_size; 672 num_layers = n; 673 info = (kmp_hier_layer_info_t<T> *)__kmp_allocate( 674 sizeof(kmp_hier_layer_info_t<T>) * n); 675 layers = (kmp_hier_top_unit_t<T> **)__kmp_allocate( 676 sizeof(kmp_hier_top_unit_t<T> *) * n); 677 for (int i = 0; i < n; ++i) { 678 int max = 0; 679 kmp_hier_layer_e layer = new_layers[i]; 680 info[i].num_active = 0; 681 info[i].type = layer; 682 info[i].sched = new_scheds[i]; 683 info[i].chunk = new_chunks[i]; 684 max = __kmp_hier_max_units[layer + 1]; 685 if (max == 0) { 686 valid = false; 687 KMP_WARNING(HierSchedInvalid, __kmp_get_hier_str(layer)); 688 deallocate(); 689 return; 690 } 691 info[i].length = max; 692 layers[i] = (kmp_hier_top_unit_t<T> *)__kmp_allocate( 693 sizeof(kmp_hier_top_unit_t<T>) * max); 694 for (int j = 0; j < max; ++j) { 695 layers[i][j].active = 0; 696 layers[i][j].hier_pr.flags.use_hier = TRUE; 697 } 698 } 699 valid = true; 700 } 701 // loc - source file location 702 // gtid - global thread identifier 703 // pr - this thread's private dispatch buffer (corresponding with gtid) 704 // p_last (return value) - pointer to flag indicating this set of iterations 705 // contains last 706 // iteration 707 // p_lb (return value) - lower bound for this chunk of iterations 708 // p_ub (return value) - upper bound for this chunk of iterations 709 // p_st (return value) - stride for this chunk of iterations 710 // 711 // Returns 1 if there are more iterations to perform, 0 otherwise 712 int next(ident_t *loc, int gtid, dispatch_private_info_template<T> *pr, 713 kmp_int32 *p_last, T *p_lb, T *p_ub, ST *p_st) { 714 int status; 715 kmp_int32 contains_last = 0; 716 kmp_info_t *th = __kmp_threads[gtid]; 717 kmp_hier_private_bdata_t *tdata = &(th->th.th_hier_bar_data[0]); 718 auto parent = pr->get_parent(); 719 KMP_DEBUG_ASSERT(parent); 720 KMP_DEBUG_ASSERT(th); 721 KMP_DEBUG_ASSERT(tdata); 722 KMP_DEBUG_ASSERT(parent); 723 T nproc = (T)parent->get_num_active(); 724 T unit_id = (T)pr->get_hier_id(); 725 KD_TRACE( 726 10, 727 ("kmp_hier_t.next(): T#%d THREAD LEVEL nproc:%d unit_id:%d called\n", 728 gtid, nproc, unit_id)); 729 // Handthreading implementation 730 // Each iteration is performed by all threads on last unit (typically 731 // cores/tiles) 732 // e.g., threads 0,1,2,3 all execute iteration 0 733 // threads 0,1,2,3 all execute iteration 1 734 // threads 4,5,6,7 all execute iteration 2 735 // threads 4,5,6,7 all execute iteration 3 736 // ... etc. 737 if (__kmp_dispatch_hand_threading) { 738 KD_TRACE(10, 739 ("kmp_hier_t.next(): T#%d THREAD LEVEL using hand threading\n", 740 gtid)); 741 if (unit_id == 0) { 742 // For hand threading, the sh buffer on the lowest level is only ever 743 // modified and read by the primary thread on that level. Because of 744 // this, we can always use the first sh buffer. 745 auto sh = &(parent->hier_barrier.sh[0]); 746 KMP_DEBUG_ASSERT(sh); 747 status = __kmp_dispatch_next_algorithm<T>( 748 gtid, pr, sh, &contains_last, p_lb, p_ub, p_st, nproc, unit_id); 749 if (!status) { 750 bool done = false; 751 while (!done) { 752 done = true; 753 kmp_int32 uid; 754 __kmp_type_convert(unit_id, &uid); 755 status = next_recurse(loc, gtid, parent, &contains_last, p_lb, p_ub, 756 p_st, uid, 0); 757 if (status == 1) { 758 __kmp_dispatch_init_algorithm(loc, gtid, pr, pr->schedule, 759 parent->get_next_lb(tdata->index), 760 parent->get_next_ub(tdata->index), 761 parent->get_next_st(tdata->index), 762 #if USE_ITT_BUILD 763 NULL, 764 #endif 765 pr->u.p.parm1, nproc, unit_id); 766 sh->u.s.iteration = 0; 767 status = __kmp_dispatch_next_algorithm<T>( 768 gtid, pr, sh, &contains_last, p_lb, p_ub, p_st, nproc, 769 unit_id); 770 if (!status) { 771 KD_TRACE(10, 772 ("kmp_hier_t.next(): T#%d THREAD LEVEL status == 0 " 773 "after next_pr_sh()" 774 "trying again.\n", 775 gtid)); 776 done = false; 777 } 778 } else if (status == 2) { 779 KD_TRACE(10, ("kmp_hier_t.next(): T#%d THREAD LEVEL status == 2 " 780 "trying again.\n", 781 gtid)); 782 done = false; 783 } 784 } 785 } 786 parent->set_next_hand_thread(*p_lb, *p_ub, *p_st, status, tdata->index); 787 } // if primary thread of lowest unit level 788 parent->barrier(pr->get_hier_id(), tdata); 789 if (unit_id != 0) { 790 *p_lb = parent->get_curr_lb(tdata->index); 791 *p_ub = parent->get_curr_ub(tdata->index); 792 *p_st = parent->get_curr_st(tdata->index); 793 status = parent->get_curr_status(tdata->index); 794 } 795 } else { 796 // Normal implementation 797 // Each thread grabs an iteration chunk and executes it (no cooperation) 798 auto sh = parent->get_curr_sh(tdata->index); 799 KMP_DEBUG_ASSERT(sh); 800 status = __kmp_dispatch_next_algorithm<T>( 801 gtid, pr, sh, &contains_last, p_lb, p_ub, p_st, nproc, unit_id); 802 KD_TRACE(10, 803 ("kmp_hier_t.next(): T#%d THREAD LEVEL next_algorithm status:%d " 804 "contains_last:%d p_lb:%d p_ub:%d p_st:%d\n", 805 gtid, status, contains_last, *p_lb, *p_ub, *p_st)); 806 if (!status) { 807 bool done = false; 808 while (!done) { 809 done = true; 810 kmp_int32 uid; 811 __kmp_type_convert(unit_id, &uid); 812 status = next_recurse(loc, gtid, parent, &contains_last, p_lb, p_ub, 813 p_st, uid, 0); 814 if (status == 1) { 815 sh = parent->get_curr_sh(tdata->index); 816 __kmp_dispatch_init_algorithm(loc, gtid, pr, pr->schedule, 817 parent->get_curr_lb(tdata->index), 818 parent->get_curr_ub(tdata->index), 819 parent->get_curr_st(tdata->index), 820 #if USE_ITT_BUILD 821 NULL, 822 #endif 823 pr->u.p.parm1, nproc, unit_id); 824 status = __kmp_dispatch_next_algorithm<T>( 825 gtid, pr, sh, &contains_last, p_lb, p_ub, p_st, nproc, unit_id); 826 if (!status) { 827 KD_TRACE(10, ("kmp_hier_t.next(): T#%d THREAD LEVEL status == 0 " 828 "after next_pr_sh()" 829 "trying again.\n", 830 gtid)); 831 done = false; 832 } 833 } else if (status == 2) { 834 KD_TRACE(10, ("kmp_hier_t.next(): T#%d THREAD LEVEL status == 2 " 835 "trying again.\n", 836 gtid)); 837 done = false; 838 } 839 } 840 } 841 } 842 if (contains_last && !parent->hier_pr.flags.contains_last) { 843 KD_TRACE(10, ("kmp_hier_t.next(): T#%d THREAD LEVEL resetting " 844 "contains_last to FALSE\n", 845 gtid)); 846 contains_last = FALSE; 847 } 848 if (p_last) 849 *p_last = contains_last; 850 KD_TRACE(10, ("kmp_hier_t.next(): T#%d THREAD LEVEL exit status %d\n", gtid, 851 status)); 852 return status; 853 } 854 // These functions probe the layer info structure 855 // Returns the type of topology unit given level 856 kmp_hier_layer_e get_type(int level) const { 857 KMP_DEBUG_ASSERT(level >= 0); 858 KMP_DEBUG_ASSERT(level < num_layers); 859 return info[level].type; 860 } 861 // Returns the schedule type at given level 862 enum sched_type get_sched(int level) const { 863 KMP_DEBUG_ASSERT(level >= 0); 864 KMP_DEBUG_ASSERT(level < num_layers); 865 return info[level].sched; 866 } 867 // Returns the chunk size at given level 868 ST get_chunk(int level) const { 869 KMP_DEBUG_ASSERT(level >= 0); 870 KMP_DEBUG_ASSERT(level < num_layers); 871 return info[level].chunk; 872 } 873 // Returns the number of active threads at given level 874 int get_num_active(int level) const { 875 KMP_DEBUG_ASSERT(level >= 0); 876 KMP_DEBUG_ASSERT(level < num_layers); 877 return info[level].num_active; 878 } 879 // Returns the length of topology unit array at given level 880 int get_length(int level) const { 881 KMP_DEBUG_ASSERT(level >= 0); 882 KMP_DEBUG_ASSERT(level < num_layers); 883 return info[level].length; 884 } 885 // Returns the topology unit given the level and index 886 kmp_hier_top_unit_t<T> *get_unit(int level, int index) { 887 KMP_DEBUG_ASSERT(level >= 0); 888 KMP_DEBUG_ASSERT(level < num_layers); 889 KMP_DEBUG_ASSERT(index >= 0); 890 KMP_DEBUG_ASSERT(index < get_length(level)); 891 return &(layers[level][index]); 892 } 893 // Returns the number of layers in the hierarchy 894 int get_num_layers() const { return num_layers; } 895 // Returns the number of threads in the top layer 896 // This is necessary because we don't store a topology unit as 897 // the very top level and the scheduling algorithms need this information 898 int get_top_level_nproc() const { return top_level_nproc; } 899 // Return whether this hierarchy is valid or not 900 bool is_valid() const { return valid; } 901 #ifdef KMP_DEBUG 902 // Print the hierarchy 903 void print() { 904 KD_TRACE(10, ("kmp_hier_t:\n")); 905 for (int i = num_layers - 1; i >= 0; --i) { 906 KD_TRACE(10, ("Info[%d] = ", i)); 907 info[i].print(); 908 } 909 for (int i = num_layers - 1; i >= 0; --i) { 910 KD_TRACE(10, ("Layer[%d] =\n", i)); 911 for (int j = 0; j < info[i].length; ++j) { 912 layers[i][j].print(); 913 } 914 } 915 } 916 #endif 917 }; 918 919 template <typename T> 920 void __kmp_dispatch_init_hierarchy(ident_t *loc, int n, 921 kmp_hier_layer_e *new_layers, 922 enum sched_type *new_scheds, 923 typename traits_t<T>::signed_t *new_chunks, 924 T lb, T ub, 925 typename traits_t<T>::signed_t st) { 926 int tid, gtid, num_hw_threads, num_threads_per_layer1, active; 927 unsigned int my_buffer_index; 928 kmp_info_t *th; 929 kmp_team_t *team; 930 dispatch_private_info_template<T> *pr; 931 dispatch_shared_info_template<T> volatile *sh; 932 gtid = __kmp_entry_gtid(); 933 tid = __kmp_tid_from_gtid(gtid); 934 #ifdef KMP_DEBUG 935 KD_TRACE(10, ("__kmp_dispatch_init_hierarchy: T#%d called: %d layer(s)\n", 936 gtid, n)); 937 for (int i = 0; i < n; ++i) { 938 const char *layer = __kmp_get_hier_str(new_layers[i]); 939 KD_TRACE(10, ("__kmp_dispatch_init_hierarchy: T#%d: new_layers[%d] = %s, " 940 "new_scheds[%d] = %d, new_chunks[%d] = %u\n", 941 gtid, i, layer, i, (int)new_scheds[i], i, new_chunks[i])); 942 } 943 #endif // KMP_DEBUG 944 KMP_DEBUG_ASSERT(n > 0); 945 KMP_DEBUG_ASSERT(new_layers); 946 KMP_DEBUG_ASSERT(new_scheds); 947 KMP_DEBUG_ASSERT(new_chunks); 948 if (!TCR_4(__kmp_init_parallel)) 949 __kmp_parallel_initialize(); 950 __kmp_resume_if_soft_paused(); 951 952 th = __kmp_threads[gtid]; 953 team = th->th.th_team; 954 active = !team->t.t_serialized; 955 th->th.th_ident = loc; 956 num_hw_threads = __kmp_hier_max_units[kmp_hier_layer_e::LAYER_THREAD + 1]; 957 KMP_DEBUG_ASSERT(th->th.th_dispatch == 958 &th->th.th_team->t.t_dispatch[th->th.th_info.ds.ds_tid]); 959 my_buffer_index = th->th.th_dispatch->th_disp_index; 960 pr = reinterpret_cast<dispatch_private_info_template<T> *>( 961 &th->th.th_dispatch 962 ->th_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]); 963 sh = reinterpret_cast<dispatch_shared_info_template<T> volatile *>( 964 &team->t.t_disp_buffer[my_buffer_index % __kmp_dispatch_num_buffers]); 965 if (!active) { 966 KD_TRACE(10, ("__kmp_dispatch_init_hierarchy: T#%d not active parallel. " 967 "Using normal dispatch functions.\n", 968 gtid)); 969 KMP_DEBUG_ASSERT(pr); 970 pr->flags.use_hier = FALSE; 971 pr->flags.contains_last = FALSE; 972 return; 973 } 974 KMP_DEBUG_ASSERT(pr); 975 KMP_DEBUG_ASSERT(sh); 976 pr->flags.use_hier = TRUE; 977 pr->u.p.tc = 0; 978 // Have primary thread allocate the hierarchy 979 if (__kmp_tid_from_gtid(gtid) == 0) { 980 KD_TRACE(10, ("__kmp_dispatch_init_hierarchy: T#%d pr:%p sh:%p allocating " 981 "hierarchy\n", 982 gtid, pr, sh)); 983 if (sh->hier == NULL) { 984 sh->hier = (kmp_hier_t<T> *)__kmp_allocate(sizeof(kmp_hier_t<T>)); 985 } 986 sh->hier->allocate_hier(n, new_layers, new_scheds, new_chunks); 987 sh->u.s.iteration = 0; 988 } 989 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL); 990 // Check to make sure the hierarchy is valid 991 kmp_hier_t<T> *hier = sh->hier; 992 if (!sh->hier->is_valid()) { 993 pr->flags.use_hier = FALSE; 994 return; 995 } 996 // Have threads allocate their thread-private barrier data if it hasn't 997 // already been allocated 998 if (th->th.th_hier_bar_data == NULL) { 999 th->th.th_hier_bar_data = (kmp_hier_private_bdata_t *)__kmp_allocate( 1000 sizeof(kmp_hier_private_bdata_t) * kmp_hier_layer_e::LAYER_LAST); 1001 } 1002 // Have threads "register" themselves by modifying the active count for each 1003 // level they are involved in. The active count will act as nthreads for that 1004 // level regarding the scheduling algorithms 1005 for (int i = 0; i < n; ++i) { 1006 int index = __kmp_dispatch_get_index(tid, hier->get_type(i)); 1007 kmp_hier_top_unit_t<T> *my_unit = hier->get_unit(i, index); 1008 // Setup the thread's private dispatch buffer's hierarchy pointers 1009 if (i == 0) 1010 pr->hier_parent = my_unit; 1011 // If this unit is already active, then increment active count and wait 1012 if (my_unit->is_active()) { 1013 KD_TRACE(10, ("__kmp_dispatch_init_hierarchy: T#%d my_unit (%p) " 1014 "is already active (%d)\n", 1015 gtid, my_unit, my_unit->active)); 1016 KMP_TEST_THEN_INC32(&(my_unit->active)); 1017 break; 1018 } 1019 // Flag that this unit is active 1020 if (KMP_COMPARE_AND_STORE_ACQ32(&(my_unit->active), 0, 1)) { 1021 // Do not setup parent pointer for top level unit since it has no parent 1022 if (i < n - 1) { 1023 // Setup middle layer pointers to parents 1024 my_unit->get_my_pr()->hier_id = 1025 index % __kmp_dispatch_get_t1_per_t2(hier->get_type(i), 1026 hier->get_type(i + 1)); 1027 int parent_index = __kmp_dispatch_get_index(tid, hier->get_type(i + 1)); 1028 my_unit->hier_parent = hier->get_unit(i + 1, parent_index); 1029 } else { 1030 // Setup top layer information (no parent pointers are set) 1031 my_unit->get_my_pr()->hier_id = 1032 index % __kmp_dispatch_get_t1_per_t2(hier->get_type(i), 1033 kmp_hier_layer_e::LAYER_LOOP); 1034 KMP_TEST_THEN_INC32(&(hier->top_level_nproc)); 1035 my_unit->hier_parent = nullptr; 1036 } 1037 // Set trip count to 0 so that next() operation will initially climb up 1038 // the hierarchy to get more iterations (early exit in next() for tc == 0) 1039 my_unit->get_my_pr()->u.p.tc = 0; 1040 // Increment this layer's number of active units 1041 KMP_TEST_THEN_INC32(&(hier->info[i].num_active)); 1042 KD_TRACE(10, ("__kmp_dispatch_init_hierarchy: T#%d my_unit (%p) " 1043 "incrementing num_active\n", 1044 gtid, my_unit)); 1045 } else { 1046 KMP_TEST_THEN_INC32(&(my_unit->active)); 1047 break; 1048 } 1049 } 1050 // Set this thread's id 1051 num_threads_per_layer1 = __kmp_dispatch_get_t1_per_t2( 1052 kmp_hier_layer_e::LAYER_THREAD, hier->get_type(0)); 1053 pr->hier_id = tid % num_threads_per_layer1; 1054 // For oversubscribed threads, increment their index within the lowest unit 1055 // This is done to prevent having two or more threads with id 0, id 1, etc. 1056 if (tid >= num_hw_threads) 1057 pr->hier_id += ((tid / num_hw_threads) * num_threads_per_layer1); 1058 KD_TRACE( 1059 10, ("__kmp_dispatch_init_hierarchy: T#%d setting lowest hier_id to %d\n", 1060 gtid, pr->hier_id)); 1061 1062 pr->flags.contains_last = FALSE; 1063 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL); 1064 1065 // Now that the number of active threads at each level is determined, 1066 // the barrier data for each unit can be initialized and the last layer's 1067 // loop information can be initialized. 1068 int prev_id = pr->get_hier_id(); 1069 for (int i = 0; i < n; ++i) { 1070 if (prev_id != 0) 1071 break; 1072 int index = __kmp_dispatch_get_index(tid, hier->get_type(i)); 1073 kmp_hier_top_unit_t<T> *my_unit = hier->get_unit(i, index); 1074 // Only primary threads of this unit within the hierarchy do initialization 1075 KD_TRACE(10, ("__kmp_dispatch_init_hierarchy: T#%d (%d) prev_id is 0\n", 1076 gtid, i)); 1077 my_unit->reset_shared_barrier(); 1078 my_unit->hier_pr.flags.contains_last = FALSE; 1079 // Last layer, initialize the private buffers with entire loop information 1080 // Now the next next_algorithm() call will get the first chunk of 1081 // iterations properly 1082 if (i == n - 1) { 1083 __kmp_dispatch_init_algorithm<T>( 1084 loc, gtid, my_unit->get_my_pr(), hier->get_sched(i), lb, ub, st, 1085 #if USE_ITT_BUILD 1086 NULL, 1087 #endif 1088 hier->get_chunk(i), hier->get_num_active(i), my_unit->get_hier_id()); 1089 } 1090 prev_id = my_unit->get_hier_id(); 1091 } 1092 // Initialize each layer of the thread's private barrier data 1093 kmp_hier_top_unit_t<T> *unit = pr->hier_parent; 1094 for (int i = 0; i < n && unit; ++i, unit = unit->get_parent()) { 1095 kmp_hier_private_bdata_t *tdata = &(th->th.th_hier_bar_data[i]); 1096 unit->reset_private_barrier(tdata); 1097 } 1098 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL); 1099 1100 #ifdef KMP_DEBUG 1101 if (__kmp_tid_from_gtid(gtid) == 0) { 1102 for (int i = 0; i < n; ++i) { 1103 KD_TRACE(10, 1104 ("__kmp_dispatch_init_hierarchy: T#%d active count[%d] = %d\n", 1105 gtid, i, hier->get_num_active(i))); 1106 } 1107 hier->print(); 1108 } 1109 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL); 1110 #endif // KMP_DEBUG 1111 } 1112 #endif 1113