1 /* 2 * kmp_tasking.cpp -- OpenMP 3.0 tasking support. 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.h" 14 #include "kmp_i18n.h" 15 #include "kmp_itt.h" 16 #include "kmp_stats.h" 17 #include "kmp_wait_release.h" 18 #include "kmp_taskdeps.h" 19 20 #if OMPT_SUPPORT 21 #include "ompt-specific.h" 22 #endif 23 24 /* forward declaration */ 25 static void __kmp_enable_tasking(kmp_task_team_t *task_team, 26 kmp_info_t *this_thr); 27 static void __kmp_alloc_task_deque(kmp_info_t *thread, 28 kmp_thread_data_t *thread_data); 29 static int __kmp_realloc_task_threads_data(kmp_info_t *thread, 30 kmp_task_team_t *task_team); 31 static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask); 32 33 #ifdef BUILD_TIED_TASK_STACK 34 35 // __kmp_trace_task_stack: print the tied tasks from the task stack in order 36 // from top do bottom 37 // 38 // gtid: global thread identifier for thread containing stack 39 // thread_data: thread data for task team thread containing stack 40 // threshold: value above which the trace statement triggers 41 // location: string identifying call site of this function (for trace) 42 static void __kmp_trace_task_stack(kmp_int32 gtid, 43 kmp_thread_data_t *thread_data, 44 int threshold, char *location) { 45 kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 46 kmp_taskdata_t **stack_top = task_stack->ts_top; 47 kmp_int32 entries = task_stack->ts_entries; 48 kmp_taskdata_t *tied_task; 49 50 KA_TRACE( 51 threshold, 52 ("__kmp_trace_task_stack(start): location = %s, gtid = %d, entries = %d, " 53 "first_block = %p, stack_top = %p \n", 54 location, gtid, entries, task_stack->ts_first_block, stack_top)); 55 56 KMP_DEBUG_ASSERT(stack_top != NULL); 57 KMP_DEBUG_ASSERT(entries > 0); 58 59 while (entries != 0) { 60 KMP_DEBUG_ASSERT(stack_top != &task_stack->ts_first_block.sb_block[0]); 61 // fix up ts_top if we need to pop from previous block 62 if (entries & TASK_STACK_INDEX_MASK == 0) { 63 kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(stack_top); 64 65 stack_block = stack_block->sb_prev; 66 stack_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE]; 67 } 68 69 // finish bookkeeping 70 stack_top--; 71 entries--; 72 73 tied_task = *stack_top; 74 75 KMP_DEBUG_ASSERT(tied_task != NULL); 76 KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED); 77 78 KA_TRACE(threshold, 79 ("__kmp_trace_task_stack(%s): gtid=%d, entry=%d, " 80 "stack_top=%p, tied_task=%p\n", 81 location, gtid, entries, stack_top, tied_task)); 82 } 83 KMP_DEBUG_ASSERT(stack_top == &task_stack->ts_first_block.sb_block[0]); 84 85 KA_TRACE(threshold, 86 ("__kmp_trace_task_stack(exit): location = %s, gtid = %d\n", 87 location, gtid)); 88 } 89 90 // __kmp_init_task_stack: initialize the task stack for the first time 91 // after a thread_data structure is created. 92 // It should not be necessary to do this again (assuming the stack works). 93 // 94 // gtid: global thread identifier of calling thread 95 // thread_data: thread data for task team thread containing stack 96 static void __kmp_init_task_stack(kmp_int32 gtid, 97 kmp_thread_data_t *thread_data) { 98 kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 99 kmp_stack_block_t *first_block; 100 101 // set up the first block of the stack 102 first_block = &task_stack->ts_first_block; 103 task_stack->ts_top = (kmp_taskdata_t **)first_block; 104 memset((void *)first_block, '\0', 105 TASK_STACK_BLOCK_SIZE * sizeof(kmp_taskdata_t *)); 106 107 // initialize the stack to be empty 108 task_stack->ts_entries = TASK_STACK_EMPTY; 109 first_block->sb_next = NULL; 110 first_block->sb_prev = NULL; 111 } 112 113 // __kmp_free_task_stack: free the task stack when thread_data is destroyed. 114 // 115 // gtid: global thread identifier for calling thread 116 // thread_data: thread info for thread containing stack 117 static void __kmp_free_task_stack(kmp_int32 gtid, 118 kmp_thread_data_t *thread_data) { 119 kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 120 kmp_stack_block_t *stack_block = &task_stack->ts_first_block; 121 122 KMP_DEBUG_ASSERT(task_stack->ts_entries == TASK_STACK_EMPTY); 123 // free from the second block of the stack 124 while (stack_block != NULL) { 125 kmp_stack_block_t *next_block = (stack_block) ? stack_block->sb_next : NULL; 126 127 stack_block->sb_next = NULL; 128 stack_block->sb_prev = NULL; 129 if (stack_block != &task_stack->ts_first_block) { 130 __kmp_thread_free(thread, 131 stack_block); // free the block, if not the first 132 } 133 stack_block = next_block; 134 } 135 // initialize the stack to be empty 136 task_stack->ts_entries = 0; 137 task_stack->ts_top = NULL; 138 } 139 140 // __kmp_push_task_stack: Push the tied task onto the task stack. 141 // Grow the stack if necessary by allocating another block. 142 // 143 // gtid: global thread identifier for calling thread 144 // thread: thread info for thread containing stack 145 // tied_task: the task to push on the stack 146 static void __kmp_push_task_stack(kmp_int32 gtid, kmp_info_t *thread, 147 kmp_taskdata_t *tied_task) { 148 // GEH - need to consider what to do if tt_threads_data not allocated yet 149 kmp_thread_data_t *thread_data = 150 &thread->th.th_task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)]; 151 kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 152 153 if (tied_task->td_flags.team_serial || tied_task->td_flags.tasking_ser) { 154 return; // Don't push anything on stack if team or team tasks are serialized 155 } 156 157 KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED); 158 KMP_DEBUG_ASSERT(task_stack->ts_top != NULL); 159 160 KA_TRACE(20, 161 ("__kmp_push_task_stack(enter): GTID: %d; THREAD: %p; TASK: %p\n", 162 gtid, thread, tied_task)); 163 // Store entry 164 *(task_stack->ts_top) = tied_task; 165 166 // Do bookkeeping for next push 167 task_stack->ts_top++; 168 task_stack->ts_entries++; 169 170 if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) { 171 // Find beginning of this task block 172 kmp_stack_block_t *stack_block = 173 (kmp_stack_block_t *)(task_stack->ts_top - TASK_STACK_BLOCK_SIZE); 174 175 // Check if we already have a block 176 if (stack_block->sb_next != 177 NULL) { // reset ts_top to beginning of next block 178 task_stack->ts_top = &stack_block->sb_next->sb_block[0]; 179 } else { // Alloc new block and link it up 180 kmp_stack_block_t *new_block = (kmp_stack_block_t *)__kmp_thread_calloc( 181 thread, sizeof(kmp_stack_block_t)); 182 183 task_stack->ts_top = &new_block->sb_block[0]; 184 stack_block->sb_next = new_block; 185 new_block->sb_prev = stack_block; 186 new_block->sb_next = NULL; 187 188 KA_TRACE( 189 30, 190 ("__kmp_push_task_stack(): GTID: %d; TASK: %p; Alloc new block: %p\n", 191 gtid, tied_task, new_block)); 192 } 193 } 194 KA_TRACE(20, ("__kmp_push_task_stack(exit): GTID: %d; TASK: %p\n", gtid, 195 tied_task)); 196 } 197 198 // __kmp_pop_task_stack: Pop the tied task from the task stack. Don't return 199 // the task, just check to make sure it matches the ending task passed in. 200 // 201 // gtid: global thread identifier for the calling thread 202 // thread: thread info structure containing stack 203 // tied_task: the task popped off the stack 204 // ending_task: the task that is ending (should match popped task) 205 static void __kmp_pop_task_stack(kmp_int32 gtid, kmp_info_t *thread, 206 kmp_taskdata_t *ending_task) { 207 // GEH - need to consider what to do if tt_threads_data not allocated yet 208 kmp_thread_data_t *thread_data = 209 &thread->th.th_task_team->tt_threads_data[__kmp_tid_from_gtid(gtid)]; 210 kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 211 kmp_taskdata_t *tied_task; 212 213 if (ending_task->td_flags.team_serial || ending_task->td_flags.tasking_ser) { 214 // Don't pop anything from stack if team or team tasks are serialized 215 return; 216 } 217 218 KMP_DEBUG_ASSERT(task_stack->ts_top != NULL); 219 KMP_DEBUG_ASSERT(task_stack->ts_entries > 0); 220 221 KA_TRACE(20, ("__kmp_pop_task_stack(enter): GTID: %d; THREAD: %p\n", gtid, 222 thread)); 223 224 // fix up ts_top if we need to pop from previous block 225 if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) { 226 kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(task_stack->ts_top); 227 228 stack_block = stack_block->sb_prev; 229 task_stack->ts_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE]; 230 } 231 232 // finish bookkeeping 233 task_stack->ts_top--; 234 task_stack->ts_entries--; 235 236 tied_task = *(task_stack->ts_top); 237 238 KMP_DEBUG_ASSERT(tied_task != NULL); 239 KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED); 240 KMP_DEBUG_ASSERT(tied_task == ending_task); // If we built the stack correctly 241 242 KA_TRACE(20, ("__kmp_pop_task_stack(exit): GTID: %d; TASK: %p\n", gtid, 243 tied_task)); 244 return; 245 } 246 #endif /* BUILD_TIED_TASK_STACK */ 247 248 // returns 1 if new task is allowed to execute, 0 otherwise 249 // checks Task Scheduling constraint (if requested) and 250 // mutexinoutset dependencies if any 251 static bool __kmp_task_is_allowed(int gtid, const kmp_int32 is_constrained, 252 const kmp_taskdata_t *tasknew, 253 const kmp_taskdata_t *taskcurr) { 254 if (is_constrained && (tasknew->td_flags.tiedness == TASK_TIED)) { 255 // Check if the candidate obeys the Task Scheduling Constraints (TSC) 256 // only descendant of all deferred tied tasks can be scheduled, checking 257 // the last one is enough, as it in turn is the descendant of all others 258 kmp_taskdata_t *current = taskcurr->td_last_tied; 259 KMP_DEBUG_ASSERT(current != NULL); 260 // check if the task is not suspended on barrier 261 if (current->td_flags.tasktype == TASK_EXPLICIT || 262 current->td_taskwait_thread > 0) { // <= 0 on barrier 263 kmp_int32 level = current->td_level; 264 kmp_taskdata_t *parent = tasknew->td_parent; 265 while (parent != current && parent->td_level > level) { 266 // check generation up to the level of the current task 267 parent = parent->td_parent; 268 KMP_DEBUG_ASSERT(parent != NULL); 269 } 270 if (parent != current) 271 return false; 272 } 273 } 274 // Check mutexinoutset dependencies, acquire locks 275 kmp_depnode_t *node = tasknew->td_depnode; 276 if (UNLIKELY(node && (node->dn.mtx_num_locks > 0))) { 277 for (int i = 0; i < node->dn.mtx_num_locks; ++i) { 278 KMP_DEBUG_ASSERT(node->dn.mtx_locks[i] != NULL); 279 if (__kmp_test_lock(node->dn.mtx_locks[i], gtid)) 280 continue; 281 // could not get the lock, release previous locks 282 for (int j = i - 1; j >= 0; --j) 283 __kmp_release_lock(node->dn.mtx_locks[j], gtid); 284 return false; 285 } 286 // negative num_locks means all locks acquired successfully 287 node->dn.mtx_num_locks = -node->dn.mtx_num_locks; 288 } 289 return true; 290 } 291 292 // __kmp_realloc_task_deque: 293 // Re-allocates a task deque for a particular thread, copies the content from 294 // the old deque and adjusts the necessary data structures relating to the 295 // deque. This operation must be done with the deque_lock being held 296 static void __kmp_realloc_task_deque(kmp_info_t *thread, 297 kmp_thread_data_t *thread_data) { 298 kmp_int32 size = TASK_DEQUE_SIZE(thread_data->td); 299 KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) == size); 300 kmp_int32 new_size = 2 * size; 301 302 KE_TRACE(10, ("__kmp_realloc_task_deque: T#%d reallocating deque[from %d to " 303 "%d] for thread_data %p\n", 304 __kmp_gtid_from_thread(thread), size, new_size, thread_data)); 305 306 kmp_taskdata_t **new_deque = 307 (kmp_taskdata_t **)__kmp_allocate(new_size * sizeof(kmp_taskdata_t *)); 308 309 int i, j; 310 for (i = thread_data->td.td_deque_head, j = 0; j < size; 311 i = (i + 1) & TASK_DEQUE_MASK(thread_data->td), j++) 312 new_deque[j] = thread_data->td.td_deque[i]; 313 314 __kmp_free(thread_data->td.td_deque); 315 316 thread_data->td.td_deque_head = 0; 317 thread_data->td.td_deque_tail = size; 318 thread_data->td.td_deque = new_deque; 319 thread_data->td.td_deque_size = new_size; 320 } 321 322 // __kmp_push_task: Add a task to the thread's deque 323 static kmp_int32 __kmp_push_task(kmp_int32 gtid, kmp_task_t *task) { 324 kmp_info_t *thread = __kmp_threads[gtid]; 325 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 326 327 // We don't need to map to shadow gtid if it is already hidden helper thread 328 if (taskdata->td_flags.hidden_helper && !KMP_HIDDEN_HELPER_THREAD(gtid)) { 329 gtid = KMP_GTID_TO_SHADOW_GTID(gtid); 330 thread = __kmp_threads[gtid]; 331 } 332 333 kmp_task_team_t *task_team = thread->th.th_task_team; 334 kmp_int32 tid = __kmp_tid_from_gtid(gtid); 335 kmp_thread_data_t *thread_data; 336 337 KA_TRACE(20, 338 ("__kmp_push_task: T#%d trying to push task %p.\n", gtid, taskdata)); 339 340 if (UNLIKELY(taskdata->td_flags.tiedness == TASK_UNTIED)) { 341 // untied task needs to increment counter so that the task structure is not 342 // freed prematurely 343 kmp_int32 counter = 1 + KMP_ATOMIC_INC(&taskdata->td_untied_count); 344 KMP_DEBUG_USE_VAR(counter); 345 KA_TRACE( 346 20, 347 ("__kmp_push_task: T#%d untied_count (%d) incremented for task %p\n", 348 gtid, counter, taskdata)); 349 } 350 351 // The first check avoids building task_team thread data if serialized 352 if (UNLIKELY(taskdata->td_flags.task_serial)) { 353 KA_TRACE(20, ("__kmp_push_task: T#%d team serialized; returning " 354 "TASK_NOT_PUSHED for task %p\n", 355 gtid, taskdata)); 356 return TASK_NOT_PUSHED; 357 } 358 359 // Now that serialized tasks have returned, we can assume that we are not in 360 // immediate exec mode 361 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 362 if (UNLIKELY(!KMP_TASKING_ENABLED(task_team))) { 363 __kmp_enable_tasking(task_team, thread); 364 } 365 KMP_DEBUG_ASSERT(TCR_4(task_team->tt.tt_found_tasks) == TRUE); 366 KMP_DEBUG_ASSERT(TCR_PTR(task_team->tt.tt_threads_data) != NULL); 367 368 // Find tasking deque specific to encountering thread 369 thread_data = &task_team->tt.tt_threads_data[tid]; 370 371 // No lock needed since only owner can allocate. If the task is hidden_helper, 372 // we don't need it either because we have initialized the dequeue for hidden 373 // helper thread data. 374 if (UNLIKELY(thread_data->td.td_deque == NULL)) { 375 __kmp_alloc_task_deque(thread, thread_data); 376 } 377 378 int locked = 0; 379 // Check if deque is full 380 if (TCR_4(thread_data->td.td_deque_ntasks) >= 381 TASK_DEQUE_SIZE(thread_data->td)) { 382 if (__kmp_enable_task_throttling && 383 __kmp_task_is_allowed(gtid, __kmp_task_stealing_constraint, taskdata, 384 thread->th.th_current_task)) { 385 KA_TRACE(20, ("__kmp_push_task: T#%d deque is full; returning " 386 "TASK_NOT_PUSHED for task %p\n", 387 gtid, taskdata)); 388 return TASK_NOT_PUSHED; 389 } else { 390 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 391 locked = 1; 392 if (TCR_4(thread_data->td.td_deque_ntasks) >= 393 TASK_DEQUE_SIZE(thread_data->td)) { 394 // expand deque to push the task which is not allowed to execute 395 __kmp_realloc_task_deque(thread, thread_data); 396 } 397 } 398 } 399 // Lock the deque for the task push operation 400 if (!locked) { 401 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 402 // Need to recheck as we can get a proxy task from thread outside of OpenMP 403 if (TCR_4(thread_data->td.td_deque_ntasks) >= 404 TASK_DEQUE_SIZE(thread_data->td)) { 405 if (__kmp_enable_task_throttling && 406 __kmp_task_is_allowed(gtid, __kmp_task_stealing_constraint, taskdata, 407 thread->th.th_current_task)) { 408 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 409 KA_TRACE(20, ("__kmp_push_task: T#%d deque is full on 2nd check; " 410 "returning TASK_NOT_PUSHED for task %p\n", 411 gtid, taskdata)); 412 return TASK_NOT_PUSHED; 413 } else { 414 // expand deque to push the task which is not allowed to execute 415 __kmp_realloc_task_deque(thread, thread_data); 416 } 417 } 418 } 419 // Must have room since no thread can add tasks but calling thread 420 KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) < 421 TASK_DEQUE_SIZE(thread_data->td)); 422 423 thread_data->td.td_deque[thread_data->td.td_deque_tail] = 424 taskdata; // Push taskdata 425 // Wrap index. 426 thread_data->td.td_deque_tail = 427 (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td); 428 TCW_4(thread_data->td.td_deque_ntasks, 429 TCR_4(thread_data->td.td_deque_ntasks) + 1); // Adjust task count 430 KMP_FSYNC_RELEASING(thread->th.th_current_task); // releasing self 431 KMP_FSYNC_RELEASING(taskdata); // releasing child 432 KA_TRACE(20, ("__kmp_push_task: T#%d returning TASK_SUCCESSFULLY_PUSHED: " 433 "task=%p ntasks=%d head=%u tail=%u\n", 434 gtid, taskdata, thread_data->td.td_deque_ntasks, 435 thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 436 437 auto hidden_helper = taskdata->td_flags.hidden_helper; 438 439 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 440 441 // Signal one worker thread to execute the task 442 if (UNLIKELY(hidden_helper)) { 443 // Wake hidden helper threads up if they're sleeping 444 __kmp_hidden_helper_worker_thread_signal(); 445 } 446 447 return TASK_SUCCESSFULLY_PUSHED; 448 } 449 450 // __kmp_pop_current_task_from_thread: set up current task from called thread 451 // when team ends 452 // 453 // this_thr: thread structure to set current_task in. 454 void __kmp_pop_current_task_from_thread(kmp_info_t *this_thr) { 455 KF_TRACE(10, ("__kmp_pop_current_task_from_thread(enter): T#%d " 456 "this_thread=%p, curtask=%p, " 457 "curtask_parent=%p\n", 458 0, this_thr, this_thr->th.th_current_task, 459 this_thr->th.th_current_task->td_parent)); 460 461 this_thr->th.th_current_task = this_thr->th.th_current_task->td_parent; 462 463 KF_TRACE(10, ("__kmp_pop_current_task_from_thread(exit): T#%d " 464 "this_thread=%p, curtask=%p, " 465 "curtask_parent=%p\n", 466 0, this_thr, this_thr->th.th_current_task, 467 this_thr->th.th_current_task->td_parent)); 468 } 469 470 // __kmp_push_current_task_to_thread: set up current task in called thread for a 471 // new team 472 // 473 // this_thr: thread structure to set up 474 // team: team for implicit task data 475 // tid: thread within team to set up 476 void __kmp_push_current_task_to_thread(kmp_info_t *this_thr, kmp_team_t *team, 477 int tid) { 478 // current task of the thread is a parent of the new just created implicit 479 // tasks of new team 480 KF_TRACE(10, ("__kmp_push_current_task_to_thread(enter): T#%d this_thread=%p " 481 "curtask=%p " 482 "parent_task=%p\n", 483 tid, this_thr, this_thr->th.th_current_task, 484 team->t.t_implicit_task_taskdata[tid].td_parent)); 485 486 KMP_DEBUG_ASSERT(this_thr != NULL); 487 488 if (tid == 0) { 489 if (this_thr->th.th_current_task != &team->t.t_implicit_task_taskdata[0]) { 490 team->t.t_implicit_task_taskdata[0].td_parent = 491 this_thr->th.th_current_task; 492 this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[0]; 493 } 494 } else { 495 team->t.t_implicit_task_taskdata[tid].td_parent = 496 team->t.t_implicit_task_taskdata[0].td_parent; 497 this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[tid]; 498 } 499 500 KF_TRACE(10, ("__kmp_push_current_task_to_thread(exit): T#%d this_thread=%p " 501 "curtask=%p " 502 "parent_task=%p\n", 503 tid, this_thr, this_thr->th.th_current_task, 504 team->t.t_implicit_task_taskdata[tid].td_parent)); 505 } 506 507 // __kmp_task_start: bookkeeping for a task starting execution 508 // 509 // GTID: global thread id of calling thread 510 // task: task starting execution 511 // current_task: task suspending 512 static void __kmp_task_start(kmp_int32 gtid, kmp_task_t *task, 513 kmp_taskdata_t *current_task) { 514 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 515 kmp_info_t *thread = __kmp_threads[gtid]; 516 517 KA_TRACE(10, 518 ("__kmp_task_start(enter): T#%d starting task %p: current_task=%p\n", 519 gtid, taskdata, current_task)); 520 521 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 522 523 // mark currently executing task as suspended 524 // TODO: GEH - make sure root team implicit task is initialized properly. 525 // KMP_DEBUG_ASSERT( current_task -> td_flags.executing == 1 ); 526 current_task->td_flags.executing = 0; 527 528 // Add task to stack if tied 529 #ifdef BUILD_TIED_TASK_STACK 530 if (taskdata->td_flags.tiedness == TASK_TIED) { 531 __kmp_push_task_stack(gtid, thread, taskdata); 532 } 533 #endif /* BUILD_TIED_TASK_STACK */ 534 535 // mark starting task as executing and as current task 536 thread->th.th_current_task = taskdata; 537 538 KMP_DEBUG_ASSERT(taskdata->td_flags.started == 0 || 539 taskdata->td_flags.tiedness == TASK_UNTIED); 540 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0 || 541 taskdata->td_flags.tiedness == TASK_UNTIED); 542 taskdata->td_flags.started = 1; 543 taskdata->td_flags.executing = 1; 544 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0); 545 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 546 547 // GEH TODO: shouldn't we pass some sort of location identifier here? 548 // APT: yes, we will pass location here. 549 // need to store current thread state (in a thread or taskdata structure) 550 // before setting work_state, otherwise wrong state is set after end of task 551 552 KA_TRACE(10, ("__kmp_task_start(exit): T#%d task=%p\n", gtid, taskdata)); 553 554 return; 555 } 556 557 #if OMPT_SUPPORT 558 //------------------------------------------------------------------------------ 559 // __ompt_task_init: 560 // Initialize OMPT fields maintained by a task. This will only be called after 561 // ompt_start_tool, so we already know whether ompt is enabled or not. 562 563 static inline void __ompt_task_init(kmp_taskdata_t *task, int tid) { 564 // The calls to __ompt_task_init already have the ompt_enabled condition. 565 task->ompt_task_info.task_data.value = 0; 566 task->ompt_task_info.frame.exit_frame = ompt_data_none; 567 task->ompt_task_info.frame.enter_frame = ompt_data_none; 568 task->ompt_task_info.frame.exit_frame_flags = 569 ompt_frame_runtime | ompt_frame_framepointer; 570 task->ompt_task_info.frame.enter_frame_flags = 571 ompt_frame_runtime | ompt_frame_framepointer; 572 } 573 574 // __ompt_task_start: 575 // Build and trigger task-begin event 576 static inline void __ompt_task_start(kmp_task_t *task, 577 kmp_taskdata_t *current_task, 578 kmp_int32 gtid) { 579 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 580 ompt_task_status_t status = ompt_task_switch; 581 if (__kmp_threads[gtid]->th.ompt_thread_info.ompt_task_yielded) { 582 status = ompt_task_yield; 583 __kmp_threads[gtid]->th.ompt_thread_info.ompt_task_yielded = 0; 584 } 585 /* let OMPT know that we're about to run this task */ 586 if (ompt_enabled.ompt_callback_task_schedule) { 587 ompt_callbacks.ompt_callback(ompt_callback_task_schedule)( 588 &(current_task->ompt_task_info.task_data), status, 589 &(taskdata->ompt_task_info.task_data)); 590 } 591 taskdata->ompt_task_info.scheduling_parent = current_task; 592 } 593 594 // __ompt_task_finish: 595 // Build and trigger final task-schedule event 596 static inline void __ompt_task_finish(kmp_task_t *task, 597 kmp_taskdata_t *resumed_task, 598 ompt_task_status_t status) { 599 if (ompt_enabled.ompt_callback_task_schedule) { 600 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 601 if (__kmp_omp_cancellation && taskdata->td_taskgroup && 602 taskdata->td_taskgroup->cancel_request == cancel_taskgroup) { 603 status = ompt_task_cancel; 604 } 605 606 /* let OMPT know that we're returning to the callee task */ 607 ompt_callbacks.ompt_callback(ompt_callback_task_schedule)( 608 &(taskdata->ompt_task_info.task_data), status, 609 (resumed_task ? &(resumed_task->ompt_task_info.task_data) : NULL)); 610 } 611 } 612 #endif 613 614 template <bool ompt> 615 static void __kmpc_omp_task_begin_if0_template(ident_t *loc_ref, kmp_int32 gtid, 616 kmp_task_t *task, 617 void *frame_address, 618 void *return_address) { 619 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 620 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 621 622 KA_TRACE(10, ("__kmpc_omp_task_begin_if0(enter): T#%d loc=%p task=%p " 623 "current_task=%p\n", 624 gtid, loc_ref, taskdata, current_task)); 625 626 if (UNLIKELY(taskdata->td_flags.tiedness == TASK_UNTIED)) { 627 // untied task needs to increment counter so that the task structure is not 628 // freed prematurely 629 kmp_int32 counter = 1 + KMP_ATOMIC_INC(&taskdata->td_untied_count); 630 KMP_DEBUG_USE_VAR(counter); 631 KA_TRACE(20, ("__kmpc_omp_task_begin_if0: T#%d untied_count (%d) " 632 "incremented for task %p\n", 633 gtid, counter, taskdata)); 634 } 635 636 taskdata->td_flags.task_serial = 637 1; // Execute this task immediately, not deferred. 638 __kmp_task_start(gtid, task, current_task); 639 640 #if OMPT_SUPPORT 641 if (ompt) { 642 if (current_task->ompt_task_info.frame.enter_frame.ptr == NULL) { 643 current_task->ompt_task_info.frame.enter_frame.ptr = 644 taskdata->ompt_task_info.frame.exit_frame.ptr = frame_address; 645 current_task->ompt_task_info.frame.enter_frame_flags = 646 taskdata->ompt_task_info.frame.exit_frame_flags = 647 ompt_frame_application | ompt_frame_framepointer; 648 } 649 if (ompt_enabled.ompt_callback_task_create) { 650 ompt_task_info_t *parent_info = &(current_task->ompt_task_info); 651 ompt_callbacks.ompt_callback(ompt_callback_task_create)( 652 &(parent_info->task_data), &(parent_info->frame), 653 &(taskdata->ompt_task_info.task_data), 654 ompt_task_explicit | TASK_TYPE_DETAILS_FORMAT(taskdata), 0, 655 return_address); 656 } 657 __ompt_task_start(task, current_task, gtid); 658 } 659 #endif // OMPT_SUPPORT 660 661 KA_TRACE(10, ("__kmpc_omp_task_begin_if0(exit): T#%d loc=%p task=%p,\n", gtid, 662 loc_ref, taskdata)); 663 } 664 665 #if OMPT_SUPPORT 666 OMPT_NOINLINE 667 static void __kmpc_omp_task_begin_if0_ompt(ident_t *loc_ref, kmp_int32 gtid, 668 kmp_task_t *task, 669 void *frame_address, 670 void *return_address) { 671 __kmpc_omp_task_begin_if0_template<true>(loc_ref, gtid, task, frame_address, 672 return_address); 673 } 674 #endif // OMPT_SUPPORT 675 676 // __kmpc_omp_task_begin_if0: report that a given serialized task has started 677 // execution 678 // 679 // loc_ref: source location information; points to beginning of task block. 680 // gtid: global thread number. 681 // task: task thunk for the started task. 682 void __kmpc_omp_task_begin_if0(ident_t *loc_ref, kmp_int32 gtid, 683 kmp_task_t *task) { 684 #if OMPT_SUPPORT 685 if (UNLIKELY(ompt_enabled.enabled)) { 686 OMPT_STORE_RETURN_ADDRESS(gtid); 687 __kmpc_omp_task_begin_if0_ompt(loc_ref, gtid, task, 688 OMPT_GET_FRAME_ADDRESS(1), 689 OMPT_LOAD_RETURN_ADDRESS(gtid)); 690 return; 691 } 692 #endif 693 __kmpc_omp_task_begin_if0_template<false>(loc_ref, gtid, task, NULL, NULL); 694 } 695 696 #ifdef TASK_UNUSED 697 // __kmpc_omp_task_begin: report that a given task has started execution 698 // NEVER GENERATED BY COMPILER, DEPRECATED!!! 699 void __kmpc_omp_task_begin(ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *task) { 700 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 701 702 KA_TRACE( 703 10, 704 ("__kmpc_omp_task_begin(enter): T#%d loc=%p task=%p current_task=%p\n", 705 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task), current_task)); 706 707 __kmp_task_start(gtid, task, current_task); 708 709 KA_TRACE(10, ("__kmpc_omp_task_begin(exit): T#%d loc=%p task=%p,\n", gtid, 710 loc_ref, KMP_TASK_TO_TASKDATA(task))); 711 return; 712 } 713 #endif // TASK_UNUSED 714 715 // __kmp_free_task: free the current task space and the space for shareds 716 // 717 // gtid: Global thread ID of calling thread 718 // taskdata: task to free 719 // thread: thread data structure of caller 720 static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata, 721 kmp_info_t *thread) { 722 KA_TRACE(30, ("__kmp_free_task: T#%d freeing data from task %p\n", gtid, 723 taskdata)); 724 725 // Check to make sure all flags and counters have the correct values 726 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 727 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0); 728 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 1); 729 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 730 KMP_DEBUG_ASSERT(taskdata->td_allocated_child_tasks == 0 || 731 taskdata->td_flags.task_serial == 1); 732 KMP_DEBUG_ASSERT(taskdata->td_incomplete_child_tasks == 0); 733 734 taskdata->td_flags.freed = 1; 735 // deallocate the taskdata and shared variable blocks associated with this task 736 #if USE_FAST_MEMORY 737 __kmp_fast_free(thread, taskdata); 738 #else /* ! USE_FAST_MEMORY */ 739 __kmp_thread_free(thread, taskdata); 740 #endif 741 KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n", gtid, taskdata)); 742 } 743 744 // __kmp_free_task_and_ancestors: free the current task and ancestors without 745 // children 746 // 747 // gtid: Global thread ID of calling thread 748 // taskdata: task to free 749 // thread: thread data structure of caller 750 static void __kmp_free_task_and_ancestors(kmp_int32 gtid, 751 kmp_taskdata_t *taskdata, 752 kmp_info_t *thread) { 753 // Proxy tasks must always be allowed to free their parents 754 // because they can be run in background even in serial mode. 755 kmp_int32 team_serial = 756 (taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) && 757 !taskdata->td_flags.proxy; 758 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 759 760 kmp_int32 children = KMP_ATOMIC_DEC(&taskdata->td_allocated_child_tasks) - 1; 761 KMP_DEBUG_ASSERT(children >= 0); 762 763 // Now, go up the ancestor tree to see if any ancestors can now be freed. 764 while (children == 0) { 765 kmp_taskdata_t *parent_taskdata = taskdata->td_parent; 766 767 KA_TRACE(20, ("__kmp_free_task_and_ancestors(enter): T#%d task %p complete " 768 "and freeing itself\n", 769 gtid, taskdata)); 770 771 // --- Deallocate my ancestor task --- 772 __kmp_free_task(gtid, taskdata, thread); 773 774 taskdata = parent_taskdata; 775 776 if (team_serial) 777 return; 778 // Stop checking ancestors at implicit task instead of walking up ancestor 779 // tree to avoid premature deallocation of ancestors. 780 if (taskdata->td_flags.tasktype == TASK_IMPLICIT) { 781 if (taskdata->td_dephash) { // do we need to cleanup dephash? 782 int children = KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks); 783 kmp_tasking_flags_t flags_old = taskdata->td_flags; 784 if (children == 0 && flags_old.complete == 1) { 785 kmp_tasking_flags_t flags_new = flags_old; 786 flags_new.complete = 0; 787 if (KMP_COMPARE_AND_STORE_ACQ32( 788 RCAST(kmp_int32 *, &taskdata->td_flags), 789 *RCAST(kmp_int32 *, &flags_old), 790 *RCAST(kmp_int32 *, &flags_new))) { 791 KA_TRACE(100, ("__kmp_free_task_and_ancestors: T#%d cleans " 792 "dephash of implicit task %p\n", 793 gtid, taskdata)); 794 // cleanup dephash of finished implicit task 795 __kmp_dephash_free_entries(thread, taskdata->td_dephash); 796 } 797 } 798 } 799 return; 800 } 801 // Predecrement simulated by "- 1" calculation 802 children = KMP_ATOMIC_DEC(&taskdata->td_allocated_child_tasks) - 1; 803 KMP_DEBUG_ASSERT(children >= 0); 804 } 805 806 KA_TRACE( 807 20, ("__kmp_free_task_and_ancestors(exit): T#%d task %p has %d children; " 808 "not freeing it yet\n", 809 gtid, taskdata, children)); 810 } 811 812 // __kmp_task_finish: bookkeeping to do when a task finishes execution 813 // 814 // gtid: global thread ID for calling thread 815 // task: task to be finished 816 // resumed_task: task to be resumed. (may be NULL if task is serialized) 817 // 818 // template<ompt>: effectively ompt_enabled.enabled!=0 819 // the version with ompt=false is inlined, allowing to optimize away all ompt 820 // code in this case 821 template <bool ompt> 822 static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task, 823 kmp_taskdata_t *resumed_task) { 824 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 825 kmp_info_t *thread = __kmp_threads[gtid]; 826 kmp_task_team_t *task_team = 827 thread->th.th_task_team; // might be NULL for serial teams... 828 kmp_int32 children = 0; 829 830 KA_TRACE(10, ("__kmp_task_finish(enter): T#%d finishing task %p and resuming " 831 "task %p\n", 832 gtid, taskdata, resumed_task)); 833 834 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 835 836 // Pop task from stack if tied 837 #ifdef BUILD_TIED_TASK_STACK 838 if (taskdata->td_flags.tiedness == TASK_TIED) { 839 __kmp_pop_task_stack(gtid, thread, taskdata); 840 } 841 #endif /* BUILD_TIED_TASK_STACK */ 842 843 if (UNLIKELY(taskdata->td_flags.tiedness == TASK_UNTIED)) { 844 // untied task needs to check the counter so that the task structure is not 845 // freed prematurely 846 kmp_int32 counter = KMP_ATOMIC_DEC(&taskdata->td_untied_count) - 1; 847 KA_TRACE( 848 20, 849 ("__kmp_task_finish: T#%d untied_count (%d) decremented for task %p\n", 850 gtid, counter, taskdata)); 851 if (counter > 0) { 852 // untied task is not done, to be continued possibly by other thread, do 853 // not free it now 854 if (resumed_task == NULL) { 855 KMP_DEBUG_ASSERT(taskdata->td_flags.task_serial); 856 resumed_task = taskdata->td_parent; // In a serialized task, the resumed 857 // task is the parent 858 } 859 thread->th.th_current_task = resumed_task; // restore current_task 860 resumed_task->td_flags.executing = 1; // resume previous task 861 KA_TRACE(10, ("__kmp_task_finish(exit): T#%d partially done task %p, " 862 "resuming task %p\n", 863 gtid, taskdata, resumed_task)); 864 return; 865 } 866 } 867 868 // bookkeeping for resuming task: 869 // GEH - note tasking_ser => task_serial 870 KMP_DEBUG_ASSERT( 871 (taskdata->td_flags.tasking_ser || taskdata->td_flags.task_serial) == 872 taskdata->td_flags.task_serial); 873 if (taskdata->td_flags.task_serial) { 874 if (resumed_task == NULL) { 875 resumed_task = taskdata->td_parent; // In a serialized task, the resumed 876 // task is the parent 877 } 878 } else { 879 KMP_DEBUG_ASSERT(resumed_task != 880 NULL); // verify that resumed task is passed as argument 881 } 882 883 /* If the tasks' destructor thunk flag has been set, we need to invoke the 884 destructor thunk that has been generated by the compiler. The code is 885 placed here, since at this point other tasks might have been released 886 hence overlapping the destructor invocations with some other work in the 887 released tasks. The OpenMP spec is not specific on when the destructors 888 are invoked, so we should be free to choose. */ 889 if (UNLIKELY(taskdata->td_flags.destructors_thunk)) { 890 kmp_routine_entry_t destr_thunk = task->data1.destructors; 891 KMP_ASSERT(destr_thunk); 892 destr_thunk(gtid, task); 893 } 894 895 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0); 896 KMP_DEBUG_ASSERT(taskdata->td_flags.started == 1); 897 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 898 899 bool detach = false; 900 if (UNLIKELY(taskdata->td_flags.detachable == TASK_DETACHABLE)) { 901 if (taskdata->td_allow_completion_event.type == 902 KMP_EVENT_ALLOW_COMPLETION) { 903 // event hasn't been fulfilled yet. Try to detach task. 904 __kmp_acquire_tas_lock(&taskdata->td_allow_completion_event.lock, gtid); 905 if (taskdata->td_allow_completion_event.type == 906 KMP_EVENT_ALLOW_COMPLETION) { 907 // task finished execution 908 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 1); 909 taskdata->td_flags.executing = 0; // suspend the finishing task 910 911 #if OMPT_SUPPORT 912 // For a detached task, which is not completed, we switch back 913 // the omp_fulfill_event signals completion 914 // locking is necessary to avoid a race with ompt_task_late_fulfill 915 if (ompt) 916 __ompt_task_finish(task, resumed_task, ompt_task_detach); 917 #endif 918 919 // no access to taskdata after this point! 920 // __kmp_fulfill_event might free taskdata at any time from now 921 922 taskdata->td_flags.proxy = TASK_PROXY; // proxify! 923 detach = true; 924 } 925 __kmp_release_tas_lock(&taskdata->td_allow_completion_event.lock, gtid); 926 } 927 } 928 929 if (!detach) { 930 taskdata->td_flags.complete = 1; // mark the task as completed 931 932 #if OMPT_SUPPORT 933 // This is not a detached task, we are done here 934 if (ompt) 935 __ompt_task_finish(task, resumed_task, ompt_task_complete); 936 #endif 937 938 // Only need to keep track of count if team parallel and tasking not 939 // serialized, or task is detachable and event has already been fulfilled 940 if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) || 941 taskdata->td_flags.detachable == TASK_DETACHABLE || 942 taskdata->td_flags.hidden_helper) { 943 // Predecrement simulated by "- 1" calculation 944 children = 945 KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks) - 1; 946 KMP_DEBUG_ASSERT(children >= 0); 947 if (taskdata->td_taskgroup) 948 KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count); 949 __kmp_release_deps(gtid, taskdata); 950 } else if (task_team && task_team->tt.tt_found_proxy_tasks) { 951 // if we found proxy tasks there could exist a dependency chain 952 // with the proxy task as origin 953 __kmp_release_deps(gtid, taskdata); 954 } 955 // td_flags.executing must be marked as 0 after __kmp_release_deps has been 956 // called. Othertwise, if a task is executed immediately from the 957 // release_deps code, the flag will be reset to 1 again by this same 958 // function 959 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 1); 960 taskdata->td_flags.executing = 0; // suspend the finishing task 961 } 962 963 KA_TRACE( 964 20, ("__kmp_task_finish: T#%d finished task %p, %d incomplete children\n", 965 gtid, taskdata, children)); 966 967 // Free this task and then ancestor tasks if they have no children. 968 // Restore th_current_task first as suggested by John: 969 // johnmc: if an asynchronous inquiry peers into the runtime system 970 // it doesn't see the freed task as the current task. 971 thread->th.th_current_task = resumed_task; 972 if (!detach) 973 __kmp_free_task_and_ancestors(gtid, taskdata, thread); 974 975 // TODO: GEH - make sure root team implicit task is initialized properly. 976 // KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 ); 977 resumed_task->td_flags.executing = 1; // resume previous task 978 979 KA_TRACE( 980 10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n", 981 gtid, taskdata, resumed_task)); 982 983 return; 984 } 985 986 template <bool ompt> 987 static void __kmpc_omp_task_complete_if0_template(ident_t *loc_ref, 988 kmp_int32 gtid, 989 kmp_task_t *task) { 990 KA_TRACE(10, ("__kmpc_omp_task_complete_if0(enter): T#%d loc=%p task=%p\n", 991 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task))); 992 KMP_DEBUG_ASSERT(gtid >= 0); 993 // this routine will provide task to resume 994 __kmp_task_finish<ompt>(gtid, task, NULL); 995 996 KA_TRACE(10, ("__kmpc_omp_task_complete_if0(exit): T#%d loc=%p task=%p\n", 997 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task))); 998 999 #if OMPT_SUPPORT 1000 if (ompt) { 1001 ompt_frame_t *ompt_frame; 1002 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL); 1003 ompt_frame->enter_frame = ompt_data_none; 1004 ompt_frame->enter_frame_flags = 1005 ompt_frame_runtime | ompt_frame_framepointer; 1006 } 1007 #endif 1008 1009 return; 1010 } 1011 1012 #if OMPT_SUPPORT 1013 OMPT_NOINLINE 1014 void __kmpc_omp_task_complete_if0_ompt(ident_t *loc_ref, kmp_int32 gtid, 1015 kmp_task_t *task) { 1016 __kmpc_omp_task_complete_if0_template<true>(loc_ref, gtid, task); 1017 } 1018 #endif // OMPT_SUPPORT 1019 1020 // __kmpc_omp_task_complete_if0: report that a task has completed execution 1021 // 1022 // loc_ref: source location information; points to end of task block. 1023 // gtid: global thread number. 1024 // task: task thunk for the completed task. 1025 void __kmpc_omp_task_complete_if0(ident_t *loc_ref, kmp_int32 gtid, 1026 kmp_task_t *task) { 1027 #if OMPT_SUPPORT 1028 if (UNLIKELY(ompt_enabled.enabled)) { 1029 __kmpc_omp_task_complete_if0_ompt(loc_ref, gtid, task); 1030 return; 1031 } 1032 #endif 1033 __kmpc_omp_task_complete_if0_template<false>(loc_ref, gtid, task); 1034 } 1035 1036 #ifdef TASK_UNUSED 1037 // __kmpc_omp_task_complete: report that a task has completed execution 1038 // NEVER GENERATED BY COMPILER, DEPRECATED!!! 1039 void __kmpc_omp_task_complete(ident_t *loc_ref, kmp_int32 gtid, 1040 kmp_task_t *task) { 1041 KA_TRACE(10, ("__kmpc_omp_task_complete(enter): T#%d loc=%p task=%p\n", gtid, 1042 loc_ref, KMP_TASK_TO_TASKDATA(task))); 1043 1044 __kmp_task_finish<false>(gtid, task, 1045 NULL); // Not sure how to find task to resume 1046 1047 KA_TRACE(10, ("__kmpc_omp_task_complete(exit): T#%d loc=%p task=%p\n", gtid, 1048 loc_ref, KMP_TASK_TO_TASKDATA(task))); 1049 return; 1050 } 1051 #endif // TASK_UNUSED 1052 1053 // __kmp_init_implicit_task: Initialize the appropriate fields in the implicit 1054 // task for a given thread 1055 // 1056 // loc_ref: reference to source location of parallel region 1057 // this_thr: thread data structure corresponding to implicit task 1058 // team: team for this_thr 1059 // tid: thread id of given thread within team 1060 // set_curr_task: TRUE if need to push current task to thread 1061 // NOTE: Routine does not set up the implicit task ICVS. This is assumed to 1062 // have already been done elsewhere. 1063 // TODO: Get better loc_ref. Value passed in may be NULL 1064 void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr, 1065 kmp_team_t *team, int tid, int set_curr_task) { 1066 kmp_taskdata_t *task = &team->t.t_implicit_task_taskdata[tid]; 1067 1068 KF_TRACE( 1069 10, 1070 ("__kmp_init_implicit_task(enter): T#:%d team=%p task=%p, reinit=%s\n", 1071 tid, team, task, set_curr_task ? "TRUE" : "FALSE")); 1072 1073 task->td_task_id = KMP_GEN_TASK_ID(); 1074 task->td_team = team; 1075 // task->td_parent = NULL; // fix for CQ230101 (broken parent task info 1076 // in debugger) 1077 task->td_ident = loc_ref; 1078 task->td_taskwait_ident = NULL; 1079 task->td_taskwait_counter = 0; 1080 task->td_taskwait_thread = 0; 1081 1082 task->td_flags.tiedness = TASK_TIED; 1083 task->td_flags.tasktype = TASK_IMPLICIT; 1084 task->td_flags.proxy = TASK_FULL; 1085 1086 // All implicit tasks are executed immediately, not deferred 1087 task->td_flags.task_serial = 1; 1088 task->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec); 1089 task->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0; 1090 1091 task->td_flags.started = 1; 1092 task->td_flags.executing = 1; 1093 task->td_flags.complete = 0; 1094 task->td_flags.freed = 0; 1095 1096 task->td_depnode = NULL; 1097 task->td_last_tied = task; 1098 task->td_allow_completion_event.type = KMP_EVENT_UNINITIALIZED; 1099 1100 if (set_curr_task) { // only do this init first time thread is created 1101 KMP_ATOMIC_ST_REL(&task->td_incomplete_child_tasks, 0); 1102 // Not used: don't need to deallocate implicit task 1103 KMP_ATOMIC_ST_REL(&task->td_allocated_child_tasks, 0); 1104 task->td_taskgroup = NULL; // An implicit task does not have taskgroup 1105 task->td_dephash = NULL; 1106 __kmp_push_current_task_to_thread(this_thr, team, tid); 1107 } else { 1108 KMP_DEBUG_ASSERT(task->td_incomplete_child_tasks == 0); 1109 KMP_DEBUG_ASSERT(task->td_allocated_child_tasks == 0); 1110 } 1111 1112 #if OMPT_SUPPORT 1113 if (UNLIKELY(ompt_enabled.enabled)) 1114 __ompt_task_init(task, tid); 1115 #endif 1116 1117 KF_TRACE(10, ("__kmp_init_implicit_task(exit): T#:%d team=%p task=%p\n", tid, 1118 team, task)); 1119 } 1120 1121 // __kmp_finish_implicit_task: Release resources associated to implicit tasks 1122 // at the end of parallel regions. Some resources are kept for reuse in the next 1123 // parallel region. 1124 // 1125 // thread: thread data structure corresponding to implicit task 1126 void __kmp_finish_implicit_task(kmp_info_t *thread) { 1127 kmp_taskdata_t *task = thread->th.th_current_task; 1128 if (task->td_dephash) { 1129 int children; 1130 task->td_flags.complete = 1; 1131 children = KMP_ATOMIC_LD_ACQ(&task->td_incomplete_child_tasks); 1132 kmp_tasking_flags_t flags_old = task->td_flags; 1133 if (children == 0 && flags_old.complete == 1) { 1134 kmp_tasking_flags_t flags_new = flags_old; 1135 flags_new.complete = 0; 1136 if (KMP_COMPARE_AND_STORE_ACQ32(RCAST(kmp_int32 *, &task->td_flags), 1137 *RCAST(kmp_int32 *, &flags_old), 1138 *RCAST(kmp_int32 *, &flags_new))) { 1139 KA_TRACE(100, ("__kmp_finish_implicit_task: T#%d cleans " 1140 "dephash of implicit task %p\n", 1141 thread->th.th_info.ds.ds_gtid, task)); 1142 __kmp_dephash_free_entries(thread, task->td_dephash); 1143 } 1144 } 1145 } 1146 } 1147 1148 // __kmp_free_implicit_task: Release resources associated to implicit tasks 1149 // when these are destroyed regions 1150 // 1151 // thread: thread data structure corresponding to implicit task 1152 void __kmp_free_implicit_task(kmp_info_t *thread) { 1153 kmp_taskdata_t *task = thread->th.th_current_task; 1154 if (task && task->td_dephash) { 1155 __kmp_dephash_free(thread, task->td_dephash); 1156 task->td_dephash = NULL; 1157 } 1158 } 1159 1160 // Round up a size to a power of two specified by val: Used to insert padding 1161 // between structures co-allocated using a single malloc() call 1162 static size_t __kmp_round_up_to_val(size_t size, size_t val) { 1163 if (size & (val - 1)) { 1164 size &= ~(val - 1); 1165 if (size <= KMP_SIZE_T_MAX - val) { 1166 size += val; // Round up if there is no overflow. 1167 } 1168 } 1169 return size; 1170 } // __kmp_round_up_to_va 1171 1172 // __kmp_task_alloc: Allocate the taskdata and task data structures for a task 1173 // 1174 // loc_ref: source location information 1175 // gtid: global thread number. 1176 // flags: include tiedness & task type (explicit vs. implicit) of the ''new'' 1177 // task encountered. Converted from kmp_int32 to kmp_tasking_flags_t in routine. 1178 // sizeof_kmp_task_t: Size in bytes of kmp_task_t data structure including 1179 // private vars accessed in task. 1180 // sizeof_shareds: Size in bytes of array of pointers to shared vars accessed 1181 // in task. 1182 // task_entry: Pointer to task code entry point generated by compiler. 1183 // returns: a pointer to the allocated kmp_task_t structure (task). 1184 kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid, 1185 kmp_tasking_flags_t *flags, 1186 size_t sizeof_kmp_task_t, size_t sizeof_shareds, 1187 kmp_routine_entry_t task_entry) { 1188 kmp_task_t *task; 1189 kmp_taskdata_t *taskdata; 1190 kmp_info_t *thread = __kmp_threads[gtid]; 1191 kmp_info_t *encountering_thread = thread; 1192 kmp_team_t *team = thread->th.th_team; 1193 kmp_taskdata_t *parent_task = thread->th.th_current_task; 1194 size_t shareds_offset; 1195 1196 if (UNLIKELY(!TCR_4(__kmp_init_middle))) 1197 __kmp_middle_initialize(); 1198 1199 if (flags->hidden_helper) { 1200 if (__kmp_enable_hidden_helper) { 1201 if (!TCR_4(__kmp_init_hidden_helper)) 1202 __kmp_hidden_helper_initialize(); 1203 1204 // For a hidden helper task encountered by a regular thread, we will push 1205 // the task to the (gtid%__kmp_hidden_helper_threads_num)-th hidden helper 1206 // thread. 1207 if (!KMP_HIDDEN_HELPER_THREAD(gtid)) { 1208 thread = __kmp_threads[KMP_GTID_TO_SHADOW_GTID(gtid)]; 1209 // We don't change the parent-child relation for hidden helper task as 1210 // we need that to do per-task-region synchronization. 1211 } 1212 } else { 1213 // If the hidden helper task is not enabled, reset the flag to FALSE. 1214 flags->hidden_helper = FALSE; 1215 } 1216 } 1217 1218 KA_TRACE(10, ("__kmp_task_alloc(enter): T#%d loc=%p, flags=(0x%x) " 1219 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n", 1220 gtid, loc_ref, *((kmp_int32 *)flags), sizeof_kmp_task_t, 1221 sizeof_shareds, task_entry)); 1222 1223 KMP_DEBUG_ASSERT(parent_task); 1224 if (parent_task->td_flags.final) { 1225 if (flags->merged_if0) { 1226 } 1227 flags->final = 1; 1228 } 1229 1230 if (flags->tiedness == TASK_UNTIED && !team->t.t_serialized) { 1231 // Untied task encountered causes the TSC algorithm to check entire deque of 1232 // the victim thread. If no untied task encountered, then checking the head 1233 // of the deque should be enough. 1234 KMP_CHECK_UPDATE( 1235 encountering_thread->th.th_task_team->tt.tt_untied_task_encountered, 1); 1236 } 1237 1238 // Detachable tasks are not proxy tasks yet but could be in the future. Doing 1239 // the tasking setup 1240 // when that happens is too late. 1241 if (UNLIKELY(flags->proxy == TASK_PROXY || 1242 flags->detachable == TASK_DETACHABLE || flags->hidden_helper)) { 1243 if (flags->proxy == TASK_PROXY) { 1244 flags->tiedness = TASK_UNTIED; 1245 flags->merged_if0 = 1; 1246 } 1247 /* are we running in a sequential parallel or tskm_immediate_exec... we need 1248 tasking support enabled */ 1249 if ((encountering_thread->th.th_task_team) == NULL) { 1250 /* This should only happen if the team is serialized 1251 setup a task team and propagate it to the thread */ 1252 KMP_DEBUG_ASSERT(team->t.t_serialized); 1253 KA_TRACE(30, 1254 ("T#%d creating task team in __kmp_task_alloc for proxy task\n", 1255 gtid)); 1256 __kmp_task_team_setup( 1257 encountering_thread, team, 1258 1); // 1 indicates setup the current team regardless of nthreads 1259 encountering_thread->th.th_task_team = 1260 team->t.t_task_team[encountering_thread->th.th_task_state]; 1261 } 1262 kmp_task_team_t *task_team = encountering_thread->th.th_task_team; 1263 1264 /* tasking must be enabled now as the task might not be pushed */ 1265 if (!KMP_TASKING_ENABLED(task_team)) { 1266 KA_TRACE( 1267 30, 1268 ("T#%d enabling tasking in __kmp_task_alloc for proxy task\n", gtid)); 1269 __kmp_enable_tasking(task_team, encountering_thread); 1270 kmp_int32 tid = encountering_thread->th.th_info.ds.ds_tid; 1271 kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid]; 1272 // No lock needed since only owner can allocate 1273 if (thread_data->td.td_deque == NULL) { 1274 __kmp_alloc_task_deque(encountering_thread, thread_data); 1275 } 1276 } 1277 1278 if ((flags->proxy == TASK_PROXY || flags->detachable == TASK_DETACHABLE) && 1279 task_team->tt.tt_found_proxy_tasks == FALSE) 1280 TCW_4(task_team->tt.tt_found_proxy_tasks, TRUE); 1281 if (flags->hidden_helper && 1282 task_team->tt.tt_hidden_helper_task_encountered == FALSE) 1283 TCW_4(task_team->tt.tt_hidden_helper_task_encountered, TRUE); 1284 } 1285 1286 // Calculate shared structure offset including padding after kmp_task_t struct 1287 // to align pointers in shared struct 1288 shareds_offset = sizeof(kmp_taskdata_t) + sizeof_kmp_task_t; 1289 shareds_offset = __kmp_round_up_to_val(shareds_offset, sizeof(void *)); 1290 1291 // Allocate a kmp_taskdata_t block and a kmp_task_t block. 1292 KA_TRACE(30, ("__kmp_task_alloc: T#%d First malloc size: %ld\n", gtid, 1293 shareds_offset)); 1294 KA_TRACE(30, ("__kmp_task_alloc: T#%d Second malloc size: %ld\n", gtid, 1295 sizeof_shareds)); 1296 1297 // Avoid double allocation here by combining shareds with taskdata 1298 #if USE_FAST_MEMORY 1299 taskdata = (kmp_taskdata_t *)__kmp_fast_allocate( 1300 encountering_thread, shareds_offset + sizeof_shareds); 1301 #else /* ! USE_FAST_MEMORY */ 1302 taskdata = (kmp_taskdata_t *)__kmp_thread_malloc( 1303 encountering_thread, shareds_offset + sizeof_shareds); 1304 #endif /* USE_FAST_MEMORY */ 1305 1306 task = KMP_TASKDATA_TO_TASK(taskdata); 1307 1308 // Make sure task & taskdata are aligned appropriately 1309 #if KMP_ARCH_X86 || KMP_ARCH_PPC64 || !KMP_HAVE_QUAD 1310 KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(double) - 1)) == 0); 1311 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(double) - 1)) == 0); 1312 #else 1313 KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(_Quad) - 1)) == 0); 1314 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(_Quad) - 1)) == 0); 1315 #endif 1316 if (sizeof_shareds > 0) { 1317 // Avoid double allocation here by combining shareds with taskdata 1318 task->shareds = &((char *)taskdata)[shareds_offset]; 1319 // Make sure shareds struct is aligned to pointer size 1320 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) == 1321 0); 1322 } else { 1323 task->shareds = NULL; 1324 } 1325 task->routine = task_entry; 1326 task->part_id = 0; // AC: Always start with 0 part id 1327 1328 taskdata->td_task_id = KMP_GEN_TASK_ID(); 1329 taskdata->td_team = thread->th.th_team; 1330 taskdata->td_alloc_thread = encountering_thread; 1331 taskdata->td_parent = parent_task; 1332 taskdata->td_level = parent_task->td_level + 1; // increment nesting level 1333 KMP_ATOMIC_ST_RLX(&taskdata->td_untied_count, 0); 1334 taskdata->td_ident = loc_ref; 1335 taskdata->td_taskwait_ident = NULL; 1336 taskdata->td_taskwait_counter = 0; 1337 taskdata->td_taskwait_thread = 0; 1338 KMP_DEBUG_ASSERT(taskdata->td_parent != NULL); 1339 // avoid copying icvs for proxy tasks 1340 if (flags->proxy == TASK_FULL) 1341 copy_icvs(&taskdata->td_icvs, &taskdata->td_parent->td_icvs); 1342 1343 taskdata->td_flags.tiedness = flags->tiedness; 1344 taskdata->td_flags.final = flags->final; 1345 taskdata->td_flags.merged_if0 = flags->merged_if0; 1346 taskdata->td_flags.destructors_thunk = flags->destructors_thunk; 1347 taskdata->td_flags.proxy = flags->proxy; 1348 taskdata->td_flags.detachable = flags->detachable; 1349 taskdata->td_flags.hidden_helper = flags->hidden_helper; 1350 taskdata->encountering_gtid = gtid; 1351 taskdata->td_task_team = thread->th.th_task_team; 1352 taskdata->td_size_alloc = shareds_offset + sizeof_shareds; 1353 taskdata->td_flags.tasktype = TASK_EXPLICIT; 1354 1355 // GEH - TODO: fix this to copy parent task's value of tasking_ser flag 1356 taskdata->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec); 1357 1358 // GEH - TODO: fix this to copy parent task's value of team_serial flag 1359 taskdata->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0; 1360 1361 // GEH - Note we serialize the task if the team is serialized to make sure 1362 // implicit parallel region tasks are not left until program termination to 1363 // execute. Also, it helps locality to execute immediately. 1364 1365 taskdata->td_flags.task_serial = 1366 (parent_task->td_flags.final || taskdata->td_flags.team_serial || 1367 taskdata->td_flags.tasking_ser || flags->merged_if0); 1368 1369 taskdata->td_flags.started = 0; 1370 taskdata->td_flags.executing = 0; 1371 taskdata->td_flags.complete = 0; 1372 taskdata->td_flags.freed = 0; 1373 1374 taskdata->td_flags.native = flags->native; 1375 1376 KMP_ATOMIC_ST_RLX(&taskdata->td_incomplete_child_tasks, 0); 1377 // start at one because counts current task and children 1378 KMP_ATOMIC_ST_RLX(&taskdata->td_allocated_child_tasks, 1); 1379 taskdata->td_taskgroup = 1380 parent_task->td_taskgroup; // task inherits taskgroup from the parent task 1381 taskdata->td_dephash = NULL; 1382 taskdata->td_depnode = NULL; 1383 if (flags->tiedness == TASK_UNTIED) 1384 taskdata->td_last_tied = NULL; // will be set when the task is scheduled 1385 else 1386 taskdata->td_last_tied = taskdata; 1387 taskdata->td_allow_completion_event.type = KMP_EVENT_UNINITIALIZED; 1388 #if OMPT_SUPPORT 1389 if (UNLIKELY(ompt_enabled.enabled)) 1390 __ompt_task_init(taskdata, gtid); 1391 #endif 1392 // Only need to keep track of child task counts if team parallel and tasking 1393 // not serialized or if it is a proxy or detachable or hidden helper task 1394 if (flags->proxy == TASK_PROXY || flags->detachable == TASK_DETACHABLE || 1395 flags->hidden_helper || 1396 !(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) { 1397 KMP_ATOMIC_INC(&parent_task->td_incomplete_child_tasks); 1398 if (parent_task->td_taskgroup) 1399 KMP_ATOMIC_INC(&parent_task->td_taskgroup->count); 1400 // Only need to keep track of allocated child tasks for explicit tasks since 1401 // implicit not deallocated 1402 if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT) { 1403 KMP_ATOMIC_INC(&taskdata->td_parent->td_allocated_child_tasks); 1404 } 1405 } 1406 1407 if (flags->hidden_helper) { 1408 taskdata->td_flags.task_serial = FALSE; 1409 // Increment the number of hidden helper tasks to be executed 1410 KMP_ATOMIC_INC(&__kmp_unexecuted_hidden_helper_tasks); 1411 } 1412 1413 KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n", 1414 gtid, taskdata, taskdata->td_parent)); 1415 1416 return task; 1417 } 1418 1419 kmp_task_t *__kmpc_omp_task_alloc(ident_t *loc_ref, kmp_int32 gtid, 1420 kmp_int32 flags, size_t sizeof_kmp_task_t, 1421 size_t sizeof_shareds, 1422 kmp_routine_entry_t task_entry) { 1423 kmp_task_t *retval; 1424 kmp_tasking_flags_t *input_flags = (kmp_tasking_flags_t *)&flags; 1425 __kmp_assert_valid_gtid(gtid); 1426 input_flags->native = FALSE; 1427 // __kmp_task_alloc() sets up all other runtime flags 1428 KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s %s %s) " 1429 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n", 1430 gtid, loc_ref, input_flags->tiedness ? "tied " : "untied", 1431 input_flags->proxy ? "proxy" : "", 1432 input_flags->detachable ? "detachable" : "", sizeof_kmp_task_t, 1433 sizeof_shareds, task_entry)); 1434 1435 retval = __kmp_task_alloc(loc_ref, gtid, input_flags, sizeof_kmp_task_t, 1436 sizeof_shareds, task_entry); 1437 1438 KA_TRACE(20, ("__kmpc_omp_task_alloc(exit): T#%d retval %p\n", gtid, retval)); 1439 1440 return retval; 1441 } 1442 1443 kmp_task_t *__kmpc_omp_target_task_alloc(ident_t *loc_ref, kmp_int32 gtid, 1444 kmp_int32 flags, 1445 size_t sizeof_kmp_task_t, 1446 size_t sizeof_shareds, 1447 kmp_routine_entry_t task_entry, 1448 kmp_int64 device_id) { 1449 if (__kmp_enable_hidden_helper) { 1450 auto &input_flags = reinterpret_cast<kmp_tasking_flags_t &>(flags); 1451 input_flags.hidden_helper = TRUE; 1452 } 1453 1454 return __kmpc_omp_task_alloc(loc_ref, gtid, flags, sizeof_kmp_task_t, 1455 sizeof_shareds, task_entry); 1456 } 1457 1458 /*! 1459 @ingroup TASKING 1460 @param loc_ref location of the original task directive 1461 @param gtid Global Thread ID of encountering thread 1462 @param new_task task thunk allocated by __kmpc_omp_task_alloc() for the ''new 1463 task'' 1464 @param naffins Number of affinity items 1465 @param affin_list List of affinity items 1466 @return Returns non-zero if registering affinity information was not successful. 1467 Returns 0 if registration was successful 1468 This entry registers the affinity information attached to a task with the task 1469 thunk structure kmp_taskdata_t. 1470 */ 1471 kmp_int32 1472 __kmpc_omp_reg_task_with_affinity(ident_t *loc_ref, kmp_int32 gtid, 1473 kmp_task_t *new_task, kmp_int32 naffins, 1474 kmp_task_affinity_info_t *affin_list) { 1475 return 0; 1476 } 1477 1478 // __kmp_invoke_task: invoke the specified task 1479 // 1480 // gtid: global thread ID of caller 1481 // task: the task to invoke 1482 // current_task: the task to resume after task invocation 1483 static void __kmp_invoke_task(kmp_int32 gtid, kmp_task_t *task, 1484 kmp_taskdata_t *current_task) { 1485 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 1486 kmp_info_t *thread; 1487 int discard = 0 /* false */; 1488 KA_TRACE( 1489 30, ("__kmp_invoke_task(enter): T#%d invoking task %p, current_task=%p\n", 1490 gtid, taskdata, current_task)); 1491 KMP_DEBUG_ASSERT(task); 1492 if (UNLIKELY(taskdata->td_flags.proxy == TASK_PROXY && 1493 taskdata->td_flags.complete == 1)) { 1494 // This is a proxy task that was already completed but it needs to run 1495 // its bottom-half finish 1496 KA_TRACE( 1497 30, 1498 ("__kmp_invoke_task: T#%d running bottom finish for proxy task %p\n", 1499 gtid, taskdata)); 1500 1501 __kmp_bottom_half_finish_proxy(gtid, task); 1502 1503 KA_TRACE(30, ("__kmp_invoke_task(exit): T#%d completed bottom finish for " 1504 "proxy task %p, resuming task %p\n", 1505 gtid, taskdata, current_task)); 1506 1507 return; 1508 } 1509 1510 #if OMPT_SUPPORT 1511 // For untied tasks, the first task executed only calls __kmpc_omp_task and 1512 // does not execute code. 1513 ompt_thread_info_t oldInfo; 1514 if (UNLIKELY(ompt_enabled.enabled)) { 1515 // Store the threads states and restore them after the task 1516 thread = __kmp_threads[gtid]; 1517 oldInfo = thread->th.ompt_thread_info; 1518 thread->th.ompt_thread_info.wait_id = 0; 1519 thread->th.ompt_thread_info.state = (thread->th.th_team_serialized) 1520 ? ompt_state_work_serial 1521 : ompt_state_work_parallel; 1522 taskdata->ompt_task_info.frame.exit_frame.ptr = OMPT_GET_FRAME_ADDRESS(0); 1523 } 1524 #endif 1525 1526 // Decreament the counter of hidden helper tasks to be executed 1527 if (taskdata->td_flags.hidden_helper) { 1528 // Hidden helper tasks can only be executed by hidden helper threads 1529 KMP_ASSERT(KMP_HIDDEN_HELPER_THREAD(gtid)); 1530 KMP_ATOMIC_DEC(&__kmp_unexecuted_hidden_helper_tasks); 1531 } 1532 1533 // Proxy tasks are not handled by the runtime 1534 if (taskdata->td_flags.proxy != TASK_PROXY) { 1535 __kmp_task_start(gtid, task, current_task); // OMPT only if not discarded 1536 } 1537 1538 // TODO: cancel tasks if the parallel region has also been cancelled 1539 // TODO: check if this sequence can be hoisted above __kmp_task_start 1540 // if cancellation has been enabled for this run ... 1541 if (UNLIKELY(__kmp_omp_cancellation)) { 1542 thread = __kmp_threads[gtid]; 1543 kmp_team_t *this_team = thread->th.th_team; 1544 kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup; 1545 if ((taskgroup && taskgroup->cancel_request) || 1546 (this_team->t.t_cancel_request == cancel_parallel)) { 1547 #if OMPT_SUPPORT && OMPT_OPTIONAL 1548 ompt_data_t *task_data; 1549 if (UNLIKELY(ompt_enabled.ompt_callback_cancel)) { 1550 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL, NULL); 1551 ompt_callbacks.ompt_callback(ompt_callback_cancel)( 1552 task_data, 1553 ((taskgroup && taskgroup->cancel_request) ? ompt_cancel_taskgroup 1554 : ompt_cancel_parallel) | 1555 ompt_cancel_discarded_task, 1556 NULL); 1557 } 1558 #endif 1559 KMP_COUNT_BLOCK(TASK_cancelled); 1560 // this task belongs to a task group and we need to cancel it 1561 discard = 1 /* true */; 1562 } 1563 } 1564 1565 // Invoke the task routine and pass in relevant data. 1566 // Thunks generated by gcc take a different argument list. 1567 if (!discard) { 1568 if (taskdata->td_flags.tiedness == TASK_UNTIED) { 1569 taskdata->td_last_tied = current_task->td_last_tied; 1570 KMP_DEBUG_ASSERT(taskdata->td_last_tied); 1571 } 1572 #if KMP_STATS_ENABLED 1573 KMP_COUNT_BLOCK(TASK_executed); 1574 switch (KMP_GET_THREAD_STATE()) { 1575 case FORK_JOIN_BARRIER: 1576 KMP_PUSH_PARTITIONED_TIMER(OMP_task_join_bar); 1577 break; 1578 case PLAIN_BARRIER: 1579 KMP_PUSH_PARTITIONED_TIMER(OMP_task_plain_bar); 1580 break; 1581 case TASKYIELD: 1582 KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskyield); 1583 break; 1584 case TASKWAIT: 1585 KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskwait); 1586 break; 1587 case TASKGROUP: 1588 KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskgroup); 1589 break; 1590 default: 1591 KMP_PUSH_PARTITIONED_TIMER(OMP_task_immediate); 1592 break; 1593 } 1594 #endif // KMP_STATS_ENABLED 1595 1596 // OMPT task begin 1597 #if OMPT_SUPPORT 1598 if (UNLIKELY(ompt_enabled.enabled)) 1599 __ompt_task_start(task, current_task, gtid); 1600 #endif 1601 1602 #if OMPD_SUPPORT 1603 if (ompd_state & OMPD_ENABLE_BP) 1604 ompd_bp_task_begin(); 1605 #endif 1606 1607 #if USE_ITT_BUILD && USE_ITT_NOTIFY 1608 kmp_uint64 cur_time; 1609 kmp_int32 kmp_itt_count_task = 1610 __kmp_forkjoin_frames_mode == 3 && !taskdata->td_flags.task_serial && 1611 current_task->td_flags.tasktype == TASK_IMPLICIT; 1612 if (kmp_itt_count_task) { 1613 thread = __kmp_threads[gtid]; 1614 // Time outer level explicit task on barrier for adjusting imbalance time 1615 if (thread->th.th_bar_arrive_time) 1616 cur_time = __itt_get_timestamp(); 1617 else 1618 kmp_itt_count_task = 0; // thread is not on a barrier - skip timing 1619 } 1620 KMP_FSYNC_ACQUIRED(taskdata); // acquired self (new task) 1621 #endif 1622 1623 #ifdef KMP_GOMP_COMPAT 1624 if (taskdata->td_flags.native) { 1625 ((void (*)(void *))(*(task->routine)))(task->shareds); 1626 } else 1627 #endif /* KMP_GOMP_COMPAT */ 1628 { 1629 (*(task->routine))(gtid, task); 1630 } 1631 KMP_POP_PARTITIONED_TIMER(); 1632 1633 #if USE_ITT_BUILD && USE_ITT_NOTIFY 1634 if (kmp_itt_count_task) { 1635 // Barrier imbalance - adjust arrive time with the task duration 1636 thread->th.th_bar_arrive_time += (__itt_get_timestamp() - cur_time); 1637 } 1638 KMP_FSYNC_CANCEL(taskdata); // destroy self (just executed) 1639 KMP_FSYNC_RELEASING(taskdata->td_parent); // releasing parent 1640 #endif 1641 } 1642 1643 #if OMPD_SUPPORT 1644 if (ompd_state & OMPD_ENABLE_BP) 1645 ompd_bp_task_end(); 1646 #endif 1647 1648 // Proxy tasks are not handled by the runtime 1649 if (taskdata->td_flags.proxy != TASK_PROXY) { 1650 #if OMPT_SUPPORT 1651 if (UNLIKELY(ompt_enabled.enabled)) { 1652 thread->th.ompt_thread_info = oldInfo; 1653 if (taskdata->td_flags.tiedness == TASK_TIED) { 1654 taskdata->ompt_task_info.frame.exit_frame = ompt_data_none; 1655 } 1656 __kmp_task_finish<true>(gtid, task, current_task); 1657 } else 1658 #endif 1659 __kmp_task_finish<false>(gtid, task, current_task); 1660 } 1661 1662 KA_TRACE( 1663 30, 1664 ("__kmp_invoke_task(exit): T#%d completed task %p, resuming task %p\n", 1665 gtid, taskdata, current_task)); 1666 return; 1667 } 1668 1669 // __kmpc_omp_task_parts: Schedule a thread-switchable task for execution 1670 // 1671 // loc_ref: location of original task pragma (ignored) 1672 // gtid: Global Thread ID of encountering thread 1673 // new_task: task thunk allocated by __kmp_omp_task_alloc() for the ''new task'' 1674 // Returns: 1675 // TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to 1676 // be resumed later. 1677 // TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be 1678 // resumed later. 1679 kmp_int32 __kmpc_omp_task_parts(ident_t *loc_ref, kmp_int32 gtid, 1680 kmp_task_t *new_task) { 1681 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task); 1682 1683 KA_TRACE(10, ("__kmpc_omp_task_parts(enter): T#%d loc=%p task=%p\n", gtid, 1684 loc_ref, new_taskdata)); 1685 1686 #if OMPT_SUPPORT 1687 kmp_taskdata_t *parent; 1688 if (UNLIKELY(ompt_enabled.enabled)) { 1689 parent = new_taskdata->td_parent; 1690 if (ompt_enabled.ompt_callback_task_create) { 1691 ompt_callbacks.ompt_callback(ompt_callback_task_create)( 1692 &(parent->ompt_task_info.task_data), &(parent->ompt_task_info.frame), 1693 &(new_taskdata->ompt_task_info.task_data), ompt_task_explicit, 0, 1694 OMPT_GET_RETURN_ADDRESS(0)); 1695 } 1696 } 1697 #endif 1698 1699 /* Should we execute the new task or queue it? For now, let's just always try 1700 to queue it. If the queue fills up, then we'll execute it. */ 1701 1702 if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer 1703 { // Execute this task immediately 1704 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 1705 new_taskdata->td_flags.task_serial = 1; 1706 __kmp_invoke_task(gtid, new_task, current_task); 1707 } 1708 1709 KA_TRACE( 1710 10, 1711 ("__kmpc_omp_task_parts(exit): T#%d returning TASK_CURRENT_NOT_QUEUED: " 1712 "loc=%p task=%p, return: TASK_CURRENT_NOT_QUEUED\n", 1713 gtid, loc_ref, new_taskdata)); 1714 1715 #if OMPT_SUPPORT 1716 if (UNLIKELY(ompt_enabled.enabled)) { 1717 parent->ompt_task_info.frame.enter_frame = ompt_data_none; 1718 } 1719 #endif 1720 return TASK_CURRENT_NOT_QUEUED; 1721 } 1722 1723 // __kmp_omp_task: Schedule a non-thread-switchable task for execution 1724 // 1725 // gtid: Global Thread ID of encountering thread 1726 // new_task:non-thread-switchable task thunk allocated by __kmp_omp_task_alloc() 1727 // serialize_immediate: if TRUE then if the task is executed immediately its 1728 // execution will be serialized 1729 // Returns: 1730 // TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to 1731 // be resumed later. 1732 // TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be 1733 // resumed later. 1734 kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task, 1735 bool serialize_immediate) { 1736 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task); 1737 1738 /* Should we execute the new task or queue it? For now, let's just always try 1739 to queue it. If the queue fills up, then we'll execute it. */ 1740 if (new_taskdata->td_flags.proxy == TASK_PROXY || 1741 __kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer 1742 { // Execute this task immediately 1743 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 1744 if (serialize_immediate) 1745 new_taskdata->td_flags.task_serial = 1; 1746 __kmp_invoke_task(gtid, new_task, current_task); 1747 } 1748 1749 return TASK_CURRENT_NOT_QUEUED; 1750 } 1751 1752 // __kmpc_omp_task: Wrapper around __kmp_omp_task to schedule a 1753 // non-thread-switchable task from the parent thread only! 1754 // 1755 // loc_ref: location of original task pragma (ignored) 1756 // gtid: Global Thread ID of encountering thread 1757 // new_task: non-thread-switchable task thunk allocated by 1758 // __kmp_omp_task_alloc() 1759 // Returns: 1760 // TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to 1761 // be resumed later. 1762 // TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be 1763 // resumed later. 1764 kmp_int32 __kmpc_omp_task(ident_t *loc_ref, kmp_int32 gtid, 1765 kmp_task_t *new_task) { 1766 kmp_int32 res; 1767 KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK); 1768 1769 #if KMP_DEBUG || OMPT_SUPPORT 1770 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task); 1771 #endif 1772 KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref, 1773 new_taskdata)); 1774 __kmp_assert_valid_gtid(gtid); 1775 1776 #if OMPT_SUPPORT 1777 kmp_taskdata_t *parent = NULL; 1778 if (UNLIKELY(ompt_enabled.enabled)) { 1779 if (!new_taskdata->td_flags.started) { 1780 OMPT_STORE_RETURN_ADDRESS(gtid); 1781 parent = new_taskdata->td_parent; 1782 if (!parent->ompt_task_info.frame.enter_frame.ptr) { 1783 parent->ompt_task_info.frame.enter_frame.ptr = 1784 OMPT_GET_FRAME_ADDRESS(0); 1785 } 1786 if (ompt_enabled.ompt_callback_task_create) { 1787 ompt_callbacks.ompt_callback(ompt_callback_task_create)( 1788 &(parent->ompt_task_info.task_data), 1789 &(parent->ompt_task_info.frame), 1790 &(new_taskdata->ompt_task_info.task_data), 1791 ompt_task_explicit | TASK_TYPE_DETAILS_FORMAT(new_taskdata), 0, 1792 OMPT_LOAD_RETURN_ADDRESS(gtid)); 1793 } 1794 } else { 1795 // We are scheduling the continuation of an UNTIED task. 1796 // Scheduling back to the parent task. 1797 __ompt_task_finish(new_task, 1798 new_taskdata->ompt_task_info.scheduling_parent, 1799 ompt_task_switch); 1800 new_taskdata->ompt_task_info.frame.exit_frame = ompt_data_none; 1801 } 1802 } 1803 #endif 1804 1805 res = __kmp_omp_task(gtid, new_task, true); 1806 1807 KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning " 1808 "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n", 1809 gtid, loc_ref, new_taskdata)); 1810 #if OMPT_SUPPORT 1811 if (UNLIKELY(ompt_enabled.enabled && parent != NULL)) { 1812 parent->ompt_task_info.frame.enter_frame = ompt_data_none; 1813 } 1814 #endif 1815 return res; 1816 } 1817 1818 // __kmp_omp_taskloop_task: Wrapper around __kmp_omp_task to schedule 1819 // a taskloop task with the correct OMPT return address 1820 // 1821 // loc_ref: location of original task pragma (ignored) 1822 // gtid: Global Thread ID of encountering thread 1823 // new_task: non-thread-switchable task thunk allocated by 1824 // __kmp_omp_task_alloc() 1825 // codeptr_ra: return address for OMPT callback 1826 // Returns: 1827 // TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to 1828 // be resumed later. 1829 // TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be 1830 // resumed later. 1831 kmp_int32 __kmp_omp_taskloop_task(ident_t *loc_ref, kmp_int32 gtid, 1832 kmp_task_t *new_task, void *codeptr_ra) { 1833 kmp_int32 res; 1834 KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK); 1835 1836 #if KMP_DEBUG || OMPT_SUPPORT 1837 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task); 1838 #endif 1839 KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref, 1840 new_taskdata)); 1841 1842 #if OMPT_SUPPORT 1843 kmp_taskdata_t *parent = NULL; 1844 if (UNLIKELY(ompt_enabled.enabled && !new_taskdata->td_flags.started)) { 1845 parent = new_taskdata->td_parent; 1846 if (!parent->ompt_task_info.frame.enter_frame.ptr) 1847 parent->ompt_task_info.frame.enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0); 1848 if (ompt_enabled.ompt_callback_task_create) { 1849 ompt_callbacks.ompt_callback(ompt_callback_task_create)( 1850 &(parent->ompt_task_info.task_data), &(parent->ompt_task_info.frame), 1851 &(new_taskdata->ompt_task_info.task_data), 1852 ompt_task_explicit | TASK_TYPE_DETAILS_FORMAT(new_taskdata), 0, 1853 codeptr_ra); 1854 } 1855 } 1856 #endif 1857 1858 res = __kmp_omp_task(gtid, new_task, true); 1859 1860 KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning " 1861 "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n", 1862 gtid, loc_ref, new_taskdata)); 1863 #if OMPT_SUPPORT 1864 if (UNLIKELY(ompt_enabled.enabled && parent != NULL)) { 1865 parent->ompt_task_info.frame.enter_frame = ompt_data_none; 1866 } 1867 #endif 1868 return res; 1869 } 1870 1871 template <bool ompt> 1872 static kmp_int32 __kmpc_omp_taskwait_template(ident_t *loc_ref, kmp_int32 gtid, 1873 void *frame_address, 1874 void *return_address) { 1875 kmp_taskdata_t *taskdata = nullptr; 1876 kmp_info_t *thread; 1877 int thread_finished = FALSE; 1878 KMP_SET_THREAD_STATE_BLOCK(TASKWAIT); 1879 1880 KA_TRACE(10, ("__kmpc_omp_taskwait(enter): T#%d loc=%p\n", gtid, loc_ref)); 1881 KMP_DEBUG_ASSERT(gtid >= 0); 1882 1883 if (__kmp_tasking_mode != tskm_immediate_exec) { 1884 thread = __kmp_threads[gtid]; 1885 taskdata = thread->th.th_current_task; 1886 1887 #if OMPT_SUPPORT && OMPT_OPTIONAL 1888 ompt_data_t *my_task_data; 1889 ompt_data_t *my_parallel_data; 1890 1891 if (ompt) { 1892 my_task_data = &(taskdata->ompt_task_info.task_data); 1893 my_parallel_data = OMPT_CUR_TEAM_DATA(thread); 1894 1895 taskdata->ompt_task_info.frame.enter_frame.ptr = frame_address; 1896 1897 if (ompt_enabled.ompt_callback_sync_region) { 1898 ompt_callbacks.ompt_callback(ompt_callback_sync_region)( 1899 ompt_sync_region_taskwait, ompt_scope_begin, my_parallel_data, 1900 my_task_data, return_address); 1901 } 1902 1903 if (ompt_enabled.ompt_callback_sync_region_wait) { 1904 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)( 1905 ompt_sync_region_taskwait, ompt_scope_begin, my_parallel_data, 1906 my_task_data, return_address); 1907 } 1908 } 1909 #endif // OMPT_SUPPORT && OMPT_OPTIONAL 1910 1911 // Debugger: The taskwait is active. Store location and thread encountered the 1912 // taskwait. 1913 #if USE_ITT_BUILD 1914 // Note: These values are used by ITT events as well. 1915 #endif /* USE_ITT_BUILD */ 1916 taskdata->td_taskwait_counter += 1; 1917 taskdata->td_taskwait_ident = loc_ref; 1918 taskdata->td_taskwait_thread = gtid + 1; 1919 1920 #if USE_ITT_BUILD 1921 void *itt_sync_obj = NULL; 1922 #if USE_ITT_NOTIFY 1923 KMP_ITT_TASKWAIT_STARTING(itt_sync_obj); 1924 #endif /* USE_ITT_NOTIFY */ 1925 #endif /* USE_ITT_BUILD */ 1926 1927 bool must_wait = 1928 !taskdata->td_flags.team_serial && !taskdata->td_flags.final; 1929 1930 must_wait = must_wait || (thread->th.th_task_team != NULL && 1931 thread->th.th_task_team->tt.tt_found_proxy_tasks); 1932 // If hidden helper thread is encountered, we must enable wait here. 1933 must_wait = 1934 must_wait || 1935 (__kmp_enable_hidden_helper && thread->th.th_task_team != NULL && 1936 thread->th.th_task_team->tt.tt_hidden_helper_task_encountered); 1937 1938 if (must_wait) { 1939 kmp_flag_32<false, false> flag( 1940 RCAST(std::atomic<kmp_uint32> *, 1941 &(taskdata->td_incomplete_child_tasks)), 1942 0U); 1943 while (KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) != 0) { 1944 flag.execute_tasks(thread, gtid, FALSE, 1945 &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), 1946 __kmp_task_stealing_constraint); 1947 } 1948 } 1949 #if USE_ITT_BUILD 1950 KMP_ITT_TASKWAIT_FINISHED(itt_sync_obj); 1951 KMP_FSYNC_ACQUIRED(taskdata); // acquire self - sync with children 1952 #endif /* USE_ITT_BUILD */ 1953 1954 // Debugger: The taskwait is completed. Location remains, but thread is 1955 // negated. 1956 taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread; 1957 1958 #if OMPT_SUPPORT && OMPT_OPTIONAL 1959 if (ompt) { 1960 if (ompt_enabled.ompt_callback_sync_region_wait) { 1961 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)( 1962 ompt_sync_region_taskwait, ompt_scope_end, my_parallel_data, 1963 my_task_data, return_address); 1964 } 1965 if (ompt_enabled.ompt_callback_sync_region) { 1966 ompt_callbacks.ompt_callback(ompt_callback_sync_region)( 1967 ompt_sync_region_taskwait, ompt_scope_end, my_parallel_data, 1968 my_task_data, return_address); 1969 } 1970 taskdata->ompt_task_info.frame.enter_frame = ompt_data_none; 1971 } 1972 #endif // OMPT_SUPPORT && OMPT_OPTIONAL 1973 1974 } 1975 1976 KA_TRACE(10, ("__kmpc_omp_taskwait(exit): T#%d task %p finished waiting, " 1977 "returning TASK_CURRENT_NOT_QUEUED\n", 1978 gtid, taskdata)); 1979 1980 return TASK_CURRENT_NOT_QUEUED; 1981 } 1982 1983 #if OMPT_SUPPORT && OMPT_OPTIONAL 1984 OMPT_NOINLINE 1985 static kmp_int32 __kmpc_omp_taskwait_ompt(ident_t *loc_ref, kmp_int32 gtid, 1986 void *frame_address, 1987 void *return_address) { 1988 return __kmpc_omp_taskwait_template<true>(loc_ref, gtid, frame_address, 1989 return_address); 1990 } 1991 #endif // OMPT_SUPPORT && OMPT_OPTIONAL 1992 1993 // __kmpc_omp_taskwait: Wait until all tasks generated by the current task are 1994 // complete 1995 kmp_int32 __kmpc_omp_taskwait(ident_t *loc_ref, kmp_int32 gtid) { 1996 #if OMPT_SUPPORT && OMPT_OPTIONAL 1997 if (UNLIKELY(ompt_enabled.enabled)) { 1998 OMPT_STORE_RETURN_ADDRESS(gtid); 1999 return __kmpc_omp_taskwait_ompt(loc_ref, gtid, OMPT_GET_FRAME_ADDRESS(0), 2000 OMPT_LOAD_RETURN_ADDRESS(gtid)); 2001 } 2002 #endif 2003 return __kmpc_omp_taskwait_template<false>(loc_ref, gtid, NULL, NULL); 2004 } 2005 2006 // __kmpc_omp_taskyield: switch to a different task 2007 kmp_int32 __kmpc_omp_taskyield(ident_t *loc_ref, kmp_int32 gtid, int end_part) { 2008 kmp_taskdata_t *taskdata = NULL; 2009 kmp_info_t *thread; 2010 int thread_finished = FALSE; 2011 2012 KMP_COUNT_BLOCK(OMP_TASKYIELD); 2013 KMP_SET_THREAD_STATE_BLOCK(TASKYIELD); 2014 2015 KA_TRACE(10, ("__kmpc_omp_taskyield(enter): T#%d loc=%p end_part = %d\n", 2016 gtid, loc_ref, end_part)); 2017 __kmp_assert_valid_gtid(gtid); 2018 2019 if (__kmp_tasking_mode != tskm_immediate_exec && __kmp_init_parallel) { 2020 thread = __kmp_threads[gtid]; 2021 taskdata = thread->th.th_current_task; 2022 // Should we model this as a task wait or not? 2023 // Debugger: The taskwait is active. Store location and thread encountered the 2024 // taskwait. 2025 #if USE_ITT_BUILD 2026 // Note: These values are used by ITT events as well. 2027 #endif /* USE_ITT_BUILD */ 2028 taskdata->td_taskwait_counter += 1; 2029 taskdata->td_taskwait_ident = loc_ref; 2030 taskdata->td_taskwait_thread = gtid + 1; 2031 2032 #if USE_ITT_BUILD 2033 void *itt_sync_obj = NULL; 2034 #if USE_ITT_NOTIFY 2035 KMP_ITT_TASKWAIT_STARTING(itt_sync_obj); 2036 #endif /* USE_ITT_NOTIFY */ 2037 #endif /* USE_ITT_BUILD */ 2038 if (!taskdata->td_flags.team_serial) { 2039 kmp_task_team_t *task_team = thread->th.th_task_team; 2040 if (task_team != NULL) { 2041 if (KMP_TASKING_ENABLED(task_team)) { 2042 #if OMPT_SUPPORT 2043 if (UNLIKELY(ompt_enabled.enabled)) 2044 thread->th.ompt_thread_info.ompt_task_yielded = 1; 2045 #endif 2046 __kmp_execute_tasks_32( 2047 thread, gtid, (kmp_flag_32<> *)NULL, FALSE, 2048 &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), 2049 __kmp_task_stealing_constraint); 2050 #if OMPT_SUPPORT 2051 if (UNLIKELY(ompt_enabled.enabled)) 2052 thread->th.ompt_thread_info.ompt_task_yielded = 0; 2053 #endif 2054 } 2055 } 2056 } 2057 #if USE_ITT_BUILD 2058 KMP_ITT_TASKWAIT_FINISHED(itt_sync_obj); 2059 #endif /* USE_ITT_BUILD */ 2060 2061 // Debugger: The taskwait is completed. Location remains, but thread is 2062 // negated. 2063 taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread; 2064 } 2065 2066 KA_TRACE(10, ("__kmpc_omp_taskyield(exit): T#%d task %p resuming, " 2067 "returning TASK_CURRENT_NOT_QUEUED\n", 2068 gtid, taskdata)); 2069 2070 return TASK_CURRENT_NOT_QUEUED; 2071 } 2072 2073 // Task Reduction implementation 2074 // 2075 // Note: initial implementation didn't take into account the possibility 2076 // to specify omp_orig for initializer of the UDR (user defined reduction). 2077 // Corrected implementation takes into account the omp_orig object. 2078 // Compiler is free to use old implementation if omp_orig is not specified. 2079 2080 /*! 2081 @ingroup BASIC_TYPES 2082 @{ 2083 */ 2084 2085 /*! 2086 Flags for special info per task reduction item. 2087 */ 2088 typedef struct kmp_taskred_flags { 2089 /*! 1 - use lazy alloc/init (e.g. big objects, #tasks < #threads) */ 2090 unsigned lazy_priv : 1; 2091 unsigned reserved31 : 31; 2092 } kmp_taskred_flags_t; 2093 2094 /*! 2095 Internal struct for reduction data item related info set up by compiler. 2096 */ 2097 typedef struct kmp_task_red_input { 2098 void *reduce_shar; /**< shared between tasks item to reduce into */ 2099 size_t reduce_size; /**< size of data item in bytes */ 2100 // three compiler-generated routines (init, fini are optional): 2101 void *reduce_init; /**< data initialization routine (single parameter) */ 2102 void *reduce_fini; /**< data finalization routine */ 2103 void *reduce_comb; /**< data combiner routine */ 2104 kmp_taskred_flags_t flags; /**< flags for additional info from compiler */ 2105 } kmp_task_red_input_t; 2106 2107 /*! 2108 Internal struct for reduction data item related info saved by the library. 2109 */ 2110 typedef struct kmp_taskred_data { 2111 void *reduce_shar; /**< shared between tasks item to reduce into */ 2112 size_t reduce_size; /**< size of data item */ 2113 kmp_taskred_flags_t flags; /**< flags for additional info from compiler */ 2114 void *reduce_priv; /**< array of thread specific items */ 2115 void *reduce_pend; /**< end of private data for faster comparison op */ 2116 // three compiler-generated routines (init, fini are optional): 2117 void *reduce_comb; /**< data combiner routine */ 2118 void *reduce_init; /**< data initialization routine (two parameters) */ 2119 void *reduce_fini; /**< data finalization routine */ 2120 void *reduce_orig; /**< original item (can be used in UDR initializer) */ 2121 } kmp_taskred_data_t; 2122 2123 /*! 2124 Internal struct for reduction data item related info set up by compiler. 2125 2126 New interface: added reduce_orig field to provide omp_orig for UDR initializer. 2127 */ 2128 typedef struct kmp_taskred_input { 2129 void *reduce_shar; /**< shared between tasks item to reduce into */ 2130 void *reduce_orig; /**< original reduction item used for initialization */ 2131 size_t reduce_size; /**< size of data item */ 2132 // three compiler-generated routines (init, fini are optional): 2133 void *reduce_init; /**< data initialization routine (two parameters) */ 2134 void *reduce_fini; /**< data finalization routine */ 2135 void *reduce_comb; /**< data combiner routine */ 2136 kmp_taskred_flags_t flags; /**< flags for additional info from compiler */ 2137 } kmp_taskred_input_t; 2138 /*! 2139 @} 2140 */ 2141 2142 template <typename T> void __kmp_assign_orig(kmp_taskred_data_t &item, T &src); 2143 template <> 2144 void __kmp_assign_orig<kmp_task_red_input_t>(kmp_taskred_data_t &item, 2145 kmp_task_red_input_t &src) { 2146 item.reduce_orig = NULL; 2147 } 2148 template <> 2149 void __kmp_assign_orig<kmp_taskred_input_t>(kmp_taskred_data_t &item, 2150 kmp_taskred_input_t &src) { 2151 if (src.reduce_orig != NULL) { 2152 item.reduce_orig = src.reduce_orig; 2153 } else { 2154 item.reduce_orig = src.reduce_shar; 2155 } // non-NULL reduce_orig means new interface used 2156 } 2157 2158 template <typename T> void __kmp_call_init(kmp_taskred_data_t &item, size_t j); 2159 template <> 2160 void __kmp_call_init<kmp_task_red_input_t>(kmp_taskred_data_t &item, 2161 size_t offset) { 2162 ((void (*)(void *))item.reduce_init)((char *)(item.reduce_priv) + offset); 2163 } 2164 template <> 2165 void __kmp_call_init<kmp_taskred_input_t>(kmp_taskred_data_t &item, 2166 size_t offset) { 2167 ((void (*)(void *, void *))item.reduce_init)( 2168 (char *)(item.reduce_priv) + offset, item.reduce_orig); 2169 } 2170 2171 template <typename T> 2172 void *__kmp_task_reduction_init(int gtid, int num, T *data) { 2173 __kmp_assert_valid_gtid(gtid); 2174 kmp_info_t *thread = __kmp_threads[gtid]; 2175 kmp_taskgroup_t *tg = thread->th.th_current_task->td_taskgroup; 2176 kmp_uint32 nth = thread->th.th_team_nproc; 2177 kmp_taskred_data_t *arr; 2178 2179 // check input data just in case 2180 KMP_ASSERT(tg != NULL); 2181 KMP_ASSERT(data != NULL); 2182 KMP_ASSERT(num > 0); 2183 if (nth == 1) { 2184 KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, tg %p, exiting nth=1\n", 2185 gtid, tg)); 2186 return (void *)tg; 2187 } 2188 KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, taskgroup %p, #items %d\n", 2189 gtid, tg, num)); 2190 arr = (kmp_taskred_data_t *)__kmp_thread_malloc( 2191 thread, num * sizeof(kmp_taskred_data_t)); 2192 for (int i = 0; i < num; ++i) { 2193 size_t size = data[i].reduce_size - 1; 2194 // round the size up to cache line per thread-specific item 2195 size += CACHE_LINE - size % CACHE_LINE; 2196 KMP_ASSERT(data[i].reduce_comb != NULL); // combiner is mandatory 2197 arr[i].reduce_shar = data[i].reduce_shar; 2198 arr[i].reduce_size = size; 2199 arr[i].flags = data[i].flags; 2200 arr[i].reduce_comb = data[i].reduce_comb; 2201 arr[i].reduce_init = data[i].reduce_init; 2202 arr[i].reduce_fini = data[i].reduce_fini; 2203 __kmp_assign_orig<T>(arr[i], data[i]); 2204 if (!arr[i].flags.lazy_priv) { 2205 // allocate cache-line aligned block and fill it with zeros 2206 arr[i].reduce_priv = __kmp_allocate(nth * size); 2207 arr[i].reduce_pend = (char *)(arr[i].reduce_priv) + nth * size; 2208 if (arr[i].reduce_init != NULL) { 2209 // initialize all thread-specific items 2210 for (size_t j = 0; j < nth; ++j) { 2211 __kmp_call_init<T>(arr[i], j * size); 2212 } 2213 } 2214 } else { 2215 // only allocate space for pointers now, 2216 // objects will be lazily allocated/initialized if/when requested 2217 // note that __kmp_allocate zeroes the allocated memory 2218 arr[i].reduce_priv = __kmp_allocate(nth * sizeof(void *)); 2219 } 2220 } 2221 tg->reduce_data = (void *)arr; 2222 tg->reduce_num_data = num; 2223 return (void *)tg; 2224 } 2225 2226 /*! 2227 @ingroup TASKING 2228 @param gtid Global thread ID 2229 @param num Number of data items to reduce 2230 @param data Array of data for reduction 2231 @return The taskgroup identifier 2232 2233 Initialize task reduction for the taskgroup. 2234 2235 Note: this entry supposes the optional compiler-generated initializer routine 2236 has single parameter - pointer to object to be initialized. That means 2237 the reduction either does not use omp_orig object, or the omp_orig is accessible 2238 without help of the runtime library. 2239 */ 2240 void *__kmpc_task_reduction_init(int gtid, int num, void *data) { 2241 return __kmp_task_reduction_init(gtid, num, (kmp_task_red_input_t *)data); 2242 } 2243 2244 /*! 2245 @ingroup TASKING 2246 @param gtid Global thread ID 2247 @param num Number of data items to reduce 2248 @param data Array of data for reduction 2249 @return The taskgroup identifier 2250 2251 Initialize task reduction for the taskgroup. 2252 2253 Note: this entry supposes the optional compiler-generated initializer routine 2254 has two parameters, pointer to object to be initialized and pointer to omp_orig 2255 */ 2256 void *__kmpc_taskred_init(int gtid, int num, void *data) { 2257 return __kmp_task_reduction_init(gtid, num, (kmp_taskred_input_t *)data); 2258 } 2259 2260 // Copy task reduction data (except for shared pointers). 2261 template <typename T> 2262 void __kmp_task_reduction_init_copy(kmp_info_t *thr, int num, T *data, 2263 kmp_taskgroup_t *tg, void *reduce_data) { 2264 kmp_taskred_data_t *arr; 2265 KA_TRACE(20, ("__kmp_task_reduction_init_copy: Th %p, init taskgroup %p," 2266 " from data %p\n", 2267 thr, tg, reduce_data)); 2268 arr = (kmp_taskred_data_t *)__kmp_thread_malloc( 2269 thr, num * sizeof(kmp_taskred_data_t)); 2270 // threads will share private copies, thunk routines, sizes, flags, etc.: 2271 KMP_MEMCPY(arr, reduce_data, num * sizeof(kmp_taskred_data_t)); 2272 for (int i = 0; i < num; ++i) { 2273 arr[i].reduce_shar = data[i].reduce_shar; // init unique shared pointers 2274 } 2275 tg->reduce_data = (void *)arr; 2276 tg->reduce_num_data = num; 2277 } 2278 2279 /*! 2280 @ingroup TASKING 2281 @param gtid Global thread ID 2282 @param tskgrp The taskgroup ID (optional) 2283 @param data Shared location of the item 2284 @return The pointer to per-thread data 2285 2286 Get thread-specific location of data item 2287 */ 2288 void *__kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data) { 2289 __kmp_assert_valid_gtid(gtid); 2290 kmp_info_t *thread = __kmp_threads[gtid]; 2291 kmp_int32 nth = thread->th.th_team_nproc; 2292 if (nth == 1) 2293 return data; // nothing to do 2294 2295 kmp_taskgroup_t *tg = (kmp_taskgroup_t *)tskgrp; 2296 if (tg == NULL) 2297 tg = thread->th.th_current_task->td_taskgroup; 2298 KMP_ASSERT(tg != NULL); 2299 kmp_taskred_data_t *arr = (kmp_taskred_data_t *)(tg->reduce_data); 2300 kmp_int32 num = tg->reduce_num_data; 2301 kmp_int32 tid = thread->th.th_info.ds.ds_tid; 2302 2303 KMP_ASSERT(data != NULL); 2304 while (tg != NULL) { 2305 for (int i = 0; i < num; ++i) { 2306 if (!arr[i].flags.lazy_priv) { 2307 if (data == arr[i].reduce_shar || 2308 (data >= arr[i].reduce_priv && data < arr[i].reduce_pend)) 2309 return (char *)(arr[i].reduce_priv) + tid * arr[i].reduce_size; 2310 } else { 2311 // check shared location first 2312 void **p_priv = (void **)(arr[i].reduce_priv); 2313 if (data == arr[i].reduce_shar) 2314 goto found; 2315 // check if we get some thread specific location as parameter 2316 for (int j = 0; j < nth; ++j) 2317 if (data == p_priv[j]) 2318 goto found; 2319 continue; // not found, continue search 2320 found: 2321 if (p_priv[tid] == NULL) { 2322 // allocate thread specific object lazily 2323 p_priv[tid] = __kmp_allocate(arr[i].reduce_size); 2324 if (arr[i].reduce_init != NULL) { 2325 if (arr[i].reduce_orig != NULL) { // new interface 2326 ((void (*)(void *, void *))arr[i].reduce_init)( 2327 p_priv[tid], arr[i].reduce_orig); 2328 } else { // old interface (single parameter) 2329 ((void (*)(void *))arr[i].reduce_init)(p_priv[tid]); 2330 } 2331 } 2332 } 2333 return p_priv[tid]; 2334 } 2335 } 2336 tg = tg->parent; 2337 arr = (kmp_taskred_data_t *)(tg->reduce_data); 2338 num = tg->reduce_num_data; 2339 } 2340 KMP_ASSERT2(0, "Unknown task reduction item"); 2341 return NULL; // ERROR, this line never executed 2342 } 2343 2344 // Finalize task reduction. 2345 // Called from __kmpc_end_taskgroup() 2346 static void __kmp_task_reduction_fini(kmp_info_t *th, kmp_taskgroup_t *tg) { 2347 kmp_int32 nth = th->th.th_team_nproc; 2348 KMP_DEBUG_ASSERT(nth > 1); // should not be called if nth == 1 2349 kmp_taskred_data_t *arr = (kmp_taskred_data_t *)tg->reduce_data; 2350 kmp_int32 num = tg->reduce_num_data; 2351 for (int i = 0; i < num; ++i) { 2352 void *sh_data = arr[i].reduce_shar; 2353 void (*f_fini)(void *) = (void (*)(void *))(arr[i].reduce_fini); 2354 void (*f_comb)(void *, void *) = 2355 (void (*)(void *, void *))(arr[i].reduce_comb); 2356 if (!arr[i].flags.lazy_priv) { 2357 void *pr_data = arr[i].reduce_priv; 2358 size_t size = arr[i].reduce_size; 2359 for (int j = 0; j < nth; ++j) { 2360 void *priv_data = (char *)pr_data + j * size; 2361 f_comb(sh_data, priv_data); // combine results 2362 if (f_fini) 2363 f_fini(priv_data); // finalize if needed 2364 } 2365 } else { 2366 void **pr_data = (void **)(arr[i].reduce_priv); 2367 for (int j = 0; j < nth; ++j) { 2368 if (pr_data[j] != NULL) { 2369 f_comb(sh_data, pr_data[j]); // combine results 2370 if (f_fini) 2371 f_fini(pr_data[j]); // finalize if needed 2372 __kmp_free(pr_data[j]); 2373 } 2374 } 2375 } 2376 __kmp_free(arr[i].reduce_priv); 2377 } 2378 __kmp_thread_free(th, arr); 2379 tg->reduce_data = NULL; 2380 tg->reduce_num_data = 0; 2381 } 2382 2383 // Cleanup task reduction data for parallel or worksharing, 2384 // do not touch task private data other threads still working with. 2385 // Called from __kmpc_end_taskgroup() 2386 static void __kmp_task_reduction_clean(kmp_info_t *th, kmp_taskgroup_t *tg) { 2387 __kmp_thread_free(th, tg->reduce_data); 2388 tg->reduce_data = NULL; 2389 tg->reduce_num_data = 0; 2390 } 2391 2392 template <typename T> 2393 void *__kmp_task_reduction_modifier_init(ident_t *loc, int gtid, int is_ws, 2394 int num, T *data) { 2395 __kmp_assert_valid_gtid(gtid); 2396 kmp_info_t *thr = __kmp_threads[gtid]; 2397 kmp_int32 nth = thr->th.th_team_nproc; 2398 __kmpc_taskgroup(loc, gtid); // form new taskgroup first 2399 if (nth == 1) { 2400 KA_TRACE(10, 2401 ("__kmpc_reduction_modifier_init: T#%d, tg %p, exiting nth=1\n", 2402 gtid, thr->th.th_current_task->td_taskgroup)); 2403 return (void *)thr->th.th_current_task->td_taskgroup; 2404 } 2405 kmp_team_t *team = thr->th.th_team; 2406 void *reduce_data; 2407 kmp_taskgroup_t *tg; 2408 reduce_data = KMP_ATOMIC_LD_RLX(&team->t.t_tg_reduce_data[is_ws]); 2409 if (reduce_data == NULL && 2410 __kmp_atomic_compare_store(&team->t.t_tg_reduce_data[is_ws], reduce_data, 2411 (void *)1)) { 2412 // single thread enters this block to initialize common reduction data 2413 KMP_DEBUG_ASSERT(reduce_data == NULL); 2414 // first initialize own data, then make a copy other threads can use 2415 tg = (kmp_taskgroup_t *)__kmp_task_reduction_init<T>(gtid, num, data); 2416 reduce_data = __kmp_thread_malloc(thr, num * sizeof(kmp_taskred_data_t)); 2417 KMP_MEMCPY(reduce_data, tg->reduce_data, num * sizeof(kmp_taskred_data_t)); 2418 // fini counters should be 0 at this point 2419 KMP_DEBUG_ASSERT(KMP_ATOMIC_LD_RLX(&team->t.t_tg_fini_counter[0]) == 0); 2420 KMP_DEBUG_ASSERT(KMP_ATOMIC_LD_RLX(&team->t.t_tg_fini_counter[1]) == 0); 2421 KMP_ATOMIC_ST_REL(&team->t.t_tg_reduce_data[is_ws], reduce_data); 2422 } else { 2423 while ( 2424 (reduce_data = KMP_ATOMIC_LD_ACQ(&team->t.t_tg_reduce_data[is_ws])) == 2425 (void *)1) { // wait for task reduction initialization 2426 KMP_CPU_PAUSE(); 2427 } 2428 KMP_DEBUG_ASSERT(reduce_data > (void *)1); // should be valid pointer here 2429 tg = thr->th.th_current_task->td_taskgroup; 2430 __kmp_task_reduction_init_copy<T>(thr, num, data, tg, reduce_data); 2431 } 2432 return tg; 2433 } 2434 2435 /*! 2436 @ingroup TASKING 2437 @param loc Source location info 2438 @param gtid Global thread ID 2439 @param is_ws Is 1 if the reduction is for worksharing, 0 otherwise 2440 @param num Number of data items to reduce 2441 @param data Array of data for reduction 2442 @return The taskgroup identifier 2443 2444 Initialize task reduction for a parallel or worksharing. 2445 2446 Note: this entry supposes the optional compiler-generated initializer routine 2447 has single parameter - pointer to object to be initialized. That means 2448 the reduction either does not use omp_orig object, or the omp_orig is accessible 2449 without help of the runtime library. 2450 */ 2451 void *__kmpc_task_reduction_modifier_init(ident_t *loc, int gtid, int is_ws, 2452 int num, void *data) { 2453 return __kmp_task_reduction_modifier_init(loc, gtid, is_ws, num, 2454 (kmp_task_red_input_t *)data); 2455 } 2456 2457 /*! 2458 @ingroup TASKING 2459 @param loc Source location info 2460 @param gtid Global thread ID 2461 @param is_ws Is 1 if the reduction is for worksharing, 0 otherwise 2462 @param num Number of data items to reduce 2463 @param data Array of data for reduction 2464 @return The taskgroup identifier 2465 2466 Initialize task reduction for a parallel or worksharing. 2467 2468 Note: this entry supposes the optional compiler-generated initializer routine 2469 has two parameters, pointer to object to be initialized and pointer to omp_orig 2470 */ 2471 void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int is_ws, int num, 2472 void *data) { 2473 return __kmp_task_reduction_modifier_init(loc, gtid, is_ws, num, 2474 (kmp_taskred_input_t *)data); 2475 } 2476 2477 /*! 2478 @ingroup TASKING 2479 @param loc Source location info 2480 @param gtid Global thread ID 2481 @param is_ws Is 1 if the reduction is for worksharing, 0 otherwise 2482 2483 Finalize task reduction for a parallel or worksharing. 2484 */ 2485 void __kmpc_task_reduction_modifier_fini(ident_t *loc, int gtid, int is_ws) { 2486 __kmpc_end_taskgroup(loc, gtid); 2487 } 2488 2489 // __kmpc_taskgroup: Start a new taskgroup 2490 void __kmpc_taskgroup(ident_t *loc, int gtid) { 2491 __kmp_assert_valid_gtid(gtid); 2492 kmp_info_t *thread = __kmp_threads[gtid]; 2493 kmp_taskdata_t *taskdata = thread->th.th_current_task; 2494 kmp_taskgroup_t *tg_new = 2495 (kmp_taskgroup_t *)__kmp_thread_malloc(thread, sizeof(kmp_taskgroup_t)); 2496 KA_TRACE(10, ("__kmpc_taskgroup: T#%d loc=%p group=%p\n", gtid, loc, tg_new)); 2497 KMP_ATOMIC_ST_RLX(&tg_new->count, 0); 2498 KMP_ATOMIC_ST_RLX(&tg_new->cancel_request, cancel_noreq); 2499 tg_new->parent = taskdata->td_taskgroup; 2500 tg_new->reduce_data = NULL; 2501 tg_new->reduce_num_data = 0; 2502 tg_new->gomp_data = NULL; 2503 taskdata->td_taskgroup = tg_new; 2504 2505 #if OMPT_SUPPORT && OMPT_OPTIONAL 2506 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region)) { 2507 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid); 2508 if (!codeptr) 2509 codeptr = OMPT_GET_RETURN_ADDRESS(0); 2510 kmp_team_t *team = thread->th.th_team; 2511 ompt_data_t my_task_data = taskdata->ompt_task_info.task_data; 2512 // FIXME: I think this is wrong for lwt! 2513 ompt_data_t my_parallel_data = team->t.ompt_team_info.parallel_data; 2514 2515 ompt_callbacks.ompt_callback(ompt_callback_sync_region)( 2516 ompt_sync_region_taskgroup, ompt_scope_begin, &(my_parallel_data), 2517 &(my_task_data), codeptr); 2518 } 2519 #endif 2520 } 2521 2522 // __kmpc_end_taskgroup: Wait until all tasks generated by the current task 2523 // and its descendants are complete 2524 void __kmpc_end_taskgroup(ident_t *loc, int gtid) { 2525 __kmp_assert_valid_gtid(gtid); 2526 kmp_info_t *thread = __kmp_threads[gtid]; 2527 kmp_taskdata_t *taskdata = thread->th.th_current_task; 2528 kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup; 2529 int thread_finished = FALSE; 2530 2531 #if OMPT_SUPPORT && OMPT_OPTIONAL 2532 kmp_team_t *team; 2533 ompt_data_t my_task_data; 2534 ompt_data_t my_parallel_data; 2535 void *codeptr = nullptr; 2536 if (UNLIKELY(ompt_enabled.enabled)) { 2537 team = thread->th.th_team; 2538 my_task_data = taskdata->ompt_task_info.task_data; 2539 // FIXME: I think this is wrong for lwt! 2540 my_parallel_data = team->t.ompt_team_info.parallel_data; 2541 codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid); 2542 if (!codeptr) 2543 codeptr = OMPT_GET_RETURN_ADDRESS(0); 2544 } 2545 #endif 2546 2547 KA_TRACE(10, ("__kmpc_end_taskgroup(enter): T#%d loc=%p\n", gtid, loc)); 2548 KMP_DEBUG_ASSERT(taskgroup != NULL); 2549 KMP_SET_THREAD_STATE_BLOCK(TASKGROUP); 2550 2551 if (__kmp_tasking_mode != tskm_immediate_exec) { 2552 // mark task as waiting not on a barrier 2553 taskdata->td_taskwait_counter += 1; 2554 taskdata->td_taskwait_ident = loc; 2555 taskdata->td_taskwait_thread = gtid + 1; 2556 #if USE_ITT_BUILD 2557 // For ITT the taskgroup wait is similar to taskwait until we need to 2558 // distinguish them 2559 void *itt_sync_obj = NULL; 2560 #if USE_ITT_NOTIFY 2561 KMP_ITT_TASKWAIT_STARTING(itt_sync_obj); 2562 #endif /* USE_ITT_NOTIFY */ 2563 #endif /* USE_ITT_BUILD */ 2564 2565 #if OMPT_SUPPORT && OMPT_OPTIONAL 2566 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region_wait)) { 2567 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)( 2568 ompt_sync_region_taskgroup, ompt_scope_begin, &(my_parallel_data), 2569 &(my_task_data), codeptr); 2570 } 2571 #endif 2572 2573 if (!taskdata->td_flags.team_serial || 2574 (thread->th.th_task_team != NULL && 2575 thread->th.th_task_team->tt.tt_found_proxy_tasks)) { 2576 kmp_flag_32<false, false> flag( 2577 RCAST(std::atomic<kmp_uint32> *, &(taskgroup->count)), 0U); 2578 while (KMP_ATOMIC_LD_ACQ(&taskgroup->count) != 0) { 2579 flag.execute_tasks(thread, gtid, FALSE, 2580 &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), 2581 __kmp_task_stealing_constraint); 2582 } 2583 } 2584 taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread; // end waiting 2585 2586 #if OMPT_SUPPORT && OMPT_OPTIONAL 2587 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region_wait)) { 2588 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)( 2589 ompt_sync_region_taskgroup, ompt_scope_end, &(my_parallel_data), 2590 &(my_task_data), codeptr); 2591 } 2592 #endif 2593 2594 #if USE_ITT_BUILD 2595 KMP_ITT_TASKWAIT_FINISHED(itt_sync_obj); 2596 KMP_FSYNC_ACQUIRED(taskdata); // acquire self - sync with descendants 2597 #endif /* USE_ITT_BUILD */ 2598 } 2599 KMP_DEBUG_ASSERT(taskgroup->count == 0); 2600 2601 if (taskgroup->reduce_data != NULL && 2602 !taskgroup->gomp_data) { // need to reduce? 2603 int cnt; 2604 void *reduce_data; 2605 kmp_team_t *t = thread->th.th_team; 2606 kmp_taskred_data_t *arr = (kmp_taskred_data_t *)taskgroup->reduce_data; 2607 // check if <priv> data of the first reduction variable shared for the team 2608 void *priv0 = arr[0].reduce_priv; 2609 if ((reduce_data = KMP_ATOMIC_LD_ACQ(&t->t.t_tg_reduce_data[0])) != NULL && 2610 ((kmp_taskred_data_t *)reduce_data)[0].reduce_priv == priv0) { 2611 // finishing task reduction on parallel 2612 cnt = KMP_ATOMIC_INC(&t->t.t_tg_fini_counter[0]); 2613 if (cnt == thread->th.th_team_nproc - 1) { 2614 // we are the last thread passing __kmpc_reduction_modifier_fini() 2615 // finalize task reduction: 2616 __kmp_task_reduction_fini(thread, taskgroup); 2617 // cleanup fields in the team structure: 2618 // TODO: is relaxed store enough here (whole barrier should follow)? 2619 __kmp_thread_free(thread, reduce_data); 2620 KMP_ATOMIC_ST_REL(&t->t.t_tg_reduce_data[0], NULL); 2621 KMP_ATOMIC_ST_REL(&t->t.t_tg_fini_counter[0], 0); 2622 } else { 2623 // we are not the last thread passing __kmpc_reduction_modifier_fini(), 2624 // so do not finalize reduction, just clean own copy of the data 2625 __kmp_task_reduction_clean(thread, taskgroup); 2626 } 2627 } else if ((reduce_data = KMP_ATOMIC_LD_ACQ(&t->t.t_tg_reduce_data[1])) != 2628 NULL && 2629 ((kmp_taskred_data_t *)reduce_data)[0].reduce_priv == priv0) { 2630 // finishing task reduction on worksharing 2631 cnt = KMP_ATOMIC_INC(&t->t.t_tg_fini_counter[1]); 2632 if (cnt == thread->th.th_team_nproc - 1) { 2633 // we are the last thread passing __kmpc_reduction_modifier_fini() 2634 __kmp_task_reduction_fini(thread, taskgroup); 2635 // cleanup fields in team structure: 2636 // TODO: is relaxed store enough here (whole barrier should follow)? 2637 __kmp_thread_free(thread, reduce_data); 2638 KMP_ATOMIC_ST_REL(&t->t.t_tg_reduce_data[1], NULL); 2639 KMP_ATOMIC_ST_REL(&t->t.t_tg_fini_counter[1], 0); 2640 } else { 2641 // we are not the last thread passing __kmpc_reduction_modifier_fini(), 2642 // so do not finalize reduction, just clean own copy of the data 2643 __kmp_task_reduction_clean(thread, taskgroup); 2644 } 2645 } else { 2646 // finishing task reduction on taskgroup 2647 __kmp_task_reduction_fini(thread, taskgroup); 2648 } 2649 } 2650 // Restore parent taskgroup for the current task 2651 taskdata->td_taskgroup = taskgroup->parent; 2652 __kmp_thread_free(thread, taskgroup); 2653 2654 KA_TRACE(10, ("__kmpc_end_taskgroup(exit): T#%d task %p finished waiting\n", 2655 gtid, taskdata)); 2656 2657 #if OMPT_SUPPORT && OMPT_OPTIONAL 2658 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region)) { 2659 ompt_callbacks.ompt_callback(ompt_callback_sync_region)( 2660 ompt_sync_region_taskgroup, ompt_scope_end, &(my_parallel_data), 2661 &(my_task_data), codeptr); 2662 } 2663 #endif 2664 } 2665 2666 // __kmp_remove_my_task: remove a task from my own deque 2667 static kmp_task_t *__kmp_remove_my_task(kmp_info_t *thread, kmp_int32 gtid, 2668 kmp_task_team_t *task_team, 2669 kmp_int32 is_constrained) { 2670 kmp_task_t *task; 2671 kmp_taskdata_t *taskdata; 2672 kmp_thread_data_t *thread_data; 2673 kmp_uint32 tail; 2674 2675 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 2676 KMP_DEBUG_ASSERT(task_team->tt.tt_threads_data != 2677 NULL); // Caller should check this condition 2678 2679 thread_data = &task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)]; 2680 2681 KA_TRACE(10, ("__kmp_remove_my_task(enter): T#%d ntasks=%d head=%u tail=%u\n", 2682 gtid, thread_data->td.td_deque_ntasks, 2683 thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 2684 2685 if (TCR_4(thread_data->td.td_deque_ntasks) == 0) { 2686 KA_TRACE(10, 2687 ("__kmp_remove_my_task(exit #1): T#%d No tasks to remove: " 2688 "ntasks=%d head=%u tail=%u\n", 2689 gtid, thread_data->td.td_deque_ntasks, 2690 thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 2691 return NULL; 2692 } 2693 2694 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 2695 2696 if (TCR_4(thread_data->td.td_deque_ntasks) == 0) { 2697 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 2698 KA_TRACE(10, 2699 ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: " 2700 "ntasks=%d head=%u tail=%u\n", 2701 gtid, thread_data->td.td_deque_ntasks, 2702 thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 2703 return NULL; 2704 } 2705 2706 tail = (thread_data->td.td_deque_tail - 1) & 2707 TASK_DEQUE_MASK(thread_data->td); // Wrap index. 2708 taskdata = thread_data->td.td_deque[tail]; 2709 2710 if (!__kmp_task_is_allowed(gtid, is_constrained, taskdata, 2711 thread->th.th_current_task)) { 2712 // The TSC does not allow to steal victim task 2713 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 2714 KA_TRACE(10, 2715 ("__kmp_remove_my_task(exit #3): T#%d TSC blocks tail task: " 2716 "ntasks=%d head=%u tail=%u\n", 2717 gtid, thread_data->td.td_deque_ntasks, 2718 thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 2719 return NULL; 2720 } 2721 2722 thread_data->td.td_deque_tail = tail; 2723 TCW_4(thread_data->td.td_deque_ntasks, thread_data->td.td_deque_ntasks - 1); 2724 2725 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 2726 2727 KA_TRACE(10, ("__kmp_remove_my_task(exit #4): T#%d task %p removed: " 2728 "ntasks=%d head=%u tail=%u\n", 2729 gtid, taskdata, thread_data->td.td_deque_ntasks, 2730 thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 2731 2732 task = KMP_TASKDATA_TO_TASK(taskdata); 2733 return task; 2734 } 2735 2736 // __kmp_steal_task: remove a task from another thread's deque 2737 // Assume that calling thread has already checked existence of 2738 // task_team thread_data before calling this routine. 2739 static kmp_task_t *__kmp_steal_task(kmp_info_t *victim_thr, kmp_int32 gtid, 2740 kmp_task_team_t *task_team, 2741 std::atomic<kmp_int32> *unfinished_threads, 2742 int *thread_finished, 2743 kmp_int32 is_constrained) { 2744 kmp_task_t *task; 2745 kmp_taskdata_t *taskdata; 2746 kmp_taskdata_t *current; 2747 kmp_thread_data_t *victim_td, *threads_data; 2748 kmp_int32 target; 2749 kmp_int32 victim_tid; 2750 2751 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 2752 2753 threads_data = task_team->tt.tt_threads_data; 2754 KMP_DEBUG_ASSERT(threads_data != NULL); // Caller should check this condition 2755 2756 victim_tid = victim_thr->th.th_info.ds.ds_tid; 2757 victim_td = &threads_data[victim_tid]; 2758 2759 KA_TRACE(10, ("__kmp_steal_task(enter): T#%d try to steal from T#%d: " 2760 "task_team=%p ntasks=%d head=%u tail=%u\n", 2761 gtid, __kmp_gtid_from_thread(victim_thr), task_team, 2762 victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head, 2763 victim_td->td.td_deque_tail)); 2764 2765 if (TCR_4(victim_td->td.td_deque_ntasks) == 0) { 2766 KA_TRACE(10, ("__kmp_steal_task(exit #1): T#%d could not steal from T#%d: " 2767 "task_team=%p ntasks=%d head=%u tail=%u\n", 2768 gtid, __kmp_gtid_from_thread(victim_thr), task_team, 2769 victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head, 2770 victim_td->td.td_deque_tail)); 2771 return NULL; 2772 } 2773 2774 __kmp_acquire_bootstrap_lock(&victim_td->td.td_deque_lock); 2775 2776 int ntasks = TCR_4(victim_td->td.td_deque_ntasks); 2777 // Check again after we acquire the lock 2778 if (ntasks == 0) { 2779 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock); 2780 KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: " 2781 "task_team=%p ntasks=%d head=%u tail=%u\n", 2782 gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks, 2783 victim_td->td.td_deque_head, victim_td->td.td_deque_tail)); 2784 return NULL; 2785 } 2786 2787 KMP_DEBUG_ASSERT(victim_td->td.td_deque != NULL); 2788 current = __kmp_threads[gtid]->th.th_current_task; 2789 taskdata = victim_td->td.td_deque[victim_td->td.td_deque_head]; 2790 if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) { 2791 // Bump head pointer and Wrap. 2792 victim_td->td.td_deque_head = 2793 (victim_td->td.td_deque_head + 1) & TASK_DEQUE_MASK(victim_td->td); 2794 } else { 2795 if (!task_team->tt.tt_untied_task_encountered) { 2796 // The TSC does not allow to steal victim task 2797 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock); 2798 KA_TRACE(10, ("__kmp_steal_task(exit #3): T#%d could not steal from " 2799 "T#%d: task_team=%p ntasks=%d head=%u tail=%u\n", 2800 gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks, 2801 victim_td->td.td_deque_head, victim_td->td.td_deque_tail)); 2802 return NULL; 2803 } 2804 int i; 2805 // walk through victim's deque trying to steal any task 2806 target = victim_td->td.td_deque_head; 2807 taskdata = NULL; 2808 for (i = 1; i < ntasks; ++i) { 2809 target = (target + 1) & TASK_DEQUE_MASK(victim_td->td); 2810 taskdata = victim_td->td.td_deque[target]; 2811 if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) { 2812 break; // found victim task 2813 } else { 2814 taskdata = NULL; 2815 } 2816 } 2817 if (taskdata == NULL) { 2818 // No appropriate candidate to steal found 2819 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock); 2820 KA_TRACE(10, ("__kmp_steal_task(exit #4): T#%d could not steal from " 2821 "T#%d: task_team=%p ntasks=%d head=%u tail=%u\n", 2822 gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks, 2823 victim_td->td.td_deque_head, victim_td->td.td_deque_tail)); 2824 return NULL; 2825 } 2826 int prev = target; 2827 for (i = i + 1; i < ntasks; ++i) { 2828 // shift remaining tasks in the deque left by 1 2829 target = (target + 1) & TASK_DEQUE_MASK(victim_td->td); 2830 victim_td->td.td_deque[prev] = victim_td->td.td_deque[target]; 2831 prev = target; 2832 } 2833 KMP_DEBUG_ASSERT( 2834 victim_td->td.td_deque_tail == 2835 (kmp_uint32)((target + 1) & TASK_DEQUE_MASK(victim_td->td))); 2836 victim_td->td.td_deque_tail = target; // tail -= 1 (wrapped)) 2837 } 2838 if (*thread_finished) { 2839 // We need to un-mark this victim as a finished victim. This must be done 2840 // before releasing the lock, or else other threads (starting with the 2841 // primary thread victim) might be prematurely released from the barrier!!! 2842 kmp_int32 count; 2843 2844 count = KMP_ATOMIC_INC(unfinished_threads); 2845 2846 KA_TRACE( 2847 20, 2848 ("__kmp_steal_task: T#%d inc unfinished_threads to %d: task_team=%p\n", 2849 gtid, count + 1, task_team)); 2850 2851 *thread_finished = FALSE; 2852 } 2853 TCW_4(victim_td->td.td_deque_ntasks, ntasks - 1); 2854 2855 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock); 2856 2857 KMP_COUNT_BLOCK(TASK_stolen); 2858 KA_TRACE(10, 2859 ("__kmp_steal_task(exit #5): T#%d stole task %p from T#%d: " 2860 "task_team=%p ntasks=%d head=%u tail=%u\n", 2861 gtid, taskdata, __kmp_gtid_from_thread(victim_thr), task_team, 2862 ntasks, victim_td->td.td_deque_head, victim_td->td.td_deque_tail)); 2863 2864 task = KMP_TASKDATA_TO_TASK(taskdata); 2865 return task; 2866 } 2867 2868 // __kmp_execute_tasks_template: Choose and execute tasks until either the 2869 // condition is statisfied (return true) or there are none left (return false). 2870 // 2871 // final_spin is TRUE if this is the spin at the release barrier. 2872 // thread_finished indicates whether the thread is finished executing all 2873 // the tasks it has on its deque, and is at the release barrier. 2874 // spinner is the location on which to spin. 2875 // spinner == NULL means only execute a single task and return. 2876 // checker is the value to check to terminate the spin. 2877 template <class C> 2878 static inline int __kmp_execute_tasks_template( 2879 kmp_info_t *thread, kmp_int32 gtid, C *flag, int final_spin, 2880 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 2881 kmp_int32 is_constrained) { 2882 kmp_task_team_t *task_team = thread->th.th_task_team; 2883 kmp_thread_data_t *threads_data; 2884 kmp_task_t *task; 2885 kmp_info_t *other_thread; 2886 kmp_taskdata_t *current_task = thread->th.th_current_task; 2887 std::atomic<kmp_int32> *unfinished_threads; 2888 kmp_int32 nthreads, victim_tid = -2, use_own_tasks = 1, new_victim = 0, 2889 tid = thread->th.th_info.ds.ds_tid; 2890 2891 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 2892 KMP_DEBUG_ASSERT(thread == __kmp_threads[gtid]); 2893 2894 if (task_team == NULL || current_task == NULL) 2895 return FALSE; 2896 2897 KA_TRACE(15, ("__kmp_execute_tasks_template(enter): T#%d final_spin=%d " 2898 "*thread_finished=%d\n", 2899 gtid, final_spin, *thread_finished)); 2900 2901 thread->th.th_reap_state = KMP_NOT_SAFE_TO_REAP; 2902 threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data); 2903 2904 KMP_DEBUG_ASSERT(threads_data != NULL); 2905 2906 nthreads = task_team->tt.tt_nproc; 2907 unfinished_threads = &(task_team->tt.tt_unfinished_threads); 2908 KMP_DEBUG_ASSERT(nthreads > 1 || task_team->tt.tt_found_proxy_tasks || 2909 task_team->tt.tt_hidden_helper_task_encountered); 2910 KMP_DEBUG_ASSERT(*unfinished_threads >= 0); 2911 2912 while (1) { // Outer loop keeps trying to find tasks in case of single thread 2913 // getting tasks from target constructs 2914 while (1) { // Inner loop to find a task and execute it 2915 task = NULL; 2916 if (use_own_tasks) { // check on own queue first 2917 task = __kmp_remove_my_task(thread, gtid, task_team, is_constrained); 2918 } 2919 if ((task == NULL) && (nthreads > 1)) { // Steal a task 2920 int asleep = 1; 2921 use_own_tasks = 0; 2922 // Try to steal from the last place I stole from successfully. 2923 if (victim_tid == -2) { // haven't stolen anything yet 2924 victim_tid = threads_data[tid].td.td_deque_last_stolen; 2925 if (victim_tid != 2926 -1) // if we have a last stolen from victim, get the thread 2927 other_thread = threads_data[victim_tid].td.td_thr; 2928 } 2929 if (victim_tid != -1) { // found last victim 2930 asleep = 0; 2931 } else if (!new_victim) { // no recent steals and we haven't already 2932 // used a new victim; select a random thread 2933 do { // Find a different thread to steal work from. 2934 // Pick a random thread. Initial plan was to cycle through all the 2935 // threads, and only return if we tried to steal from every thread, 2936 // and failed. Arch says that's not such a great idea. 2937 victim_tid = __kmp_get_random(thread) % (nthreads - 1); 2938 if (victim_tid >= tid) { 2939 ++victim_tid; // Adjusts random distribution to exclude self 2940 } 2941 // Found a potential victim 2942 other_thread = threads_data[victim_tid].td.td_thr; 2943 // There is a slight chance that __kmp_enable_tasking() did not wake 2944 // up all threads waiting at the barrier. If victim is sleeping, 2945 // then wake it up. Since we were going to pay the cache miss 2946 // penalty for referencing another thread's kmp_info_t struct 2947 // anyway, 2948 // the check shouldn't cost too much performance at this point. In 2949 // extra barrier mode, tasks do not sleep at the separate tasking 2950 // barrier, so this isn't a problem. 2951 asleep = 0; 2952 if ((__kmp_tasking_mode == tskm_task_teams) && 2953 (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) && 2954 (TCR_PTR(CCAST(void *, other_thread->th.th_sleep_loc)) != 2955 NULL)) { 2956 asleep = 1; 2957 __kmp_null_resume_wrapper(__kmp_gtid_from_thread(other_thread), 2958 other_thread->th.th_sleep_loc); 2959 // A sleeping thread should not have any tasks on it's queue. 2960 // There is a slight possibility that it resumes, steals a task 2961 // from another thread, which spawns more tasks, all in the time 2962 // that it takes this thread to check => don't write an assertion 2963 // that the victim's queue is empty. Try stealing from a 2964 // different thread. 2965 } 2966 } while (asleep); 2967 } 2968 2969 if (!asleep) { 2970 // We have a victim to try to steal from 2971 task = __kmp_steal_task(other_thread, gtid, task_team, 2972 unfinished_threads, thread_finished, 2973 is_constrained); 2974 } 2975 if (task != NULL) { // set last stolen to victim 2976 if (threads_data[tid].td.td_deque_last_stolen != victim_tid) { 2977 threads_data[tid].td.td_deque_last_stolen = victim_tid; 2978 // The pre-refactored code did not try more than 1 successful new 2979 // vicitm, unless the last one generated more local tasks; 2980 // new_victim keeps track of this 2981 new_victim = 1; 2982 } 2983 } else { // No tasks found; unset last_stolen 2984 KMP_CHECK_UPDATE(threads_data[tid].td.td_deque_last_stolen, -1); 2985 victim_tid = -2; // no successful victim found 2986 } 2987 } 2988 2989 if (task == NULL) 2990 break; // break out of tasking loop 2991 2992 // Found a task; execute it 2993 #if USE_ITT_BUILD && USE_ITT_NOTIFY 2994 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) { 2995 if (itt_sync_obj == NULL) { // we are at fork barrier where we could not 2996 // get the object reliably 2997 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier); 2998 } 2999 __kmp_itt_task_starting(itt_sync_obj); 3000 } 3001 #endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */ 3002 __kmp_invoke_task(gtid, task, current_task); 3003 #if USE_ITT_BUILD 3004 if (itt_sync_obj != NULL) 3005 __kmp_itt_task_finished(itt_sync_obj); 3006 #endif /* USE_ITT_BUILD */ 3007 // If this thread is only partway through the barrier and the condition is 3008 // met, then return now, so that the barrier gather/release pattern can 3009 // proceed. If this thread is in the last spin loop in the barrier, 3010 // waiting to be released, we know that the termination condition will not 3011 // be satisfied, so don't waste any cycles checking it. 3012 if (flag == NULL || (!final_spin && flag->done_check())) { 3013 KA_TRACE( 3014 15, 3015 ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n", 3016 gtid)); 3017 return TRUE; 3018 } 3019 if (thread->th.th_task_team == NULL) { 3020 break; 3021 } 3022 KMP_YIELD(__kmp_library == library_throughput); // Yield before next task 3023 // If execution of a stolen task results in more tasks being placed on our 3024 // run queue, reset use_own_tasks 3025 if (!use_own_tasks && TCR_4(threads_data[tid].td.td_deque_ntasks) != 0) { 3026 KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d stolen task spawned " 3027 "other tasks, restart\n", 3028 gtid)); 3029 use_own_tasks = 1; 3030 new_victim = 0; 3031 } 3032 } 3033 3034 // The task source has been exhausted. If in final spin loop of barrier, 3035 // check if termination condition is satisfied. The work queue may be empty 3036 // but there might be proxy tasks still executing. 3037 if (final_spin && 3038 KMP_ATOMIC_LD_ACQ(¤t_task->td_incomplete_child_tasks) == 0) { 3039 // First, decrement the #unfinished threads, if that has not already been 3040 // done. This decrement might be to the spin location, and result in the 3041 // termination condition being satisfied. 3042 if (!*thread_finished) { 3043 kmp_int32 count; 3044 3045 count = KMP_ATOMIC_DEC(unfinished_threads) - 1; 3046 KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d dec " 3047 "unfinished_threads to %d task_team=%p\n", 3048 gtid, count, task_team)); 3049 *thread_finished = TRUE; 3050 } 3051 3052 // It is now unsafe to reference thread->th.th_team !!! 3053 // Decrementing task_team->tt.tt_unfinished_threads can allow the primary 3054 // thread to pass through the barrier, where it might reset each thread's 3055 // th.th_team field for the next parallel region. If we can steal more 3056 // work, we know that this has not happened yet. 3057 if (flag != NULL && flag->done_check()) { 3058 KA_TRACE( 3059 15, 3060 ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n", 3061 gtid)); 3062 return TRUE; 3063 } 3064 } 3065 3066 // If this thread's task team is NULL, primary thread has recognized that 3067 // there are no more tasks; bail out 3068 if (thread->th.th_task_team == NULL) { 3069 KA_TRACE(15, 3070 ("__kmp_execute_tasks_template: T#%d no more tasks\n", gtid)); 3071 return FALSE; 3072 } 3073 3074 // We could be getting tasks from target constructs; if this is the only 3075 // thread, keep trying to execute tasks from own queue 3076 if (nthreads == 1 && 3077 KMP_ATOMIC_LD_ACQ(¤t_task->td_incomplete_child_tasks)) 3078 use_own_tasks = 1; 3079 else { 3080 KA_TRACE(15, 3081 ("__kmp_execute_tasks_template: T#%d can't find work\n", gtid)); 3082 return FALSE; 3083 } 3084 } 3085 } 3086 3087 template <bool C, bool S> 3088 int __kmp_execute_tasks_32( 3089 kmp_info_t *thread, kmp_int32 gtid, kmp_flag_32<C, S> *flag, int final_spin, 3090 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 3091 kmp_int32 is_constrained) { 3092 return __kmp_execute_tasks_template( 3093 thread, gtid, flag, final_spin, 3094 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained); 3095 } 3096 3097 template <bool C, bool S> 3098 int __kmp_execute_tasks_64( 3099 kmp_info_t *thread, kmp_int32 gtid, kmp_flag_64<C, S> *flag, int final_spin, 3100 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 3101 kmp_int32 is_constrained) { 3102 return __kmp_execute_tasks_template( 3103 thread, gtid, flag, final_spin, 3104 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained); 3105 } 3106 3107 int __kmp_execute_tasks_oncore( 3108 kmp_info_t *thread, kmp_int32 gtid, kmp_flag_oncore *flag, int final_spin, 3109 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 3110 kmp_int32 is_constrained) { 3111 return __kmp_execute_tasks_template( 3112 thread, gtid, flag, final_spin, 3113 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained); 3114 } 3115 3116 template int 3117 __kmp_execute_tasks_32<false, false>(kmp_info_t *, kmp_int32, 3118 kmp_flag_32<false, false> *, int, 3119 int *USE_ITT_BUILD_ARG(void *), kmp_int32); 3120 3121 template int __kmp_execute_tasks_64<false, true>(kmp_info_t *, kmp_int32, 3122 kmp_flag_64<false, true> *, 3123 int, 3124 int *USE_ITT_BUILD_ARG(void *), 3125 kmp_int32); 3126 3127 template int __kmp_execute_tasks_64<true, false>(kmp_info_t *, kmp_int32, 3128 kmp_flag_64<true, false> *, 3129 int, 3130 int *USE_ITT_BUILD_ARG(void *), 3131 kmp_int32); 3132 3133 // __kmp_enable_tasking: Allocate task team and resume threads sleeping at the 3134 // next barrier so they can assist in executing enqueued tasks. 3135 // First thread in allocates the task team atomically. 3136 static void __kmp_enable_tasking(kmp_task_team_t *task_team, 3137 kmp_info_t *this_thr) { 3138 kmp_thread_data_t *threads_data; 3139 int nthreads, i, is_init_thread; 3140 3141 KA_TRACE(10, ("__kmp_enable_tasking(enter): T#%d\n", 3142 __kmp_gtid_from_thread(this_thr))); 3143 3144 KMP_DEBUG_ASSERT(task_team != NULL); 3145 KMP_DEBUG_ASSERT(this_thr->th.th_team != NULL); 3146 3147 nthreads = task_team->tt.tt_nproc; 3148 KMP_DEBUG_ASSERT(nthreads > 0); 3149 KMP_DEBUG_ASSERT(nthreads == this_thr->th.th_team->t.t_nproc); 3150 3151 // Allocate or increase the size of threads_data if necessary 3152 is_init_thread = __kmp_realloc_task_threads_data(this_thr, task_team); 3153 3154 if (!is_init_thread) { 3155 // Some other thread already set up the array. 3156 KA_TRACE( 3157 20, 3158 ("__kmp_enable_tasking(exit): T#%d: threads array already set up.\n", 3159 __kmp_gtid_from_thread(this_thr))); 3160 return; 3161 } 3162 threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data); 3163 KMP_DEBUG_ASSERT(threads_data != NULL); 3164 3165 if (__kmp_tasking_mode == tskm_task_teams && 3166 (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME)) { 3167 // Release any threads sleeping at the barrier, so that they can steal 3168 // tasks and execute them. In extra barrier mode, tasks do not sleep 3169 // at the separate tasking barrier, so this isn't a problem. 3170 for (i = 0; i < nthreads; i++) { 3171 volatile void *sleep_loc; 3172 kmp_info_t *thread = threads_data[i].td.td_thr; 3173 3174 if (i == this_thr->th.th_info.ds.ds_tid) { 3175 continue; 3176 } 3177 // Since we haven't locked the thread's suspend mutex lock at this 3178 // point, there is a small window where a thread might be putting 3179 // itself to sleep, but hasn't set the th_sleep_loc field yet. 3180 // To work around this, __kmp_execute_tasks_template() periodically checks 3181 // see if other threads are sleeping (using the same random mechanism that 3182 // is used for task stealing) and awakens them if they are. 3183 if ((sleep_loc = TCR_PTR(CCAST(void *, thread->th.th_sleep_loc))) != 3184 NULL) { 3185 KF_TRACE(50, ("__kmp_enable_tasking: T#%d waking up thread T#%d\n", 3186 __kmp_gtid_from_thread(this_thr), 3187 __kmp_gtid_from_thread(thread))); 3188 __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc); 3189 } else { 3190 KF_TRACE(50, ("__kmp_enable_tasking: T#%d don't wake up thread T#%d\n", 3191 __kmp_gtid_from_thread(this_thr), 3192 __kmp_gtid_from_thread(thread))); 3193 } 3194 } 3195 } 3196 3197 KA_TRACE(10, ("__kmp_enable_tasking(exit): T#%d\n", 3198 __kmp_gtid_from_thread(this_thr))); 3199 } 3200 3201 /* // TODO: Check the comment consistency 3202 * Utility routines for "task teams". A task team (kmp_task_t) is kind of 3203 * like a shadow of the kmp_team_t data struct, with a different lifetime. 3204 * After a child * thread checks into a barrier and calls __kmp_release() from 3205 * the particular variant of __kmp_<barrier_kind>_barrier_gather(), it can no 3206 * longer assume that the kmp_team_t structure is intact (at any moment, the 3207 * primary thread may exit the barrier code and free the team data structure, 3208 * and return the threads to the thread pool). 3209 * 3210 * This does not work with the tasking code, as the thread is still 3211 * expected to participate in the execution of any tasks that may have been 3212 * spawned my a member of the team, and the thread still needs access to all 3213 * to each thread in the team, so that it can steal work from it. 3214 * 3215 * Enter the existence of the kmp_task_team_t struct. It employs a reference 3216 * counting mechanism, and is allocated by the primary thread before calling 3217 * __kmp_<barrier_kind>_release, and then is release by the last thread to 3218 * exit __kmp_<barrier_kind>_release at the next barrier. I.e. the lifetimes 3219 * of the kmp_task_team_t structs for consecutive barriers can overlap 3220 * (and will, unless the primary thread is the last thread to exit the barrier 3221 * release phase, which is not typical). The existence of such a struct is 3222 * useful outside the context of tasking. 3223 * 3224 * We currently use the existence of the threads array as an indicator that 3225 * tasks were spawned since the last barrier. If the structure is to be 3226 * useful outside the context of tasking, then this will have to change, but 3227 * not setting the field minimizes the performance impact of tasking on 3228 * barriers, when no explicit tasks were spawned (pushed, actually). 3229 */ 3230 3231 static kmp_task_team_t *__kmp_free_task_teams = 3232 NULL; // Free list for task_team data structures 3233 // Lock for task team data structures 3234 kmp_bootstrap_lock_t __kmp_task_team_lock = 3235 KMP_BOOTSTRAP_LOCK_INITIALIZER(__kmp_task_team_lock); 3236 3237 // __kmp_alloc_task_deque: 3238 // Allocates a task deque for a particular thread, and initialize the necessary 3239 // data structures relating to the deque. This only happens once per thread 3240 // per task team since task teams are recycled. No lock is needed during 3241 // allocation since each thread allocates its own deque. 3242 static void __kmp_alloc_task_deque(kmp_info_t *thread, 3243 kmp_thread_data_t *thread_data) { 3244 __kmp_init_bootstrap_lock(&thread_data->td.td_deque_lock); 3245 KMP_DEBUG_ASSERT(thread_data->td.td_deque == NULL); 3246 3247 // Initialize last stolen task field to "none" 3248 thread_data->td.td_deque_last_stolen = -1; 3249 3250 KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) == 0); 3251 KMP_DEBUG_ASSERT(thread_data->td.td_deque_head == 0); 3252 KMP_DEBUG_ASSERT(thread_data->td.td_deque_tail == 0); 3253 3254 KE_TRACE( 3255 10, 3256 ("__kmp_alloc_task_deque: T#%d allocating deque[%d] for thread_data %p\n", 3257 __kmp_gtid_from_thread(thread), INITIAL_TASK_DEQUE_SIZE, thread_data)); 3258 // Allocate space for task deque, and zero the deque 3259 // Cannot use __kmp_thread_calloc() because threads not around for 3260 // kmp_reap_task_team( ). 3261 thread_data->td.td_deque = (kmp_taskdata_t **)__kmp_allocate( 3262 INITIAL_TASK_DEQUE_SIZE * sizeof(kmp_taskdata_t *)); 3263 thread_data->td.td_deque_size = INITIAL_TASK_DEQUE_SIZE; 3264 } 3265 3266 // __kmp_free_task_deque: 3267 // Deallocates a task deque for a particular thread. Happens at library 3268 // deallocation so don't need to reset all thread data fields. 3269 static void __kmp_free_task_deque(kmp_thread_data_t *thread_data) { 3270 if (thread_data->td.td_deque != NULL) { 3271 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 3272 TCW_4(thread_data->td.td_deque_ntasks, 0); 3273 __kmp_free(thread_data->td.td_deque); 3274 thread_data->td.td_deque = NULL; 3275 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 3276 } 3277 3278 #ifdef BUILD_TIED_TASK_STACK 3279 // GEH: Figure out what to do here for td_susp_tied_tasks 3280 if (thread_data->td.td_susp_tied_tasks.ts_entries != TASK_STACK_EMPTY) { 3281 __kmp_free_task_stack(__kmp_thread_from_gtid(gtid), thread_data); 3282 } 3283 #endif // BUILD_TIED_TASK_STACK 3284 } 3285 3286 // __kmp_realloc_task_threads_data: 3287 // Allocates a threads_data array for a task team, either by allocating an 3288 // initial array or enlarging an existing array. Only the first thread to get 3289 // the lock allocs or enlarges the array and re-initializes the array elements. 3290 // That thread returns "TRUE", the rest return "FALSE". 3291 // Assumes that the new array size is given by task_team -> tt.tt_nproc. 3292 // The current size is given by task_team -> tt.tt_max_threads. 3293 static int __kmp_realloc_task_threads_data(kmp_info_t *thread, 3294 kmp_task_team_t *task_team) { 3295 kmp_thread_data_t **threads_data_p; 3296 kmp_int32 nthreads, maxthreads; 3297 int is_init_thread = FALSE; 3298 3299 if (TCR_4(task_team->tt.tt_found_tasks)) { 3300 // Already reallocated and initialized. 3301 return FALSE; 3302 } 3303 3304 threads_data_p = &task_team->tt.tt_threads_data; 3305 nthreads = task_team->tt.tt_nproc; 3306 maxthreads = task_team->tt.tt_max_threads; 3307 3308 // All threads must lock when they encounter the first task of the implicit 3309 // task region to make sure threads_data fields are (re)initialized before 3310 // used. 3311 __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock); 3312 3313 if (!TCR_4(task_team->tt.tt_found_tasks)) { 3314 // first thread to enable tasking 3315 kmp_team_t *team = thread->th.th_team; 3316 int i; 3317 3318 is_init_thread = TRUE; 3319 if (maxthreads < nthreads) { 3320 3321 if (*threads_data_p != NULL) { 3322 kmp_thread_data_t *old_data = *threads_data_p; 3323 kmp_thread_data_t *new_data = NULL; 3324 3325 KE_TRACE( 3326 10, 3327 ("__kmp_realloc_task_threads_data: T#%d reallocating " 3328 "threads data for task_team %p, new_size = %d, old_size = %d\n", 3329 __kmp_gtid_from_thread(thread), task_team, nthreads, maxthreads)); 3330 // Reallocate threads_data to have more elements than current array 3331 // Cannot use __kmp_thread_realloc() because threads not around for 3332 // kmp_reap_task_team( ). Note all new array entries are initialized 3333 // to zero by __kmp_allocate(). 3334 new_data = (kmp_thread_data_t *)__kmp_allocate( 3335 nthreads * sizeof(kmp_thread_data_t)); 3336 // copy old data to new data 3337 KMP_MEMCPY_S((void *)new_data, nthreads * sizeof(kmp_thread_data_t), 3338 (void *)old_data, maxthreads * sizeof(kmp_thread_data_t)); 3339 3340 #ifdef BUILD_TIED_TASK_STACK 3341 // GEH: Figure out if this is the right thing to do 3342 for (i = maxthreads; i < nthreads; i++) { 3343 kmp_thread_data_t *thread_data = &(*threads_data_p)[i]; 3344 __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data); 3345 } 3346 #endif // BUILD_TIED_TASK_STACK 3347 // Install the new data and free the old data 3348 (*threads_data_p) = new_data; 3349 __kmp_free(old_data); 3350 } else { 3351 KE_TRACE(10, ("__kmp_realloc_task_threads_data: T#%d allocating " 3352 "threads data for task_team %p, size = %d\n", 3353 __kmp_gtid_from_thread(thread), task_team, nthreads)); 3354 // Make the initial allocate for threads_data array, and zero entries 3355 // Cannot use __kmp_thread_calloc() because threads not around for 3356 // kmp_reap_task_team( ). 3357 *threads_data_p = (kmp_thread_data_t *)__kmp_allocate( 3358 nthreads * sizeof(kmp_thread_data_t)); 3359 #ifdef BUILD_TIED_TASK_STACK 3360 // GEH: Figure out if this is the right thing to do 3361 for (i = 0; i < nthreads; i++) { 3362 kmp_thread_data_t *thread_data = &(*threads_data_p)[i]; 3363 __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data); 3364 } 3365 #endif // BUILD_TIED_TASK_STACK 3366 } 3367 task_team->tt.tt_max_threads = nthreads; 3368 } else { 3369 // If array has (more than) enough elements, go ahead and use it 3370 KMP_DEBUG_ASSERT(*threads_data_p != NULL); 3371 } 3372 3373 // initialize threads_data pointers back to thread_info structures 3374 for (i = 0; i < nthreads; i++) { 3375 kmp_thread_data_t *thread_data = &(*threads_data_p)[i]; 3376 thread_data->td.td_thr = team->t.t_threads[i]; 3377 3378 if (thread_data->td.td_deque_last_stolen >= nthreads) { 3379 // The last stolen field survives across teams / barrier, and the number 3380 // of threads may have changed. It's possible (likely?) that a new 3381 // parallel region will exhibit the same behavior as previous region. 3382 thread_data->td.td_deque_last_stolen = -1; 3383 } 3384 } 3385 3386 KMP_MB(); 3387 TCW_SYNC_4(task_team->tt.tt_found_tasks, TRUE); 3388 } 3389 3390 __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock); 3391 return is_init_thread; 3392 } 3393 3394 // __kmp_free_task_threads_data: 3395 // Deallocates a threads_data array for a task team, including any attached 3396 // tasking deques. Only occurs at library shutdown. 3397 static void __kmp_free_task_threads_data(kmp_task_team_t *task_team) { 3398 __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock); 3399 if (task_team->tt.tt_threads_data != NULL) { 3400 int i; 3401 for (i = 0; i < task_team->tt.tt_max_threads; i++) { 3402 __kmp_free_task_deque(&task_team->tt.tt_threads_data[i]); 3403 } 3404 __kmp_free(task_team->tt.tt_threads_data); 3405 task_team->tt.tt_threads_data = NULL; 3406 } 3407 __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock); 3408 } 3409 3410 // __kmp_allocate_task_team: 3411 // Allocates a task team associated with a specific team, taking it from 3412 // the global task team free list if possible. Also initializes data 3413 // structures. 3414 static kmp_task_team_t *__kmp_allocate_task_team(kmp_info_t *thread, 3415 kmp_team_t *team) { 3416 kmp_task_team_t *task_team = NULL; 3417 int nthreads; 3418 3419 KA_TRACE(20, ("__kmp_allocate_task_team: T#%d entering; team = %p\n", 3420 (thread ? __kmp_gtid_from_thread(thread) : -1), team)); 3421 3422 if (TCR_PTR(__kmp_free_task_teams) != NULL) { 3423 // Take a task team from the task team pool 3424 __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock); 3425 if (__kmp_free_task_teams != NULL) { 3426 task_team = __kmp_free_task_teams; 3427 TCW_PTR(__kmp_free_task_teams, task_team->tt.tt_next); 3428 task_team->tt.tt_next = NULL; 3429 } 3430 __kmp_release_bootstrap_lock(&__kmp_task_team_lock); 3431 } 3432 3433 if (task_team == NULL) { 3434 KE_TRACE(10, ("__kmp_allocate_task_team: T#%d allocating " 3435 "task team for team %p\n", 3436 __kmp_gtid_from_thread(thread), team)); 3437 // Allocate a new task team if one is not available. Cannot use 3438 // __kmp_thread_malloc because threads not around for kmp_reap_task_team. 3439 task_team = (kmp_task_team_t *)__kmp_allocate(sizeof(kmp_task_team_t)); 3440 __kmp_init_bootstrap_lock(&task_team->tt.tt_threads_lock); 3441 #if USE_ITT_BUILD && USE_ITT_NOTIFY && KMP_DEBUG 3442 // suppress race conditions detection on synchronization flags in debug mode 3443 // this helps to analyze library internals eliminating false positives 3444 __itt_suppress_mark_range( 3445 __itt_suppress_range, __itt_suppress_threading_errors, 3446 &task_team->tt.tt_found_tasks, sizeof(task_team->tt.tt_found_tasks)); 3447 __itt_suppress_mark_range(__itt_suppress_range, 3448 __itt_suppress_threading_errors, 3449 CCAST(kmp_uint32 *, &task_team->tt.tt_active), 3450 sizeof(task_team->tt.tt_active)); 3451 #endif /* USE_ITT_BUILD && USE_ITT_NOTIFY && KMP_DEBUG */ 3452 // Note: __kmp_allocate zeroes returned memory, othewise we would need: 3453 // task_team->tt.tt_threads_data = NULL; 3454 // task_team->tt.tt_max_threads = 0; 3455 // task_team->tt.tt_next = NULL; 3456 } 3457 3458 TCW_4(task_team->tt.tt_found_tasks, FALSE); 3459 TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE); 3460 task_team->tt.tt_nproc = nthreads = team->t.t_nproc; 3461 3462 KMP_ATOMIC_ST_REL(&task_team->tt.tt_unfinished_threads, nthreads); 3463 TCW_4(task_team->tt.tt_hidden_helper_task_encountered, FALSE); 3464 TCW_4(task_team->tt.tt_active, TRUE); 3465 3466 KA_TRACE(20, ("__kmp_allocate_task_team: T#%d exiting; task_team = %p " 3467 "unfinished_threads init'd to %d\n", 3468 (thread ? __kmp_gtid_from_thread(thread) : -1), task_team, 3469 KMP_ATOMIC_LD_RLX(&task_team->tt.tt_unfinished_threads))); 3470 return task_team; 3471 } 3472 3473 // __kmp_free_task_team: 3474 // Frees the task team associated with a specific thread, and adds it 3475 // to the global task team free list. 3476 void __kmp_free_task_team(kmp_info_t *thread, kmp_task_team_t *task_team) { 3477 KA_TRACE(20, ("__kmp_free_task_team: T#%d task_team = %p\n", 3478 thread ? __kmp_gtid_from_thread(thread) : -1, task_team)); 3479 3480 // Put task team back on free list 3481 __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock); 3482 3483 KMP_DEBUG_ASSERT(task_team->tt.tt_next == NULL); 3484 task_team->tt.tt_next = __kmp_free_task_teams; 3485 TCW_PTR(__kmp_free_task_teams, task_team); 3486 3487 __kmp_release_bootstrap_lock(&__kmp_task_team_lock); 3488 } 3489 3490 // __kmp_reap_task_teams: 3491 // Free all the task teams on the task team free list. 3492 // Should only be done during library shutdown. 3493 // Cannot do anything that needs a thread structure or gtid since they are 3494 // already gone. 3495 void __kmp_reap_task_teams(void) { 3496 kmp_task_team_t *task_team; 3497 3498 if (TCR_PTR(__kmp_free_task_teams) != NULL) { 3499 // Free all task_teams on the free list 3500 __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock); 3501 while ((task_team = __kmp_free_task_teams) != NULL) { 3502 __kmp_free_task_teams = task_team->tt.tt_next; 3503 task_team->tt.tt_next = NULL; 3504 3505 // Free threads_data if necessary 3506 if (task_team->tt.tt_threads_data != NULL) { 3507 __kmp_free_task_threads_data(task_team); 3508 } 3509 __kmp_free(task_team); 3510 } 3511 __kmp_release_bootstrap_lock(&__kmp_task_team_lock); 3512 } 3513 } 3514 3515 // __kmp_wait_to_unref_task_teams: 3516 // Some threads could still be in the fork barrier release code, possibly 3517 // trying to steal tasks. Wait for each thread to unreference its task team. 3518 void __kmp_wait_to_unref_task_teams(void) { 3519 kmp_info_t *thread; 3520 kmp_uint32 spins; 3521 int done; 3522 3523 KMP_INIT_YIELD(spins); 3524 3525 for (;;) { 3526 done = TRUE; 3527 3528 // TODO: GEH - this may be is wrong because some sync would be necessary 3529 // in case threads are added to the pool during the traversal. Need to 3530 // verify that lock for thread pool is held when calling this routine. 3531 for (thread = CCAST(kmp_info_t *, __kmp_thread_pool); thread != NULL; 3532 thread = thread->th.th_next_pool) { 3533 #if KMP_OS_WINDOWS 3534 DWORD exit_val; 3535 #endif 3536 if (TCR_PTR(thread->th.th_task_team) == NULL) { 3537 KA_TRACE(10, ("__kmp_wait_to_unref_task_team: T#%d task_team == NULL\n", 3538 __kmp_gtid_from_thread(thread))); 3539 continue; 3540 } 3541 #if KMP_OS_WINDOWS 3542 // TODO: GEH - add this check for Linux* OS / OS X* as well? 3543 if (!__kmp_is_thread_alive(thread, &exit_val)) { 3544 thread->th.th_task_team = NULL; 3545 continue; 3546 } 3547 #endif 3548 3549 done = FALSE; // Because th_task_team pointer is not NULL for this thread 3550 3551 KA_TRACE(10, ("__kmp_wait_to_unref_task_team: Waiting for T#%d to " 3552 "unreference task_team\n", 3553 __kmp_gtid_from_thread(thread))); 3554 3555 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) { 3556 volatile void *sleep_loc; 3557 // If the thread is sleeping, awaken it. 3558 if ((sleep_loc = TCR_PTR(CCAST(void *, thread->th.th_sleep_loc))) != 3559 NULL) { 3560 KA_TRACE( 3561 10, 3562 ("__kmp_wait_to_unref_task_team: T#%d waking up thread T#%d\n", 3563 __kmp_gtid_from_thread(thread), __kmp_gtid_from_thread(thread))); 3564 __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc); 3565 } 3566 } 3567 } 3568 if (done) { 3569 break; 3570 } 3571 3572 // If oversubscribed or have waited a bit, yield. 3573 KMP_YIELD_OVERSUB_ELSE_SPIN(spins); 3574 } 3575 } 3576 3577 // __kmp_task_team_setup: Create a task_team for the current team, but use 3578 // an already created, unused one if it already exists. 3579 void __kmp_task_team_setup(kmp_info_t *this_thr, kmp_team_t *team, int always) { 3580 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 3581 3582 // If this task_team hasn't been created yet, allocate it. It will be used in 3583 // the region after the next. 3584 // If it exists, it is the current task team and shouldn't be touched yet as 3585 // it may still be in use. 3586 if (team->t.t_task_team[this_thr->th.th_task_state] == NULL && 3587 (always || team->t.t_nproc > 1)) { 3588 team->t.t_task_team[this_thr->th.th_task_state] = 3589 __kmp_allocate_task_team(this_thr, team); 3590 KA_TRACE(20, ("__kmp_task_team_setup: Primary T#%d created new task_team %p" 3591 " for team %d at parity=%d\n", 3592 __kmp_gtid_from_thread(this_thr), 3593 team->t.t_task_team[this_thr->th.th_task_state], team->t.t_id, 3594 this_thr->th.th_task_state)); 3595 } 3596 3597 // After threads exit the release, they will call sync, and then point to this 3598 // other task_team; make sure it is allocated and properly initialized. As 3599 // threads spin in the barrier release phase, they will continue to use the 3600 // previous task_team struct(above), until they receive the signal to stop 3601 // checking for tasks (they can't safely reference the kmp_team_t struct, 3602 // which could be reallocated by the primary thread). No task teams are formed 3603 // for serialized teams. 3604 if (team->t.t_nproc > 1) { 3605 int other_team = 1 - this_thr->th.th_task_state; 3606 KMP_DEBUG_ASSERT(other_team >= 0 && other_team < 2); 3607 if (team->t.t_task_team[other_team] == NULL) { // setup other team as well 3608 team->t.t_task_team[other_team] = 3609 __kmp_allocate_task_team(this_thr, team); 3610 KA_TRACE(20, ("__kmp_task_team_setup: Primary T#%d created second new " 3611 "task_team %p for team %d at parity=%d\n", 3612 __kmp_gtid_from_thread(this_thr), 3613 team->t.t_task_team[other_team], team->t.t_id, other_team)); 3614 } else { // Leave the old task team struct in place for the upcoming region; 3615 // adjust as needed 3616 kmp_task_team_t *task_team = team->t.t_task_team[other_team]; 3617 if (!task_team->tt.tt_active || 3618 team->t.t_nproc != task_team->tt.tt_nproc) { 3619 TCW_4(task_team->tt.tt_nproc, team->t.t_nproc); 3620 TCW_4(task_team->tt.tt_found_tasks, FALSE); 3621 TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE); 3622 KMP_ATOMIC_ST_REL(&task_team->tt.tt_unfinished_threads, 3623 team->t.t_nproc); 3624 TCW_4(task_team->tt.tt_active, TRUE); 3625 } 3626 // if team size has changed, the first thread to enable tasking will 3627 // realloc threads_data if necessary 3628 KA_TRACE(20, ("__kmp_task_team_setup: Primary T#%d reset next task_team " 3629 "%p for team %d at parity=%d\n", 3630 __kmp_gtid_from_thread(this_thr), 3631 team->t.t_task_team[other_team], team->t.t_id, other_team)); 3632 } 3633 } 3634 3635 // For regular thread, task enabling should be called when the task is going 3636 // to be pushed to a dequeue. However, for the hidden helper thread, we need 3637 // it ahead of time so that some operations can be performed without race 3638 // condition. 3639 if (this_thr == __kmp_hidden_helper_main_thread) { 3640 for (int i = 0; i < 2; ++i) { 3641 kmp_task_team_t *task_team = team->t.t_task_team[i]; 3642 if (KMP_TASKING_ENABLED(task_team)) { 3643 continue; 3644 } 3645 __kmp_enable_tasking(task_team, this_thr); 3646 for (int j = 0; j < task_team->tt.tt_nproc; ++j) { 3647 kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[j]; 3648 if (thread_data->td.td_deque == NULL) { 3649 __kmp_alloc_task_deque(__kmp_hidden_helper_threads[j], thread_data); 3650 } 3651 } 3652 } 3653 } 3654 } 3655 3656 // __kmp_task_team_sync: Propagation of task team data from team to threads 3657 // which happens just after the release phase of a team barrier. This may be 3658 // called by any thread, but only for teams with # threads > 1. 3659 void __kmp_task_team_sync(kmp_info_t *this_thr, kmp_team_t *team) { 3660 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 3661 3662 // Toggle the th_task_state field, to switch which task_team this thread 3663 // refers to 3664 this_thr->th.th_task_state = (kmp_uint8)(1 - this_thr->th.th_task_state); 3665 3666 // It is now safe to propagate the task team pointer from the team struct to 3667 // the current thread. 3668 TCW_PTR(this_thr->th.th_task_team, 3669 team->t.t_task_team[this_thr->th.th_task_state]); 3670 KA_TRACE(20, 3671 ("__kmp_task_team_sync: Thread T#%d task team switched to task_team " 3672 "%p from Team #%d (parity=%d)\n", 3673 __kmp_gtid_from_thread(this_thr), this_thr->th.th_task_team, 3674 team->t.t_id, this_thr->th.th_task_state)); 3675 } 3676 3677 // __kmp_task_team_wait: Primary thread waits for outstanding tasks after the 3678 // barrier gather phase. Only called by primary thread if #threads in team > 1 3679 // or if proxy tasks were created. 3680 // 3681 // wait is a flag that defaults to 1 (see kmp.h), but waiting can be turned off 3682 // by passing in 0 optionally as the last argument. When wait is zero, primary 3683 // thread does not wait for unfinished_threads to reach 0. 3684 void __kmp_task_team_wait( 3685 kmp_info_t *this_thr, 3686 kmp_team_t *team USE_ITT_BUILD_ARG(void *itt_sync_obj), int wait) { 3687 kmp_task_team_t *task_team = team->t.t_task_team[this_thr->th.th_task_state]; 3688 3689 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 3690 KMP_DEBUG_ASSERT(task_team == this_thr->th.th_task_team); 3691 3692 if ((task_team != NULL) && KMP_TASKING_ENABLED(task_team)) { 3693 if (wait) { 3694 KA_TRACE(20, ("__kmp_task_team_wait: Primary T#%d waiting for all tasks " 3695 "(for unfinished_threads to reach 0) on task_team = %p\n", 3696 __kmp_gtid_from_thread(this_thr), task_team)); 3697 // Worker threads may have dropped through to release phase, but could 3698 // still be executing tasks. Wait here for tasks to complete. To avoid 3699 // memory contention, only primary thread checks termination condition. 3700 kmp_flag_32<false, false> flag( 3701 RCAST(std::atomic<kmp_uint32> *, 3702 &task_team->tt.tt_unfinished_threads), 3703 0U); 3704 flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj)); 3705 } 3706 // Deactivate the old task team, so that the worker threads will stop 3707 // referencing it while spinning. 3708 KA_TRACE( 3709 20, 3710 ("__kmp_task_team_wait: Primary T#%d deactivating task_team %p: " 3711 "setting active to false, setting local and team's pointer to NULL\n", 3712 __kmp_gtid_from_thread(this_thr), task_team)); 3713 KMP_DEBUG_ASSERT(task_team->tt.tt_nproc > 1 || 3714 task_team->tt.tt_found_proxy_tasks == TRUE); 3715 TCW_SYNC_4(task_team->tt.tt_found_proxy_tasks, FALSE); 3716 KMP_CHECK_UPDATE(task_team->tt.tt_untied_task_encountered, 0); 3717 TCW_SYNC_4(task_team->tt.tt_active, FALSE); 3718 KMP_MB(); 3719 3720 TCW_PTR(this_thr->th.th_task_team, NULL); 3721 } 3722 } 3723 3724 // __kmp_tasking_barrier: 3725 // This routine is called only when __kmp_tasking_mode == tskm_extra_barrier. 3726 // Internal function to execute all tasks prior to a regular barrier or a join 3727 // barrier. It is a full barrier itself, which unfortunately turns regular 3728 // barriers into double barriers and join barriers into 1 1/2 barriers. 3729 void __kmp_tasking_barrier(kmp_team_t *team, kmp_info_t *thread, int gtid) { 3730 std::atomic<kmp_uint32> *spin = RCAST( 3731 std::atomic<kmp_uint32> *, 3732 &team->t.t_task_team[thread->th.th_task_state]->tt.tt_unfinished_threads); 3733 int flag = FALSE; 3734 KMP_DEBUG_ASSERT(__kmp_tasking_mode == tskm_extra_barrier); 3735 3736 #if USE_ITT_BUILD 3737 KMP_FSYNC_SPIN_INIT(spin, NULL); 3738 #endif /* USE_ITT_BUILD */ 3739 kmp_flag_32<false, false> spin_flag(spin, 0U); 3740 while (!spin_flag.execute_tasks(thread, gtid, TRUE, 3741 &flag USE_ITT_BUILD_ARG(NULL), 0)) { 3742 #if USE_ITT_BUILD 3743 // TODO: What about itt_sync_obj?? 3744 KMP_FSYNC_SPIN_PREPARE(RCAST(void *, spin)); 3745 #endif /* USE_ITT_BUILD */ 3746 3747 if (TCR_4(__kmp_global.g.g_done)) { 3748 if (__kmp_global.g.g_abort) 3749 __kmp_abort_thread(); 3750 break; 3751 } 3752 KMP_YIELD(TRUE); 3753 } 3754 #if USE_ITT_BUILD 3755 KMP_FSYNC_SPIN_ACQUIRED(RCAST(void *, spin)); 3756 #endif /* USE_ITT_BUILD */ 3757 } 3758 3759 // __kmp_give_task puts a task into a given thread queue if: 3760 // - the queue for that thread was created 3761 // - there's space in that queue 3762 // Because of this, __kmp_push_task needs to check if there's space after 3763 // getting the lock 3764 static bool __kmp_give_task(kmp_info_t *thread, kmp_int32 tid, kmp_task_t *task, 3765 kmp_int32 pass) { 3766 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 3767 kmp_task_team_t *task_team = taskdata->td_task_team; 3768 3769 KA_TRACE(20, ("__kmp_give_task: trying to give task %p to thread %d.\n", 3770 taskdata, tid)); 3771 3772 // If task_team is NULL something went really bad... 3773 KMP_DEBUG_ASSERT(task_team != NULL); 3774 3775 bool result = false; 3776 kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid]; 3777 3778 if (thread_data->td.td_deque == NULL) { 3779 // There's no queue in this thread, go find another one 3780 // We're guaranteed that at least one thread has a queue 3781 KA_TRACE(30, 3782 ("__kmp_give_task: thread %d has no queue while giving task %p.\n", 3783 tid, taskdata)); 3784 return result; 3785 } 3786 3787 if (TCR_4(thread_data->td.td_deque_ntasks) >= 3788 TASK_DEQUE_SIZE(thread_data->td)) { 3789 KA_TRACE( 3790 30, 3791 ("__kmp_give_task: queue is full while giving task %p to thread %d.\n", 3792 taskdata, tid)); 3793 3794 // if this deque is bigger than the pass ratio give a chance to another 3795 // thread 3796 if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass) 3797 return result; 3798 3799 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 3800 if (TCR_4(thread_data->td.td_deque_ntasks) >= 3801 TASK_DEQUE_SIZE(thread_data->td)) { 3802 // expand deque to push the task which is not allowed to execute 3803 __kmp_realloc_task_deque(thread, thread_data); 3804 } 3805 3806 } else { 3807 3808 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 3809 3810 if (TCR_4(thread_data->td.td_deque_ntasks) >= 3811 TASK_DEQUE_SIZE(thread_data->td)) { 3812 KA_TRACE(30, ("__kmp_give_task: queue is full while giving task %p to " 3813 "thread %d.\n", 3814 taskdata, tid)); 3815 3816 // if this deque is bigger than the pass ratio give a chance to another 3817 // thread 3818 if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass) 3819 goto release_and_exit; 3820 3821 __kmp_realloc_task_deque(thread, thread_data); 3822 } 3823 } 3824 3825 // lock is held here, and there is space in the deque 3826 3827 thread_data->td.td_deque[thread_data->td.td_deque_tail] = taskdata; 3828 // Wrap index. 3829 thread_data->td.td_deque_tail = 3830 (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td); 3831 TCW_4(thread_data->td.td_deque_ntasks, 3832 TCR_4(thread_data->td.td_deque_ntasks) + 1); 3833 3834 result = true; 3835 KA_TRACE(30, ("__kmp_give_task: successfully gave task %p to thread %d.\n", 3836 taskdata, tid)); 3837 3838 release_and_exit: 3839 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 3840 3841 return result; 3842 } 3843 3844 /* The finish of the proxy tasks is divided in two pieces: 3845 - the top half is the one that can be done from a thread outside the team 3846 - the bottom half must be run from a thread within the team 3847 3848 In order to run the bottom half the task gets queued back into one of the 3849 threads of the team. Once the td_incomplete_child_task counter of the parent 3850 is decremented the threads can leave the barriers. So, the bottom half needs 3851 to be queued before the counter is decremented. The top half is therefore 3852 divided in two parts: 3853 - things that can be run before queuing the bottom half 3854 - things that must be run after queuing the bottom half 3855 3856 This creates a second race as the bottom half can free the task before the 3857 second top half is executed. To avoid this we use the 3858 td_incomplete_child_task of the proxy task to synchronize the top and bottom 3859 half. */ 3860 static void __kmp_first_top_half_finish_proxy(kmp_taskdata_t *taskdata) { 3861 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 3862 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 3863 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0); 3864 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 3865 3866 taskdata->td_flags.complete = 1; // mark the task as completed 3867 3868 if (taskdata->td_taskgroup) 3869 KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count); 3870 3871 // Create an imaginary children for this task so the bottom half cannot 3872 // release the task before we have completed the second top half 3873 KMP_ATOMIC_INC(&taskdata->td_incomplete_child_tasks); 3874 } 3875 3876 static void __kmp_second_top_half_finish_proxy(kmp_taskdata_t *taskdata) { 3877 kmp_int32 children = 0; 3878 3879 // Predecrement simulated by "- 1" calculation 3880 children = 3881 KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks) - 1; 3882 KMP_DEBUG_ASSERT(children >= 0); 3883 3884 // Remove the imaginary children 3885 KMP_ATOMIC_DEC(&taskdata->td_incomplete_child_tasks); 3886 } 3887 3888 static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask) { 3889 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask); 3890 kmp_info_t *thread = __kmp_threads[gtid]; 3891 3892 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 3893 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 3894 1); // top half must run before bottom half 3895 3896 // We need to wait to make sure the top half is finished 3897 // Spinning here should be ok as this should happen quickly 3898 while (KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) > 0) 3899 ; 3900 3901 __kmp_release_deps(gtid, taskdata); 3902 __kmp_free_task_and_ancestors(gtid, taskdata, thread); 3903 } 3904 3905 /*! 3906 @ingroup TASKING 3907 @param gtid Global Thread ID of encountering thread 3908 @param ptask Task which execution is completed 3909 3910 Execute the completion of a proxy task from a thread of that is part of the 3911 team. Run first and bottom halves directly. 3912 */ 3913 void __kmpc_proxy_task_completed(kmp_int32 gtid, kmp_task_t *ptask) { 3914 KMP_DEBUG_ASSERT(ptask != NULL); 3915 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask); 3916 KA_TRACE( 3917 10, ("__kmp_proxy_task_completed(enter): T#%d proxy task %p completing\n", 3918 gtid, taskdata)); 3919 __kmp_assert_valid_gtid(gtid); 3920 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 3921 3922 __kmp_first_top_half_finish_proxy(taskdata); 3923 __kmp_second_top_half_finish_proxy(taskdata); 3924 __kmp_bottom_half_finish_proxy(gtid, ptask); 3925 3926 KA_TRACE(10, 3927 ("__kmp_proxy_task_completed(exit): T#%d proxy task %p completing\n", 3928 gtid, taskdata)); 3929 } 3930 3931 /*! 3932 @ingroup TASKING 3933 @param ptask Task which execution is completed 3934 3935 Execute the completion of a proxy task from a thread that could not belong to 3936 the team. 3937 */ 3938 void __kmpc_proxy_task_completed_ooo(kmp_task_t *ptask) { 3939 KMP_DEBUG_ASSERT(ptask != NULL); 3940 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask); 3941 3942 KA_TRACE( 3943 10, 3944 ("__kmp_proxy_task_completed_ooo(enter): proxy task completing ooo %p\n", 3945 taskdata)); 3946 3947 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 3948 3949 __kmp_first_top_half_finish_proxy(taskdata); 3950 3951 // Enqueue task to complete bottom half completion from a thread within the 3952 // corresponding team 3953 kmp_team_t *team = taskdata->td_team; 3954 kmp_int32 nthreads = team->t.t_nproc; 3955 kmp_info_t *thread; 3956 3957 // This should be similar to start_k = __kmp_get_random( thread ) % nthreads 3958 // but we cannot use __kmp_get_random here 3959 kmp_int32 start_k = 0; 3960 kmp_int32 pass = 1; 3961 kmp_int32 k = start_k; 3962 3963 do { 3964 // For now we're just linearly trying to find a thread 3965 thread = team->t.t_threads[k]; 3966 k = (k + 1) % nthreads; 3967 3968 // we did a full pass through all the threads 3969 if (k == start_k) 3970 pass = pass << 1; 3971 3972 } while (!__kmp_give_task(thread, k, ptask, pass)); 3973 3974 __kmp_second_top_half_finish_proxy(taskdata); 3975 3976 KA_TRACE( 3977 10, 3978 ("__kmp_proxy_task_completed_ooo(exit): proxy task completing ooo %p\n", 3979 taskdata)); 3980 } 3981 3982 kmp_event_t *__kmpc_task_allow_completion_event(ident_t *loc_ref, int gtid, 3983 kmp_task_t *task) { 3984 kmp_taskdata_t *td = KMP_TASK_TO_TASKDATA(task); 3985 if (td->td_allow_completion_event.type == KMP_EVENT_UNINITIALIZED) { 3986 td->td_allow_completion_event.type = KMP_EVENT_ALLOW_COMPLETION; 3987 td->td_allow_completion_event.ed.task = task; 3988 __kmp_init_tas_lock(&td->td_allow_completion_event.lock); 3989 } 3990 return &td->td_allow_completion_event; 3991 } 3992 3993 void __kmp_fulfill_event(kmp_event_t *event) { 3994 if (event->type == KMP_EVENT_ALLOW_COMPLETION) { 3995 kmp_task_t *ptask = event->ed.task; 3996 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask); 3997 bool detached = false; 3998 int gtid = __kmp_get_gtid(); 3999 4000 // The associated task might have completed or could be completing at this 4001 // point. 4002 // We need to take the lock to avoid races 4003 __kmp_acquire_tas_lock(&event->lock, gtid); 4004 if (taskdata->td_flags.proxy == TASK_PROXY) { 4005 detached = true; 4006 } else { 4007 #if OMPT_SUPPORT 4008 // The OMPT event must occur under mutual exclusion, 4009 // otherwise the tool might access ptask after free 4010 if (UNLIKELY(ompt_enabled.enabled)) 4011 __ompt_task_finish(ptask, NULL, ompt_task_early_fulfill); 4012 #endif 4013 } 4014 event->type = KMP_EVENT_UNINITIALIZED; 4015 __kmp_release_tas_lock(&event->lock, gtid); 4016 4017 if (detached) { 4018 #if OMPT_SUPPORT 4019 // We free ptask afterwards and know the task is finished, 4020 // so locking is not necessary 4021 if (UNLIKELY(ompt_enabled.enabled)) 4022 __ompt_task_finish(ptask, NULL, ompt_task_late_fulfill); 4023 #endif 4024 // If the task detached complete the proxy task 4025 if (gtid >= 0) { 4026 kmp_team_t *team = taskdata->td_team; 4027 kmp_info_t *thread = __kmp_get_thread(); 4028 if (thread->th.th_team == team) { 4029 __kmpc_proxy_task_completed(gtid, ptask); 4030 return; 4031 } 4032 } 4033 4034 // fallback 4035 __kmpc_proxy_task_completed_ooo(ptask); 4036 } 4037 } 4038 } 4039 4040 // __kmp_task_dup_alloc: Allocate the taskdata and make a copy of source task 4041 // for taskloop 4042 // 4043 // thread: allocating thread 4044 // task_src: pointer to source task to be duplicated 4045 // returns: a pointer to the allocated kmp_task_t structure (task). 4046 kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src) { 4047 kmp_task_t *task; 4048 kmp_taskdata_t *taskdata; 4049 kmp_taskdata_t *taskdata_src = KMP_TASK_TO_TASKDATA(task_src); 4050 kmp_taskdata_t *parent_task = taskdata_src->td_parent; // same parent task 4051 size_t shareds_offset; 4052 size_t task_size; 4053 4054 KA_TRACE(10, ("__kmp_task_dup_alloc(enter): Th %p, source task %p\n", thread, 4055 task_src)); 4056 KMP_DEBUG_ASSERT(taskdata_src->td_flags.proxy == 4057 TASK_FULL); // it should not be proxy task 4058 KMP_DEBUG_ASSERT(taskdata_src->td_flags.tasktype == TASK_EXPLICIT); 4059 task_size = taskdata_src->td_size_alloc; 4060 4061 // Allocate a kmp_taskdata_t block and a kmp_task_t block. 4062 KA_TRACE(30, ("__kmp_task_dup_alloc: Th %p, malloc size %ld\n", thread, 4063 task_size)); 4064 #if USE_FAST_MEMORY 4065 taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, task_size); 4066 #else 4067 taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, task_size); 4068 #endif /* USE_FAST_MEMORY */ 4069 KMP_MEMCPY(taskdata, taskdata_src, task_size); 4070 4071 task = KMP_TASKDATA_TO_TASK(taskdata); 4072 4073 // Initialize new task (only specific fields not affected by memcpy) 4074 taskdata->td_task_id = KMP_GEN_TASK_ID(); 4075 if (task->shareds != NULL) { // need setup shareds pointer 4076 shareds_offset = (char *)task_src->shareds - (char *)taskdata_src; 4077 task->shareds = &((char *)taskdata)[shareds_offset]; 4078 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) == 4079 0); 4080 } 4081 taskdata->td_alloc_thread = thread; 4082 taskdata->td_parent = parent_task; 4083 // task inherits the taskgroup from the parent task 4084 taskdata->td_taskgroup = parent_task->td_taskgroup; 4085 // tied task needs to initialize the td_last_tied at creation, 4086 // untied one does this when it is scheduled for execution 4087 if (taskdata->td_flags.tiedness == TASK_TIED) 4088 taskdata->td_last_tied = taskdata; 4089 4090 // Only need to keep track of child task counts if team parallel and tasking 4091 // not serialized 4092 if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) { 4093 KMP_ATOMIC_INC(&parent_task->td_incomplete_child_tasks); 4094 if (parent_task->td_taskgroup) 4095 KMP_ATOMIC_INC(&parent_task->td_taskgroup->count); 4096 // Only need to keep track of allocated child tasks for explicit tasks since 4097 // implicit not deallocated 4098 if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT) 4099 KMP_ATOMIC_INC(&taskdata->td_parent->td_allocated_child_tasks); 4100 } 4101 4102 KA_TRACE(20, 4103 ("__kmp_task_dup_alloc(exit): Th %p, created task %p, parent=%p\n", 4104 thread, taskdata, taskdata->td_parent)); 4105 #if OMPT_SUPPORT 4106 if (UNLIKELY(ompt_enabled.enabled)) 4107 __ompt_task_init(taskdata, thread->th.th_info.ds.ds_gtid); 4108 #endif 4109 return task; 4110 } 4111 4112 // Routine optionally generated by the compiler for setting the lastprivate flag 4113 // and calling needed constructors for private/firstprivate objects 4114 // (used to form taskloop tasks from pattern task) 4115 // Parameters: dest task, src task, lastprivate flag. 4116 typedef void (*p_task_dup_t)(kmp_task_t *, kmp_task_t *, kmp_int32); 4117 4118 KMP_BUILD_ASSERT(sizeof(long) == 4 || sizeof(long) == 8); 4119 4120 // class to encapsulate manipulating loop bounds in a taskloop task. 4121 // this abstracts away the Intel vs GOMP taskloop interface for setting/getting 4122 // the loop bound variables. 4123 class kmp_taskloop_bounds_t { 4124 kmp_task_t *task; 4125 const kmp_taskdata_t *taskdata; 4126 size_t lower_offset; 4127 size_t upper_offset; 4128 4129 public: 4130 kmp_taskloop_bounds_t(kmp_task_t *_task, kmp_uint64 *lb, kmp_uint64 *ub) 4131 : task(_task), taskdata(KMP_TASK_TO_TASKDATA(task)), 4132 lower_offset((char *)lb - (char *)task), 4133 upper_offset((char *)ub - (char *)task) { 4134 KMP_DEBUG_ASSERT((char *)lb > (char *)_task); 4135 KMP_DEBUG_ASSERT((char *)ub > (char *)_task); 4136 } 4137 kmp_taskloop_bounds_t(kmp_task_t *_task, const kmp_taskloop_bounds_t &bounds) 4138 : task(_task), taskdata(KMP_TASK_TO_TASKDATA(_task)), 4139 lower_offset(bounds.lower_offset), upper_offset(bounds.upper_offset) {} 4140 size_t get_lower_offset() const { return lower_offset; } 4141 size_t get_upper_offset() const { return upper_offset; } 4142 kmp_uint64 get_lb() const { 4143 kmp_int64 retval; 4144 #if defined(KMP_GOMP_COMPAT) 4145 // Intel task just returns the lower bound normally 4146 if (!taskdata->td_flags.native) { 4147 retval = *(kmp_int64 *)((char *)task + lower_offset); 4148 } else { 4149 // GOMP task has to take into account the sizeof(long) 4150 if (taskdata->td_size_loop_bounds == 4) { 4151 kmp_int32 *lb = RCAST(kmp_int32 *, task->shareds); 4152 retval = (kmp_int64)*lb; 4153 } else { 4154 kmp_int64 *lb = RCAST(kmp_int64 *, task->shareds); 4155 retval = (kmp_int64)*lb; 4156 } 4157 } 4158 #else 4159 (void)taskdata; 4160 retval = *(kmp_int64 *)((char *)task + lower_offset); 4161 #endif // defined(KMP_GOMP_COMPAT) 4162 return retval; 4163 } 4164 kmp_uint64 get_ub() const { 4165 kmp_int64 retval; 4166 #if defined(KMP_GOMP_COMPAT) 4167 // Intel task just returns the upper bound normally 4168 if (!taskdata->td_flags.native) { 4169 retval = *(kmp_int64 *)((char *)task + upper_offset); 4170 } else { 4171 // GOMP task has to take into account the sizeof(long) 4172 if (taskdata->td_size_loop_bounds == 4) { 4173 kmp_int32 *ub = RCAST(kmp_int32 *, task->shareds) + 1; 4174 retval = (kmp_int64)*ub; 4175 } else { 4176 kmp_int64 *ub = RCAST(kmp_int64 *, task->shareds) + 1; 4177 retval = (kmp_int64)*ub; 4178 } 4179 } 4180 #else 4181 retval = *(kmp_int64 *)((char *)task + upper_offset); 4182 #endif // defined(KMP_GOMP_COMPAT) 4183 return retval; 4184 } 4185 void set_lb(kmp_uint64 lb) { 4186 #if defined(KMP_GOMP_COMPAT) 4187 // Intel task just sets the lower bound normally 4188 if (!taskdata->td_flags.native) { 4189 *(kmp_uint64 *)((char *)task + lower_offset) = lb; 4190 } else { 4191 // GOMP task has to take into account the sizeof(long) 4192 if (taskdata->td_size_loop_bounds == 4) { 4193 kmp_uint32 *lower = RCAST(kmp_uint32 *, task->shareds); 4194 *lower = (kmp_uint32)lb; 4195 } else { 4196 kmp_uint64 *lower = RCAST(kmp_uint64 *, task->shareds); 4197 *lower = (kmp_uint64)lb; 4198 } 4199 } 4200 #else 4201 *(kmp_uint64 *)((char *)task + lower_offset) = lb; 4202 #endif // defined(KMP_GOMP_COMPAT) 4203 } 4204 void set_ub(kmp_uint64 ub) { 4205 #if defined(KMP_GOMP_COMPAT) 4206 // Intel task just sets the upper bound normally 4207 if (!taskdata->td_flags.native) { 4208 *(kmp_uint64 *)((char *)task + upper_offset) = ub; 4209 } else { 4210 // GOMP task has to take into account the sizeof(long) 4211 if (taskdata->td_size_loop_bounds == 4) { 4212 kmp_uint32 *upper = RCAST(kmp_uint32 *, task->shareds) + 1; 4213 *upper = (kmp_uint32)ub; 4214 } else { 4215 kmp_uint64 *upper = RCAST(kmp_uint64 *, task->shareds) + 1; 4216 *upper = (kmp_uint64)ub; 4217 } 4218 } 4219 #else 4220 *(kmp_uint64 *)((char *)task + upper_offset) = ub; 4221 #endif // defined(KMP_GOMP_COMPAT) 4222 } 4223 }; 4224 4225 // __kmp_taskloop_linear: Start tasks of the taskloop linearly 4226 // 4227 // loc Source location information 4228 // gtid Global thread ID 4229 // task Pattern task, exposes the loop iteration range 4230 // lb Pointer to loop lower bound in task structure 4231 // ub Pointer to loop upper bound in task structure 4232 // st Loop stride 4233 // ub_glob Global upper bound (used for lastprivate check) 4234 // num_tasks Number of tasks to execute 4235 // grainsize Number of loop iterations per task 4236 // extras Number of chunks with grainsize+1 iterations 4237 // last_chunk Reduction of grainsize for last task 4238 // tc Iterations count 4239 // task_dup Tasks duplication routine 4240 // codeptr_ra Return address for OMPT events 4241 void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task, 4242 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, 4243 kmp_uint64 ub_glob, kmp_uint64 num_tasks, 4244 kmp_uint64 grainsize, kmp_uint64 extras, 4245 kmp_int64 last_chunk, kmp_uint64 tc, 4246 #if OMPT_SUPPORT 4247 void *codeptr_ra, 4248 #endif 4249 void *task_dup) { 4250 KMP_COUNT_BLOCK(OMP_TASKLOOP); 4251 KMP_TIME_PARTITIONED_BLOCK(OMP_taskloop_scheduling); 4252 p_task_dup_t ptask_dup = (p_task_dup_t)task_dup; 4253 // compiler provides global bounds here 4254 kmp_taskloop_bounds_t task_bounds(task, lb, ub); 4255 kmp_uint64 lower = task_bounds.get_lb(); 4256 kmp_uint64 upper = task_bounds.get_ub(); 4257 kmp_uint64 i; 4258 kmp_info_t *thread = __kmp_threads[gtid]; 4259 kmp_taskdata_t *current_task = thread->th.th_current_task; 4260 kmp_task_t *next_task; 4261 kmp_int32 lastpriv = 0; 4262 4263 KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + 4264 (last_chunk < 0 ? last_chunk : extras)); 4265 KMP_DEBUG_ASSERT(num_tasks > extras); 4266 KMP_DEBUG_ASSERT(num_tasks > 0); 4267 KA_TRACE(20, ("__kmp_taskloop_linear: T#%d: %lld tasks, grainsize %lld, " 4268 "extras %lld, last_chunk %lld, i=%lld,%lld(%d)%lld, dup %p\n", 4269 gtid, num_tasks, grainsize, extras, last_chunk, lower, upper, 4270 ub_glob, st, task_dup)); 4271 4272 // Launch num_tasks tasks, assign grainsize iterations each task 4273 for (i = 0; i < num_tasks; ++i) { 4274 kmp_uint64 chunk_minus_1; 4275 if (extras == 0) { 4276 chunk_minus_1 = grainsize - 1; 4277 } else { 4278 chunk_minus_1 = grainsize; 4279 --extras; // first extras iterations get bigger chunk (grainsize+1) 4280 } 4281 upper = lower + st * chunk_minus_1; 4282 if (upper > *ub) { 4283 upper = *ub; 4284 } 4285 if (i == num_tasks - 1) { 4286 // schedule the last task, set lastprivate flag if needed 4287 if (st == 1) { // most common case 4288 KMP_DEBUG_ASSERT(upper == *ub); 4289 if (upper == ub_glob) 4290 lastpriv = 1; 4291 } else if (st > 0) { // positive loop stride 4292 KMP_DEBUG_ASSERT((kmp_uint64)st > *ub - upper); 4293 if ((kmp_uint64)st > ub_glob - upper) 4294 lastpriv = 1; 4295 } else { // negative loop stride 4296 KMP_DEBUG_ASSERT(upper + st < *ub); 4297 if (upper - ub_glob < (kmp_uint64)(-st)) 4298 lastpriv = 1; 4299 } 4300 } 4301 next_task = __kmp_task_dup_alloc(thread, task); // allocate new task 4302 kmp_taskdata_t *next_taskdata = KMP_TASK_TO_TASKDATA(next_task); 4303 kmp_taskloop_bounds_t next_task_bounds = 4304 kmp_taskloop_bounds_t(next_task, task_bounds); 4305 4306 // adjust task-specific bounds 4307 next_task_bounds.set_lb(lower); 4308 if (next_taskdata->td_flags.native) { 4309 next_task_bounds.set_ub(upper + (st > 0 ? 1 : -1)); 4310 } else { 4311 next_task_bounds.set_ub(upper); 4312 } 4313 if (ptask_dup != NULL) // set lastprivate flag, construct firstprivates, 4314 // etc. 4315 ptask_dup(next_task, task, lastpriv); 4316 KA_TRACE(40, 4317 ("__kmp_taskloop_linear: T#%d; task #%llu: task %p: lower %lld, " 4318 "upper %lld stride %lld, (offsets %p %p)\n", 4319 gtid, i, next_task, lower, upper, st, 4320 next_task_bounds.get_lower_offset(), 4321 next_task_bounds.get_upper_offset())); 4322 #if OMPT_SUPPORT 4323 __kmp_omp_taskloop_task(NULL, gtid, next_task, 4324 codeptr_ra); // schedule new task 4325 #else 4326 __kmp_omp_task(gtid, next_task, true); // schedule new task 4327 #endif 4328 lower = upper + st; // adjust lower bound for the next iteration 4329 } 4330 // free the pattern task and exit 4331 __kmp_task_start(gtid, task, current_task); // make internal bookkeeping 4332 // do not execute the pattern task, just do internal bookkeeping 4333 __kmp_task_finish<false>(gtid, task, current_task); 4334 } 4335 4336 // Structure to keep taskloop parameters for auxiliary task 4337 // kept in the shareds of the task structure. 4338 typedef struct __taskloop_params { 4339 kmp_task_t *task; 4340 kmp_uint64 *lb; 4341 kmp_uint64 *ub; 4342 void *task_dup; 4343 kmp_int64 st; 4344 kmp_uint64 ub_glob; 4345 kmp_uint64 num_tasks; 4346 kmp_uint64 grainsize; 4347 kmp_uint64 extras; 4348 kmp_int64 last_chunk; 4349 kmp_uint64 tc; 4350 kmp_uint64 num_t_min; 4351 #if OMPT_SUPPORT 4352 void *codeptr_ra; 4353 #endif 4354 } __taskloop_params_t; 4355 4356 void __kmp_taskloop_recur(ident_t *, int, kmp_task_t *, kmp_uint64 *, 4357 kmp_uint64 *, kmp_int64, kmp_uint64, kmp_uint64, 4358 kmp_uint64, kmp_uint64, kmp_int64, kmp_uint64, 4359 kmp_uint64, 4360 #if OMPT_SUPPORT 4361 void *, 4362 #endif 4363 void *); 4364 4365 // Execute part of the taskloop submitted as a task. 4366 int __kmp_taskloop_task(int gtid, void *ptask) { 4367 __taskloop_params_t *p = 4368 (__taskloop_params_t *)((kmp_task_t *)ptask)->shareds; 4369 kmp_task_t *task = p->task; 4370 kmp_uint64 *lb = p->lb; 4371 kmp_uint64 *ub = p->ub; 4372 void *task_dup = p->task_dup; 4373 // p_task_dup_t ptask_dup = (p_task_dup_t)task_dup; 4374 kmp_int64 st = p->st; 4375 kmp_uint64 ub_glob = p->ub_glob; 4376 kmp_uint64 num_tasks = p->num_tasks; 4377 kmp_uint64 grainsize = p->grainsize; 4378 kmp_uint64 extras = p->extras; 4379 kmp_int64 last_chunk = p->last_chunk; 4380 kmp_uint64 tc = p->tc; 4381 kmp_uint64 num_t_min = p->num_t_min; 4382 #if OMPT_SUPPORT 4383 void *codeptr_ra = p->codeptr_ra; 4384 #endif 4385 #if KMP_DEBUG 4386 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 4387 KMP_DEBUG_ASSERT(task != NULL); 4388 KA_TRACE(20, 4389 ("__kmp_taskloop_task: T#%d, task %p: %lld tasks, grainsize" 4390 " %lld, extras %lld, last_chunk %lld, i=%lld,%lld(%d), dup %p\n", 4391 gtid, taskdata, num_tasks, grainsize, extras, last_chunk, *lb, *ub, 4392 st, task_dup)); 4393 #endif 4394 KMP_DEBUG_ASSERT(num_tasks * 2 + 1 > num_t_min); 4395 if (num_tasks > num_t_min) 4396 __kmp_taskloop_recur(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks, 4397 grainsize, extras, last_chunk, tc, num_t_min, 4398 #if OMPT_SUPPORT 4399 codeptr_ra, 4400 #endif 4401 task_dup); 4402 else 4403 __kmp_taskloop_linear(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks, 4404 grainsize, extras, last_chunk, tc, 4405 #if OMPT_SUPPORT 4406 codeptr_ra, 4407 #endif 4408 task_dup); 4409 4410 KA_TRACE(40, ("__kmp_taskloop_task(exit): T#%d\n", gtid)); 4411 return 0; 4412 } 4413 4414 // Schedule part of the taskloop as a task, 4415 // execute the rest of the taskloop. 4416 // 4417 // loc Source location information 4418 // gtid Global thread ID 4419 // task Pattern task, exposes the loop iteration range 4420 // lb Pointer to loop lower bound in task structure 4421 // ub Pointer to loop upper bound in task structure 4422 // st Loop stride 4423 // ub_glob Global upper bound (used for lastprivate check) 4424 // num_tasks Number of tasks to execute 4425 // grainsize Number of loop iterations per task 4426 // extras Number of chunks with grainsize+1 iterations 4427 // last_chunk Reduction of grainsize for last task 4428 // tc Iterations count 4429 // num_t_min Threshold to launch tasks recursively 4430 // task_dup Tasks duplication routine 4431 // codeptr_ra Return address for OMPT events 4432 void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task, 4433 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, 4434 kmp_uint64 ub_glob, kmp_uint64 num_tasks, 4435 kmp_uint64 grainsize, kmp_uint64 extras, 4436 kmp_int64 last_chunk, kmp_uint64 tc, 4437 kmp_uint64 num_t_min, 4438 #if OMPT_SUPPORT 4439 void *codeptr_ra, 4440 #endif 4441 void *task_dup) { 4442 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 4443 KMP_DEBUG_ASSERT(task != NULL); 4444 KMP_DEBUG_ASSERT(num_tasks > num_t_min); 4445 KA_TRACE(20, 4446 ("__kmp_taskloop_recur: T#%d, task %p: %lld tasks, grainsize" 4447 " %lld, extras %lld, last_chunk %lld, i=%lld,%lld(%d), dup %p\n", 4448 gtid, taskdata, num_tasks, grainsize, extras, last_chunk, *lb, *ub, 4449 st, task_dup)); 4450 p_task_dup_t ptask_dup = (p_task_dup_t)task_dup; 4451 kmp_uint64 lower = *lb; 4452 kmp_info_t *thread = __kmp_threads[gtid]; 4453 // kmp_taskdata_t *current_task = thread->th.th_current_task; 4454 kmp_task_t *next_task; 4455 size_t lower_offset = 4456 (char *)lb - (char *)task; // remember offset of lb in the task structure 4457 size_t upper_offset = 4458 (char *)ub - (char *)task; // remember offset of ub in the task structure 4459 4460 KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + 4461 (last_chunk < 0 ? last_chunk : extras)); 4462 KMP_DEBUG_ASSERT(num_tasks > extras); 4463 KMP_DEBUG_ASSERT(num_tasks > 0); 4464 4465 // split the loop in two halves 4466 kmp_uint64 lb1, ub0, tc0, tc1, ext0, ext1; 4467 kmp_int64 last_chunk0 = 0, last_chunk1 = 0; 4468 kmp_uint64 gr_size0 = grainsize; 4469 kmp_uint64 n_tsk0 = num_tasks >> 1; // num_tasks/2 to execute 4470 kmp_uint64 n_tsk1 = num_tasks - n_tsk0; // to schedule as a task 4471 if (last_chunk < 0) { 4472 ext0 = ext1 = 0; 4473 last_chunk1 = last_chunk; 4474 tc0 = grainsize * n_tsk0; 4475 tc1 = tc - tc0; 4476 } else if (n_tsk0 <= extras) { 4477 gr_size0++; // integrate extras into grainsize 4478 ext0 = 0; // no extra iters in 1st half 4479 ext1 = extras - n_tsk0; // remaining extras 4480 tc0 = gr_size0 * n_tsk0; 4481 tc1 = tc - tc0; 4482 } else { // n_tsk0 > extras 4483 ext1 = 0; // no extra iters in 2nd half 4484 ext0 = extras; 4485 tc1 = grainsize * n_tsk1; 4486 tc0 = tc - tc1; 4487 } 4488 ub0 = lower + st * (tc0 - 1); 4489 lb1 = ub0 + st; 4490 4491 // create pattern task for 2nd half of the loop 4492 next_task = __kmp_task_dup_alloc(thread, task); // duplicate the task 4493 // adjust lower bound (upper bound is not changed) for the 2nd half 4494 *(kmp_uint64 *)((char *)next_task + lower_offset) = lb1; 4495 if (ptask_dup != NULL) // construct firstprivates, etc. 4496 ptask_dup(next_task, task, 0); 4497 *ub = ub0; // adjust upper bound for the 1st half 4498 4499 // create auxiliary task for 2nd half of the loop 4500 // make sure new task has same parent task as the pattern task 4501 kmp_taskdata_t *current_task = thread->th.th_current_task; 4502 thread->th.th_current_task = taskdata->td_parent; 4503 kmp_task_t *new_task = 4504 __kmpc_omp_task_alloc(loc, gtid, 1, 3 * sizeof(void *), 4505 sizeof(__taskloop_params_t), &__kmp_taskloop_task); 4506 // restore current task 4507 thread->th.th_current_task = current_task; 4508 __taskloop_params_t *p = (__taskloop_params_t *)new_task->shareds; 4509 p->task = next_task; 4510 p->lb = (kmp_uint64 *)((char *)next_task + lower_offset); 4511 p->ub = (kmp_uint64 *)((char *)next_task + upper_offset); 4512 p->task_dup = task_dup; 4513 p->st = st; 4514 p->ub_glob = ub_glob; 4515 p->num_tasks = n_tsk1; 4516 p->grainsize = grainsize; 4517 p->extras = ext1; 4518 p->last_chunk = last_chunk1; 4519 p->tc = tc1; 4520 p->num_t_min = num_t_min; 4521 #if OMPT_SUPPORT 4522 p->codeptr_ra = codeptr_ra; 4523 #endif 4524 4525 #if OMPT_SUPPORT 4526 // schedule new task with correct return address for OMPT events 4527 __kmp_omp_taskloop_task(NULL, gtid, new_task, codeptr_ra); 4528 #else 4529 __kmp_omp_task(gtid, new_task, true); // schedule new task 4530 #endif 4531 4532 // execute the 1st half of current subrange 4533 if (n_tsk0 > num_t_min) 4534 __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0, gr_size0, 4535 ext0, last_chunk0, tc0, num_t_min, 4536 #if OMPT_SUPPORT 4537 codeptr_ra, 4538 #endif 4539 task_dup); 4540 else 4541 __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0, 4542 gr_size0, ext0, last_chunk0, tc0, 4543 #if OMPT_SUPPORT 4544 codeptr_ra, 4545 #endif 4546 task_dup); 4547 4548 KA_TRACE(40, ("__kmp_taskloop_recur(exit): T#%d\n", gtid)); 4549 } 4550 4551 static void __kmp_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, 4552 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, 4553 int nogroup, int sched, kmp_uint64 grainsize, 4554 int modifier, void *task_dup) { 4555 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 4556 KMP_DEBUG_ASSERT(task != NULL); 4557 if (nogroup == 0) { 4558 #if OMPT_SUPPORT && OMPT_OPTIONAL 4559 OMPT_STORE_RETURN_ADDRESS(gtid); 4560 #endif 4561 __kmpc_taskgroup(loc, gtid); 4562 } 4563 4564 // ========================================================================= 4565 // calculate loop parameters 4566 kmp_taskloop_bounds_t task_bounds(task, lb, ub); 4567 kmp_uint64 tc; 4568 // compiler provides global bounds here 4569 kmp_uint64 lower = task_bounds.get_lb(); 4570 kmp_uint64 upper = task_bounds.get_ub(); 4571 kmp_uint64 ub_glob = upper; // global upper used to calc lastprivate flag 4572 kmp_uint64 num_tasks = 0, extras = 0; 4573 kmp_int64 last_chunk = 4574 0; // reduce grainsize of last task by last_chunk in strict mode 4575 kmp_uint64 num_tasks_min = __kmp_taskloop_min_tasks; 4576 kmp_info_t *thread = __kmp_threads[gtid]; 4577 kmp_taskdata_t *current_task = thread->th.th_current_task; 4578 4579 KA_TRACE(20, ("__kmp_taskloop: T#%d, task %p, lb %lld, ub %lld, st %lld, " 4580 "grain %llu(%d, %d), dup %p\n", 4581 gtid, taskdata, lower, upper, st, grainsize, sched, modifier, 4582 task_dup)); 4583 4584 // compute trip count 4585 if (st == 1) { // most common case 4586 tc = upper - lower + 1; 4587 } else if (st < 0) { 4588 tc = (lower - upper) / (-st) + 1; 4589 } else { // st > 0 4590 tc = (upper - lower) / st + 1; 4591 } 4592 if (tc == 0) { 4593 KA_TRACE(20, ("__kmp_taskloop(exit): T#%d zero-trip loop\n", gtid)); 4594 // free the pattern task and exit 4595 __kmp_task_start(gtid, task, current_task); 4596 // do not execute anything for zero-trip loop 4597 __kmp_task_finish<false>(gtid, task, current_task); 4598 return; 4599 } 4600 4601 #if OMPT_SUPPORT && OMPT_OPTIONAL 4602 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL); 4603 ompt_task_info_t *task_info = __ompt_get_task_info_object(0); 4604 if (ompt_enabled.ompt_callback_work) { 4605 ompt_callbacks.ompt_callback(ompt_callback_work)( 4606 ompt_work_taskloop, ompt_scope_begin, &(team_info->parallel_data), 4607 &(task_info->task_data), tc, OMPT_GET_RETURN_ADDRESS(0)); 4608 } 4609 #endif 4610 4611 if (num_tasks_min == 0) 4612 // TODO: can we choose better default heuristic? 4613 num_tasks_min = 4614 KMP_MIN(thread->th.th_team_nproc * 10, INITIAL_TASK_DEQUE_SIZE); 4615 4616 // compute num_tasks/grainsize based on the input provided 4617 switch (sched) { 4618 case 0: // no schedule clause specified, we can choose the default 4619 // let's try to schedule (team_size*10) tasks 4620 grainsize = thread->th.th_team_nproc * 10; 4621 KMP_FALLTHROUGH(); 4622 case 2: // num_tasks provided 4623 if (grainsize > tc) { 4624 num_tasks = tc; // too big num_tasks requested, adjust values 4625 grainsize = 1; 4626 extras = 0; 4627 } else { 4628 num_tasks = grainsize; 4629 grainsize = tc / num_tasks; 4630 extras = tc % num_tasks; 4631 } 4632 break; 4633 case 1: // grainsize provided 4634 if (grainsize > tc) { 4635 num_tasks = 1; 4636 grainsize = tc; // too big grainsize requested, adjust values 4637 extras = 0; 4638 } else { 4639 if (modifier) { 4640 num_tasks = (tc + grainsize - 1) / grainsize; 4641 last_chunk = tc - (num_tasks * grainsize); 4642 extras = 0; 4643 } else { 4644 num_tasks = tc / grainsize; 4645 // adjust grainsize for balanced distribution of iterations 4646 grainsize = tc / num_tasks; 4647 extras = tc % num_tasks; 4648 } 4649 } 4650 break; 4651 default: 4652 KMP_ASSERT2(0, "unknown scheduling of taskloop"); 4653 } 4654 4655 KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + 4656 (last_chunk < 0 ? last_chunk : extras)); 4657 KMP_DEBUG_ASSERT(num_tasks > extras); 4658 KMP_DEBUG_ASSERT(num_tasks > 0); 4659 // ========================================================================= 4660 4661 // check if clause value first 4662 // Also require GOMP_taskloop to reduce to linear (taskdata->td_flags.native) 4663 if (if_val == 0) { // if(0) specified, mark task as serial 4664 taskdata->td_flags.task_serial = 1; 4665 taskdata->td_flags.tiedness = TASK_TIED; // AC: serial task cannot be untied 4666 // always start serial tasks linearly 4667 __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks, 4668 grainsize, extras, last_chunk, tc, 4669 #if OMPT_SUPPORT 4670 OMPT_GET_RETURN_ADDRESS(0), 4671 #endif 4672 task_dup); 4673 // !taskdata->td_flags.native => currently force linear spawning of tasks 4674 // for GOMP_taskloop 4675 } else if (num_tasks > num_tasks_min && !taskdata->td_flags.native) { 4676 KA_TRACE(20, ("__kmp_taskloop: T#%d, go recursive: tc %llu, #tasks %llu" 4677 "(%lld), grain %llu, extras %llu, last_chunk %lld\n", 4678 gtid, tc, num_tasks, num_tasks_min, grainsize, extras, 4679 last_chunk)); 4680 __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, num_tasks, 4681 grainsize, extras, last_chunk, tc, num_tasks_min, 4682 #if OMPT_SUPPORT 4683 OMPT_GET_RETURN_ADDRESS(0), 4684 #endif 4685 task_dup); 4686 } else { 4687 KA_TRACE(20, ("__kmp_taskloop: T#%d, go linear: tc %llu, #tasks %llu" 4688 "(%lld), grain %llu, extras %llu, last_chunk %lld\n", 4689 gtid, tc, num_tasks, num_tasks_min, grainsize, extras, 4690 last_chunk)); 4691 __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks, 4692 grainsize, extras, last_chunk, tc, 4693 #if OMPT_SUPPORT 4694 OMPT_GET_RETURN_ADDRESS(0), 4695 #endif 4696 task_dup); 4697 } 4698 4699 #if OMPT_SUPPORT && OMPT_OPTIONAL 4700 if (ompt_enabled.ompt_callback_work) { 4701 ompt_callbacks.ompt_callback(ompt_callback_work)( 4702 ompt_work_taskloop, ompt_scope_end, &(team_info->parallel_data), 4703 &(task_info->task_data), tc, OMPT_GET_RETURN_ADDRESS(0)); 4704 } 4705 #endif 4706 4707 if (nogroup == 0) { 4708 #if OMPT_SUPPORT && OMPT_OPTIONAL 4709 OMPT_STORE_RETURN_ADDRESS(gtid); 4710 #endif 4711 __kmpc_end_taskgroup(loc, gtid); 4712 } 4713 KA_TRACE(20, ("__kmp_taskloop(exit): T#%d\n", gtid)); 4714 } 4715 4716 /*! 4717 @ingroup TASKING 4718 @param loc Source location information 4719 @param gtid Global thread ID 4720 @param task Task structure 4721 @param if_val Value of the if clause 4722 @param lb Pointer to loop lower bound in task structure 4723 @param ub Pointer to loop upper bound in task structure 4724 @param st Loop stride 4725 @param nogroup Flag, 1 if nogroup clause specified, 0 otherwise 4726 @param sched Schedule specified 0/1/2 for none/grainsize/num_tasks 4727 @param grainsize Schedule value if specified 4728 @param task_dup Tasks duplication routine 4729 4730 Execute the taskloop construct. 4731 */ 4732 void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, 4733 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, 4734 int sched, kmp_uint64 grainsize, void *task_dup) { 4735 __kmp_assert_valid_gtid(gtid); 4736 KA_TRACE(20, ("__kmpc_taskloop(enter): T#%d\n", gtid)); 4737 __kmp_taskloop(loc, gtid, task, if_val, lb, ub, st, nogroup, sched, grainsize, 4738 0, task_dup); 4739 KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d\n", gtid)); 4740 } 4741 4742 /*! 4743 @ingroup TASKING 4744 @param loc Source location information 4745 @param gtid Global thread ID 4746 @param task Task structure 4747 @param if_val Value of the if clause 4748 @param lb Pointer to loop lower bound in task structure 4749 @param ub Pointer to loop upper bound in task structure 4750 @param st Loop stride 4751 @param nogroup Flag, 1 if nogroup clause specified, 0 otherwise 4752 @param sched Schedule specified 0/1/2 for none/grainsize/num_tasks 4753 @param grainsize Schedule value if specified 4754 @param modifer Modifier 'strict' for sched, 1 if present, 0 otherwise 4755 @param task_dup Tasks duplication routine 4756 4757 Execute the taskloop construct. 4758 */ 4759 void __kmpc_taskloop_5(ident_t *loc, int gtid, kmp_task_t *task, int if_val, 4760 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, 4761 int nogroup, int sched, kmp_uint64 grainsize, 4762 int modifier, void *task_dup) { 4763 __kmp_assert_valid_gtid(gtid); 4764 KA_TRACE(20, ("__kmpc_taskloop_5(enter): T#%d\n", gtid)); 4765 __kmp_taskloop(loc, gtid, task, if_val, lb, ub, st, nogroup, sched, grainsize, 4766 modifier, task_dup); 4767 KA_TRACE(20, ("__kmpc_taskloop_5(exit): T#%d\n", gtid)); 4768 } 4769