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