17cc577a4SJonathan Peyton /* 2de4749b7SJonathan Peyton * kmp_tasking.cpp -- OpenMP 3.0 tasking support. 37cc577a4SJonathan Peyton */ 47cc577a4SJonathan Peyton 57cc577a4SJonathan Peyton 67cc577a4SJonathan Peyton //===----------------------------------------------------------------------===// 77cc577a4SJonathan Peyton // 87cc577a4SJonathan Peyton // The LLVM Compiler Infrastructure 97cc577a4SJonathan Peyton // 107cc577a4SJonathan Peyton // This file is dual licensed under the MIT and the University of Illinois Open 117cc577a4SJonathan Peyton // Source Licenses. See LICENSE.txt for details. 127cc577a4SJonathan Peyton // 137cc577a4SJonathan Peyton //===----------------------------------------------------------------------===// 147cc577a4SJonathan Peyton 157cc577a4SJonathan Peyton 167cc577a4SJonathan Peyton #include "kmp.h" 177cc577a4SJonathan Peyton #include "kmp_i18n.h" 187cc577a4SJonathan Peyton #include "kmp_itt.h" 197cc577a4SJonathan Peyton #include "kmp_stats.h" 20*3041982dSJonathan Peyton #include "kmp_wait_release.h" 217cc577a4SJonathan Peyton 227cc577a4SJonathan Peyton #if OMPT_SUPPORT 237cc577a4SJonathan Peyton #include "ompt-specific.h" 247cc577a4SJonathan Peyton #endif 257cc577a4SJonathan Peyton 267cc577a4SJonathan Peyton #include "tsan_annotations.h" 277cc577a4SJonathan Peyton 287cc577a4SJonathan Peyton /* forward declaration */ 29*3041982dSJonathan Peyton static void __kmp_enable_tasking(kmp_task_team_t *task_team, 30*3041982dSJonathan Peyton kmp_info_t *this_thr); 31*3041982dSJonathan Peyton static void __kmp_alloc_task_deque(kmp_info_t *thread, 32*3041982dSJonathan Peyton kmp_thread_data_t *thread_data); 33*3041982dSJonathan Peyton static int __kmp_realloc_task_threads_data(kmp_info_t *thread, 34*3041982dSJonathan Peyton kmp_task_team_t *task_team); 357cc577a4SJonathan Peyton 367cc577a4SJonathan Peyton #ifdef OMP_45_ENABLED 377cc577a4SJonathan Peyton static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask); 387cc577a4SJonathan Peyton #endif 397cc577a4SJonathan Peyton 407cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK 417cc577a4SJonathan Peyton 427cc577a4SJonathan Peyton // __kmp_trace_task_stack: print the tied tasks from the task stack in order 437cc577a4SJonathan Peyton // from top do bottom 447cc577a4SJonathan Peyton // 457cc577a4SJonathan Peyton // gtid: global thread identifier for thread containing stack 467cc577a4SJonathan Peyton // thread_data: thread data for task team thread containing stack 477cc577a4SJonathan Peyton // threshold: value above which the trace statement triggers 487cc577a4SJonathan Peyton // location: string identifying call site of this function (for trace) 49*3041982dSJonathan Peyton static void __kmp_trace_task_stack(kmp_int32 gtid, 50*3041982dSJonathan Peyton kmp_thread_data_t *thread_data, 51*3041982dSJonathan Peyton int threshold, char *location) { 527cc577a4SJonathan Peyton kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 537cc577a4SJonathan Peyton kmp_taskdata_t **stack_top = task_stack->ts_top; 547cc577a4SJonathan Peyton kmp_int32 entries = task_stack->ts_entries; 557cc577a4SJonathan Peyton kmp_taskdata_t *tied_task; 567cc577a4SJonathan Peyton 57*3041982dSJonathan Peyton KA_TRACE( 58*3041982dSJonathan Peyton threshold, 59*3041982dSJonathan Peyton ("__kmp_trace_task_stack(start): location = %s, gtid = %d, entries = %d, " 607cc577a4SJonathan Peyton "first_block = %p, stack_top = %p \n", 617cc577a4SJonathan Peyton location, gtid, entries, task_stack->ts_first_block, stack_top)); 627cc577a4SJonathan Peyton 637cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(stack_top != NULL); 647cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(entries > 0); 657cc577a4SJonathan Peyton 66*3041982dSJonathan Peyton while (entries != 0) { 677cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(stack_top != &task_stack->ts_first_block.sb_block[0]); 687cc577a4SJonathan Peyton // fix up ts_top if we need to pop from previous block 69*3041982dSJonathan Peyton if (entries & TASK_STACK_INDEX_MASK == 0) { 707cc577a4SJonathan Peyton kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(stack_top); 717cc577a4SJonathan Peyton 727cc577a4SJonathan Peyton stack_block = stack_block->sb_prev; 737cc577a4SJonathan Peyton stack_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE]; 747cc577a4SJonathan Peyton } 757cc577a4SJonathan Peyton 767cc577a4SJonathan Peyton // finish bookkeeping 777cc577a4SJonathan Peyton stack_top--; 787cc577a4SJonathan Peyton entries--; 797cc577a4SJonathan Peyton 807cc577a4SJonathan Peyton tied_task = *stack_top; 817cc577a4SJonathan Peyton 827cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(tied_task != NULL); 837cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED); 847cc577a4SJonathan Peyton 85*3041982dSJonathan Peyton KA_TRACE(threshold, 86*3041982dSJonathan Peyton ("__kmp_trace_task_stack(%s): gtid=%d, entry=%d, " 877cc577a4SJonathan Peyton "stack_top=%p, tied_task=%p\n", 887cc577a4SJonathan Peyton location, gtid, entries, stack_top, tied_task)); 897cc577a4SJonathan Peyton } 907cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(stack_top == &task_stack->ts_first_block.sb_block[0]); 917cc577a4SJonathan Peyton 92*3041982dSJonathan Peyton KA_TRACE(threshold, 93*3041982dSJonathan Peyton ("__kmp_trace_task_stack(exit): location = %s, gtid = %d\n", 947cc577a4SJonathan Peyton location, gtid)); 957cc577a4SJonathan Peyton } 967cc577a4SJonathan Peyton 977cc577a4SJonathan Peyton // __kmp_init_task_stack: initialize the task stack for the first time 987cc577a4SJonathan Peyton // after a thread_data structure is created. 997cc577a4SJonathan Peyton // It should not be necessary to do this again (assuming the stack works). 1007cc577a4SJonathan Peyton // 1017cc577a4SJonathan Peyton // gtid: global thread identifier of calling thread 1027cc577a4SJonathan Peyton // thread_data: thread data for task team thread containing stack 103*3041982dSJonathan Peyton static void __kmp_init_task_stack(kmp_int32 gtid, 104*3041982dSJonathan Peyton kmp_thread_data_t *thread_data) { 1057cc577a4SJonathan Peyton kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 1067cc577a4SJonathan Peyton kmp_stack_block_t *first_block; 1077cc577a4SJonathan Peyton 1087cc577a4SJonathan Peyton // set up the first block of the stack 1097cc577a4SJonathan Peyton first_block = &task_stack->ts_first_block; 1107cc577a4SJonathan Peyton task_stack->ts_top = (kmp_taskdata_t **)first_block; 111*3041982dSJonathan Peyton memset((void *)first_block, '\0', 112*3041982dSJonathan Peyton TASK_STACK_BLOCK_SIZE * sizeof(kmp_taskdata_t *)); 1137cc577a4SJonathan Peyton 1147cc577a4SJonathan Peyton // initialize the stack to be empty 1157cc577a4SJonathan Peyton task_stack->ts_entries = TASK_STACK_EMPTY; 1167cc577a4SJonathan Peyton first_block->sb_next = NULL; 1177cc577a4SJonathan Peyton first_block->sb_prev = NULL; 1187cc577a4SJonathan Peyton } 1197cc577a4SJonathan Peyton 1207cc577a4SJonathan Peyton // __kmp_free_task_stack: free the task stack when thread_data is destroyed. 1217cc577a4SJonathan Peyton // 1227cc577a4SJonathan Peyton // gtid: global thread identifier for calling thread 1237cc577a4SJonathan Peyton // thread_data: thread info for thread containing stack 124*3041982dSJonathan Peyton static void __kmp_free_task_stack(kmp_int32 gtid, 125*3041982dSJonathan Peyton kmp_thread_data_t *thread_data) { 1267cc577a4SJonathan Peyton kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 1277cc577a4SJonathan Peyton kmp_stack_block_t *stack_block = &task_stack->ts_first_block; 1287cc577a4SJonathan Peyton 1297cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_stack->ts_entries == TASK_STACK_EMPTY); 1307cc577a4SJonathan Peyton // free from the second block of the stack 1317cc577a4SJonathan Peyton while (stack_block != NULL) { 1327cc577a4SJonathan Peyton kmp_stack_block_t *next_block = (stack_block) ? stack_block->sb_next : NULL; 1337cc577a4SJonathan Peyton 1347cc577a4SJonathan Peyton stack_block->sb_next = NULL; 1357cc577a4SJonathan Peyton stack_block->sb_prev = NULL; 1367cc577a4SJonathan Peyton if (stack_block != &task_stack->ts_first_block) { 137*3041982dSJonathan Peyton __kmp_thread_free(thread, 138*3041982dSJonathan Peyton stack_block); // free the block, if not the first 1397cc577a4SJonathan Peyton } 1407cc577a4SJonathan Peyton stack_block = next_block; 1417cc577a4SJonathan Peyton } 1427cc577a4SJonathan Peyton // initialize the stack to be empty 1437cc577a4SJonathan Peyton task_stack->ts_entries = 0; 1447cc577a4SJonathan Peyton task_stack->ts_top = NULL; 1457cc577a4SJonathan Peyton } 1467cc577a4SJonathan Peyton 1477cc577a4SJonathan Peyton // __kmp_push_task_stack: Push the tied task onto the task stack. 1487cc577a4SJonathan Peyton // Grow the stack if necessary by allocating another block. 1497cc577a4SJonathan Peyton // 1507cc577a4SJonathan Peyton // gtid: global thread identifier for calling thread 1517cc577a4SJonathan Peyton // thread: thread info for thread containing stack 1527cc577a4SJonathan Peyton // tied_task: the task to push on the stack 153*3041982dSJonathan Peyton static void __kmp_push_task_stack(kmp_int32 gtid, kmp_info_t *thread, 154*3041982dSJonathan Peyton kmp_taskdata_t *tied_task) { 1557cc577a4SJonathan Peyton // GEH - need to consider what to do if tt_threads_data not allocated yet 156*3041982dSJonathan Peyton kmp_thread_data_t *thread_data = 157*3041982dSJonathan Peyton &thread->th.th_task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)]; 1587cc577a4SJonathan Peyton kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 1597cc577a4SJonathan Peyton 1607cc577a4SJonathan Peyton if (tied_task->td_flags.team_serial || tied_task->td_flags.tasking_ser) { 1617cc577a4SJonathan Peyton return; // Don't push anything on stack if team or team tasks are serialized 1627cc577a4SJonathan Peyton } 1637cc577a4SJonathan Peyton 1647cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED); 1657cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_stack->ts_top != NULL); 1667cc577a4SJonathan Peyton 167*3041982dSJonathan Peyton KA_TRACE(20, 168*3041982dSJonathan Peyton ("__kmp_push_task_stack(enter): GTID: %d; THREAD: %p; TASK: %p\n", 1697cc577a4SJonathan Peyton gtid, thread, tied_task)); 1707cc577a4SJonathan Peyton // Store entry 1717cc577a4SJonathan Peyton *(task_stack->ts_top) = tied_task; 1727cc577a4SJonathan Peyton 1737cc577a4SJonathan Peyton // Do bookkeeping for next push 1747cc577a4SJonathan Peyton task_stack->ts_top++; 1757cc577a4SJonathan Peyton task_stack->ts_entries++; 1767cc577a4SJonathan Peyton 177*3041982dSJonathan Peyton if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) { 1787cc577a4SJonathan Peyton // Find beginning of this task block 1797cc577a4SJonathan Peyton kmp_stack_block_t *stack_block = 1807cc577a4SJonathan Peyton (kmp_stack_block_t *)(task_stack->ts_top - TASK_STACK_BLOCK_SIZE); 1817cc577a4SJonathan Peyton 1827cc577a4SJonathan Peyton // Check if we already have a block 183*3041982dSJonathan Peyton if (stack_block->sb_next != 184*3041982dSJonathan Peyton NULL) { // reset ts_top to beginning of next block 1857cc577a4SJonathan Peyton task_stack->ts_top = &stack_block->sb_next->sb_block[0]; 186*3041982dSJonathan Peyton } else { // Alloc new block and link it up 187*3041982dSJonathan Peyton kmp_stack_block_t *new_block = (kmp_stack_block_t *)__kmp_thread_calloc( 188*3041982dSJonathan Peyton thread, sizeof(kmp_stack_block_t)); 1897cc577a4SJonathan Peyton 1907cc577a4SJonathan Peyton task_stack->ts_top = &new_block->sb_block[0]; 1917cc577a4SJonathan Peyton stack_block->sb_next = new_block; 1927cc577a4SJonathan Peyton new_block->sb_prev = stack_block; 1937cc577a4SJonathan Peyton new_block->sb_next = NULL; 1947cc577a4SJonathan Peyton 195*3041982dSJonathan Peyton KA_TRACE( 196*3041982dSJonathan Peyton 30, 197*3041982dSJonathan Peyton ("__kmp_push_task_stack(): GTID: %d; TASK: %p; Alloc new block: %p\n", 1987cc577a4SJonathan Peyton gtid, tied_task, new_block)); 1997cc577a4SJonathan Peyton } 2007cc577a4SJonathan Peyton } 201*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_push_task_stack(exit): GTID: %d; TASK: %p\n", gtid, 202*3041982dSJonathan Peyton tied_task)); 2037cc577a4SJonathan Peyton } 2047cc577a4SJonathan Peyton 2057cc577a4SJonathan Peyton // __kmp_pop_task_stack: Pop the tied task from the task stack. Don't return 2067cc577a4SJonathan Peyton // the task, just check to make sure it matches the ending task passed in. 2077cc577a4SJonathan Peyton // 2087cc577a4SJonathan Peyton // gtid: global thread identifier for the calling thread 2097cc577a4SJonathan Peyton // thread: thread info structure containing stack 2107cc577a4SJonathan Peyton // tied_task: the task popped off the stack 2117cc577a4SJonathan Peyton // ending_task: the task that is ending (should match popped task) 212*3041982dSJonathan Peyton static void __kmp_pop_task_stack(kmp_int32 gtid, kmp_info_t *thread, 213*3041982dSJonathan Peyton kmp_taskdata_t *ending_task) { 2147cc577a4SJonathan Peyton // GEH - need to consider what to do if tt_threads_data not allocated yet 215*3041982dSJonathan Peyton kmp_thread_data_t *thread_data = 216*3041982dSJonathan Peyton &thread->th.th_task_team->tt_threads_data[__kmp_tid_from_gtid(gtid)]; 2177cc577a4SJonathan Peyton kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks; 2187cc577a4SJonathan Peyton kmp_taskdata_t *tied_task; 2197cc577a4SJonathan Peyton 2207cc577a4SJonathan Peyton if (ending_task->td_flags.team_serial || ending_task->td_flags.tasking_ser) { 221*3041982dSJonathan Peyton // Don't pop anything from stack if team or team tasks are serialized 222*3041982dSJonathan Peyton return; 2237cc577a4SJonathan Peyton } 2247cc577a4SJonathan Peyton 2257cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_stack->ts_top != NULL); 2267cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_stack->ts_entries > 0); 2277cc577a4SJonathan Peyton 228*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_pop_task_stack(enter): GTID: %d; THREAD: %p\n", gtid, 229*3041982dSJonathan Peyton thread)); 2307cc577a4SJonathan Peyton 2317cc577a4SJonathan Peyton // fix up ts_top if we need to pop from previous block 232*3041982dSJonathan Peyton if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) { 233*3041982dSJonathan Peyton kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(task_stack->ts_top); 2347cc577a4SJonathan Peyton 2357cc577a4SJonathan Peyton stack_block = stack_block->sb_prev; 2367cc577a4SJonathan Peyton task_stack->ts_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE]; 2377cc577a4SJonathan Peyton } 2387cc577a4SJonathan Peyton 2397cc577a4SJonathan Peyton // finish bookkeeping 2407cc577a4SJonathan Peyton task_stack->ts_top--; 2417cc577a4SJonathan Peyton task_stack->ts_entries--; 2427cc577a4SJonathan Peyton 2437cc577a4SJonathan Peyton tied_task = *(task_stack->ts_top); 2447cc577a4SJonathan Peyton 2457cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(tied_task != NULL); 2467cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED); 2477cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(tied_task == ending_task); // If we built the stack correctly 2487cc577a4SJonathan Peyton 249*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_pop_task_stack(exit): GTID: %d; TASK: %p\n", gtid, 250*3041982dSJonathan Peyton tied_task)); 2517cc577a4SJonathan Peyton return; 2527cc577a4SJonathan Peyton } 2537cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */ 2547cc577a4SJonathan Peyton 2557cc577a4SJonathan Peyton // __kmp_push_task: Add a task to the thread's deque 256*3041982dSJonathan Peyton static kmp_int32 __kmp_push_task(kmp_int32 gtid, kmp_task_t *task) { 2577cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 2587cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 2597cc577a4SJonathan Peyton kmp_task_team_t *task_team = thread->th.th_task_team; 2607cc577a4SJonathan Peyton kmp_int32 tid = __kmp_tid_from_gtid(gtid); 2617cc577a4SJonathan Peyton kmp_thread_data_t *thread_data; 2627cc577a4SJonathan Peyton 263*3041982dSJonathan Peyton KA_TRACE(20, 264*3041982dSJonathan Peyton ("__kmp_push_task: T#%d trying to push task %p.\n", gtid, taskdata)); 2657cc577a4SJonathan Peyton 2667cc577a4SJonathan Peyton if (taskdata->td_flags.tiedness == TASK_UNTIED) { 267*3041982dSJonathan Peyton // untied task needs to increment counter so that the task structure is not 268*3041982dSJonathan Peyton // freed prematurely 2697cc577a4SJonathan Peyton kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count); 270*3041982dSJonathan Peyton KA_TRACE( 271*3041982dSJonathan Peyton 20, 272*3041982dSJonathan Peyton ("__kmp_push_task: T#%d untied_count (%d) incremented for task %p\n", 2737cc577a4SJonathan Peyton gtid, counter, taskdata)); 2747cc577a4SJonathan Peyton } 2757cc577a4SJonathan Peyton 2767cc577a4SJonathan Peyton // The first check avoids building task_team thread data if serialized 2777cc577a4SJonathan Peyton if (taskdata->td_flags.task_serial) { 278*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_push_task: T#%d team serialized; returning " 279*3041982dSJonathan Peyton "TASK_NOT_PUSHED for task %p\n", 2807cc577a4SJonathan Peyton gtid, taskdata)); 2817cc577a4SJonathan Peyton return TASK_NOT_PUSHED; 2827cc577a4SJonathan Peyton } 2837cc577a4SJonathan Peyton 284*3041982dSJonathan Peyton // Now that serialized tasks have returned, we can assume that we are not in 285*3041982dSJonathan Peyton // immediate exec mode 2867cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 2877cc577a4SJonathan Peyton if (!KMP_TASKING_ENABLED(task_team)) { 2887cc577a4SJonathan Peyton __kmp_enable_tasking(task_team, thread); 2897cc577a4SJonathan Peyton } 2907cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(TCR_4(task_team->tt.tt_found_tasks) == TRUE); 2917cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(TCR_PTR(task_team->tt.tt_threads_data) != NULL); 2927cc577a4SJonathan Peyton 2937cc577a4SJonathan Peyton // Find tasking deque specific to encountering thread 2947cc577a4SJonathan Peyton thread_data = &task_team->tt.tt_threads_data[tid]; 2957cc577a4SJonathan Peyton 2967cc577a4SJonathan Peyton // No lock needed since only owner can allocate 2977cc577a4SJonathan Peyton if (thread_data->td.td_deque == NULL) { 2987cc577a4SJonathan Peyton __kmp_alloc_task_deque(thread, thread_data); 2997cc577a4SJonathan Peyton } 3007cc577a4SJonathan Peyton 3017cc577a4SJonathan Peyton // Check if deque is full 302*3041982dSJonathan Peyton if (TCR_4(thread_data->td.td_deque_ntasks) >= 303*3041982dSJonathan Peyton TASK_DEQUE_SIZE(thread_data->td)) { 304*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_push_task: T#%d deque is full; returning " 305*3041982dSJonathan Peyton "TASK_NOT_PUSHED for task %p\n", 3067cc577a4SJonathan Peyton gtid, taskdata)); 3077cc577a4SJonathan Peyton return TASK_NOT_PUSHED; 3087cc577a4SJonathan Peyton } 3097cc577a4SJonathan Peyton 3107cc577a4SJonathan Peyton // Lock the deque for the task push operation 3117cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 3127cc577a4SJonathan Peyton 3137cc577a4SJonathan Peyton #if OMP_45_ENABLED 3147cc577a4SJonathan Peyton // Need to recheck as we can get a proxy task from a thread outside of OpenMP 315*3041982dSJonathan Peyton if (TCR_4(thread_data->td.td_deque_ntasks) >= 316*3041982dSJonathan Peyton TASK_DEQUE_SIZE(thread_data->td)) { 3177cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 318*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_push_task: T#%d deque is full on 2nd check; returning " 319*3041982dSJonathan Peyton "TASK_NOT_PUSHED for task %p\n", 3207cc577a4SJonathan Peyton gtid, taskdata)); 3217cc577a4SJonathan Peyton return TASK_NOT_PUSHED; 3227cc577a4SJonathan Peyton } 3237cc577a4SJonathan Peyton #else 3247cc577a4SJonathan Peyton // Must have room since no thread can add tasks but calling thread 325*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) < 326*3041982dSJonathan Peyton TASK_DEQUE_SIZE(thread_data->td)); 3277cc577a4SJonathan Peyton #endif 3287cc577a4SJonathan Peyton 329*3041982dSJonathan Peyton thread_data->td.td_deque[thread_data->td.td_deque_tail] = 330*3041982dSJonathan Peyton taskdata; // Push taskdata 3317cc577a4SJonathan Peyton // Wrap index. 332*3041982dSJonathan Peyton thread_data->td.td_deque_tail = 333*3041982dSJonathan Peyton (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td); 334*3041982dSJonathan Peyton TCW_4(thread_data->td.td_deque_ntasks, 335*3041982dSJonathan Peyton TCR_4(thread_data->td.td_deque_ntasks) + 1); // Adjust task count 3367cc577a4SJonathan Peyton 3377cc577a4SJonathan Peyton KA_TRACE(20, ("__kmp_push_task: T#%d returning TASK_SUCCESSFULLY_PUSHED: " 3387cc577a4SJonathan Peyton "task=%p ntasks=%d head=%u tail=%u\n", 3397cc577a4SJonathan Peyton gtid, taskdata, thread_data->td.td_deque_ntasks, 3407cc577a4SJonathan Peyton thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 3417cc577a4SJonathan Peyton 3427cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 3437cc577a4SJonathan Peyton 3447cc577a4SJonathan Peyton return TASK_SUCCESSFULLY_PUSHED; 3457cc577a4SJonathan Peyton } 3467cc577a4SJonathan Peyton 347*3041982dSJonathan Peyton // __kmp_pop_current_task_from_thread: set up current task from called thread 348*3041982dSJonathan Peyton // when team ends 349*3041982dSJonathan Peyton // 3507cc577a4SJonathan Peyton // this_thr: thread structure to set current_task in. 351*3041982dSJonathan Peyton void __kmp_pop_current_task_from_thread(kmp_info_t *this_thr) { 352*3041982dSJonathan Peyton KF_TRACE(10, ("__kmp_pop_current_task_from_thread(enter): T#%d " 353*3041982dSJonathan Peyton "this_thread=%p, curtask=%p, " 3547cc577a4SJonathan Peyton "curtask_parent=%p\n", 3557cc577a4SJonathan Peyton 0, this_thr, this_thr->th.th_current_task, 3567cc577a4SJonathan Peyton this_thr->th.th_current_task->td_parent)); 3577cc577a4SJonathan Peyton 3587cc577a4SJonathan Peyton this_thr->th.th_current_task = this_thr->th.th_current_task->td_parent; 3597cc577a4SJonathan Peyton 360*3041982dSJonathan Peyton KF_TRACE(10, ("__kmp_pop_current_task_from_thread(exit): T#%d " 361*3041982dSJonathan Peyton "this_thread=%p, curtask=%p, " 3627cc577a4SJonathan Peyton "curtask_parent=%p\n", 3637cc577a4SJonathan Peyton 0, this_thr, this_thr->th.th_current_task, 3647cc577a4SJonathan Peyton this_thr->th.th_current_task->td_parent)); 3657cc577a4SJonathan Peyton } 3667cc577a4SJonathan Peyton 367*3041982dSJonathan Peyton // __kmp_push_current_task_to_thread: set up current task in called thread for a 368*3041982dSJonathan Peyton // new team 369*3041982dSJonathan Peyton // 3707cc577a4SJonathan Peyton // this_thr: thread structure to set up 3717cc577a4SJonathan Peyton // team: team for implicit task data 3727cc577a4SJonathan Peyton // tid: thread within team to set up 373*3041982dSJonathan Peyton void __kmp_push_current_task_to_thread(kmp_info_t *this_thr, kmp_team_t *team, 374*3041982dSJonathan Peyton int tid) { 375*3041982dSJonathan Peyton // current task of the thread is a parent of the new just created implicit 376*3041982dSJonathan Peyton // tasks of new team 377*3041982dSJonathan Peyton KF_TRACE(10, ("__kmp_push_current_task_to_thread(enter): T#%d this_thread=%p " 378*3041982dSJonathan Peyton "curtask=%p " 3797cc577a4SJonathan Peyton "parent_task=%p\n", 3807cc577a4SJonathan Peyton tid, this_thr, this_thr->th.th_current_task, 3817cc577a4SJonathan Peyton team->t.t_implicit_task_taskdata[tid].td_parent)); 3827cc577a4SJonathan Peyton 3837cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(this_thr != NULL); 3847cc577a4SJonathan Peyton 3857cc577a4SJonathan Peyton if (tid == 0) { 3867cc577a4SJonathan Peyton if (this_thr->th.th_current_task != &team->t.t_implicit_task_taskdata[0]) { 387*3041982dSJonathan Peyton team->t.t_implicit_task_taskdata[0].td_parent = 388*3041982dSJonathan Peyton this_thr->th.th_current_task; 3897cc577a4SJonathan Peyton this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[0]; 3907cc577a4SJonathan Peyton } 3917cc577a4SJonathan Peyton } else { 392*3041982dSJonathan Peyton team->t.t_implicit_task_taskdata[tid].td_parent = 393*3041982dSJonathan Peyton team->t.t_implicit_task_taskdata[0].td_parent; 3947cc577a4SJonathan Peyton this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[tid]; 3957cc577a4SJonathan Peyton } 3967cc577a4SJonathan Peyton 397*3041982dSJonathan Peyton KF_TRACE(10, ("__kmp_push_current_task_to_thread(exit): T#%d this_thread=%p " 398*3041982dSJonathan Peyton "curtask=%p " 3997cc577a4SJonathan Peyton "parent_task=%p\n", 4007cc577a4SJonathan Peyton tid, this_thr, this_thr->th.th_current_task, 4017cc577a4SJonathan Peyton team->t.t_implicit_task_taskdata[tid].td_parent)); 4027cc577a4SJonathan Peyton } 4037cc577a4SJonathan Peyton 4047cc577a4SJonathan Peyton // __kmp_task_start: bookkeeping for a task starting execution 405*3041982dSJonathan Peyton // 4067cc577a4SJonathan Peyton // GTID: global thread id of calling thread 4077cc577a4SJonathan Peyton // task: task starting execution 4087cc577a4SJonathan Peyton // current_task: task suspending 409*3041982dSJonathan Peyton static void __kmp_task_start(kmp_int32 gtid, kmp_task_t *task, 410*3041982dSJonathan Peyton kmp_taskdata_t *current_task) { 4117cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 4127cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 4137cc577a4SJonathan Peyton 414*3041982dSJonathan Peyton KA_TRACE(10, 415*3041982dSJonathan Peyton ("__kmp_task_start(enter): T#%d starting task %p: current_task=%p\n", 4167cc577a4SJonathan Peyton gtid, taskdata, current_task)); 4177cc577a4SJonathan Peyton 4187cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 4197cc577a4SJonathan Peyton 4207cc577a4SJonathan Peyton // mark currently executing task as suspended 4217cc577a4SJonathan Peyton // TODO: GEH - make sure root team implicit task is initialized properly. 4227cc577a4SJonathan Peyton // KMP_DEBUG_ASSERT( current_task -> td_flags.executing == 1 ); 4237cc577a4SJonathan Peyton current_task->td_flags.executing = 0; 4247cc577a4SJonathan Peyton 4257cc577a4SJonathan Peyton // Add task to stack if tied 4267cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK 427*3041982dSJonathan Peyton if (taskdata->td_flags.tiedness == TASK_TIED) { 4287cc577a4SJonathan Peyton __kmp_push_task_stack(gtid, thread, taskdata); 4297cc577a4SJonathan Peyton } 4307cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */ 4317cc577a4SJonathan Peyton 4327cc577a4SJonathan Peyton // mark starting task as executing and as current task 4337cc577a4SJonathan Peyton thread->th.th_current_task = taskdata; 4347cc577a4SJonathan Peyton 435*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.started == 0 || 436*3041982dSJonathan Peyton taskdata->td_flags.tiedness == TASK_UNTIED); 437*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0 || 438*3041982dSJonathan Peyton taskdata->td_flags.tiedness == TASK_UNTIED); 4397cc577a4SJonathan Peyton taskdata->td_flags.started = 1; 4407cc577a4SJonathan Peyton taskdata->td_flags.executing = 1; 4417cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0); 4427cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 4437cc577a4SJonathan Peyton 4447cc577a4SJonathan Peyton // GEH TODO: shouldn't we pass some sort of location identifier here? 4457cc577a4SJonathan Peyton // APT: yes, we will pass location here. 4467cc577a4SJonathan Peyton // need to store current thread state (in a thread or taskdata structure) 4477cc577a4SJonathan Peyton // before setting work_state, otherwise wrong state is set after end of task 4487cc577a4SJonathan Peyton 449*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_task_start(exit): T#%d task=%p\n", gtid, taskdata)); 4507cc577a4SJonathan Peyton 4517cc577a4SJonathan Peyton #if OMPT_SUPPORT 452*3041982dSJonathan Peyton if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_begin)) { 4537cc577a4SJonathan Peyton kmp_taskdata_t *parent = taskdata->td_parent; 4547cc577a4SJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_task_begin)( 4557cc577a4SJonathan Peyton parent ? parent->ompt_task_info.task_id : ompt_task_id_none, 4567cc577a4SJonathan Peyton parent ? &(parent->ompt_task_info.frame) : NULL, 457*3041982dSJonathan Peyton taskdata->ompt_task_info.task_id, taskdata->ompt_task_info.function); 4587cc577a4SJonathan Peyton } 4597cc577a4SJonathan Peyton #endif 4607cc577a4SJonathan Peyton #if OMP_40_ENABLED && OMPT_SUPPORT && OMPT_TRACE 4617cc577a4SJonathan Peyton /* OMPT emit all dependences if requested by the tool */ 4627cc577a4SJonathan Peyton if (ompt_enabled && taskdata->ompt_task_info.ndeps > 0 && 463*3041982dSJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_task_dependences)) { 4647cc577a4SJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_task_dependences)( 465*3041982dSJonathan Peyton taskdata->ompt_task_info.task_id, taskdata->ompt_task_info.deps, 466*3041982dSJonathan Peyton taskdata->ompt_task_info.ndeps); 4677cc577a4SJonathan Peyton /* We can now free the allocated memory for the dependencies */ 4687cc577a4SJonathan Peyton KMP_OMPT_DEPS_FREE(thread, taskdata->ompt_task_info.deps); 4697cc577a4SJonathan Peyton taskdata->ompt_task_info.deps = NULL; 4707cc577a4SJonathan Peyton taskdata->ompt_task_info.ndeps = 0; 4717cc577a4SJonathan Peyton } 4727cc577a4SJonathan Peyton #endif /* OMP_40_ENABLED && OMPT_SUPPORT && OMPT_TRACE */ 4737cc577a4SJonathan Peyton 4747cc577a4SJonathan Peyton return; 4757cc577a4SJonathan Peyton } 4767cc577a4SJonathan Peyton 477*3041982dSJonathan Peyton // __kmpc_omp_task_begin_if0: report that a given serialized task has started 478*3041982dSJonathan Peyton // execution 479*3041982dSJonathan Peyton // 4807cc577a4SJonathan Peyton // loc_ref: source location information; points to beginning of task block. 4817cc577a4SJonathan Peyton // gtid: global thread number. 4827cc577a4SJonathan Peyton // task: task thunk for the started task. 483*3041982dSJonathan Peyton void __kmpc_omp_task_begin_if0(ident_t *loc_ref, kmp_int32 gtid, 484*3041982dSJonathan Peyton kmp_task_t *task) { 4857cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 4867cc577a4SJonathan Peyton kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 4877cc577a4SJonathan Peyton 488*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_begin_if0(enter): T#%d loc=%p task=%p " 489*3041982dSJonathan Peyton "current_task=%p\n", 4907cc577a4SJonathan Peyton gtid, loc_ref, taskdata, current_task)); 4917cc577a4SJonathan Peyton 4927cc577a4SJonathan Peyton if (taskdata->td_flags.tiedness == TASK_UNTIED) { 493*3041982dSJonathan Peyton // untied task needs to increment counter so that the task structure is not 494*3041982dSJonathan Peyton // freed prematurely 4957cc577a4SJonathan Peyton kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count); 496*3041982dSJonathan Peyton KA_TRACE(20, ("__kmpc_omp_task_begin_if0: T#%d untied_count (%d) " 497*3041982dSJonathan Peyton "incremented for task %p\n", 4987cc577a4SJonathan Peyton gtid, counter, taskdata)); 4997cc577a4SJonathan Peyton } 5007cc577a4SJonathan Peyton 501*3041982dSJonathan Peyton taskdata->td_flags.task_serial = 502*3041982dSJonathan Peyton 1; // Execute this task immediately, not deferred. 5037cc577a4SJonathan Peyton __kmp_task_start(gtid, task, current_task); 5047cc577a4SJonathan Peyton 505*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_begin_if0(exit): T#%d loc=%p task=%p,\n", gtid, 506*3041982dSJonathan Peyton loc_ref, taskdata)); 5077cc577a4SJonathan Peyton 5087cc577a4SJonathan Peyton return; 5097cc577a4SJonathan Peyton } 5107cc577a4SJonathan Peyton 5117cc577a4SJonathan Peyton #ifdef TASK_UNUSED 5127cc577a4SJonathan Peyton // __kmpc_omp_task_begin: report that a given task has started execution 5137cc577a4SJonathan Peyton // NEVER GENERATED BY COMPILER, DEPRECATED!!! 514*3041982dSJonathan Peyton void __kmpc_omp_task_begin(ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *task) { 5157cc577a4SJonathan Peyton kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 5167cc577a4SJonathan Peyton 517*3041982dSJonathan Peyton KA_TRACE( 518*3041982dSJonathan Peyton 10, 519*3041982dSJonathan Peyton ("__kmpc_omp_task_begin(enter): T#%d loc=%p task=%p current_task=%p\n", 5207cc577a4SJonathan Peyton gtid, loc_ref, KMP_TASK_TO_TASKDATA(task), current_task)); 5217cc577a4SJonathan Peyton 5227cc577a4SJonathan Peyton __kmp_task_start(gtid, task, current_task); 5237cc577a4SJonathan Peyton 524*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_begin(exit): T#%d loc=%p task=%p,\n", gtid, 525*3041982dSJonathan Peyton loc_ref, KMP_TASK_TO_TASKDATA(task))); 5267cc577a4SJonathan Peyton return; 5277cc577a4SJonathan Peyton } 5287cc577a4SJonathan Peyton #endif // TASK_UNUSED 5297cc577a4SJonathan Peyton 5307cc577a4SJonathan Peyton // __kmp_free_task: free the current task space and the space for shareds 531*3041982dSJonathan Peyton // 5327cc577a4SJonathan Peyton // gtid: Global thread ID of calling thread 5337cc577a4SJonathan Peyton // taskdata: task to free 5347cc577a4SJonathan Peyton // thread: thread data structure of caller 535*3041982dSJonathan Peyton static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata, 536*3041982dSJonathan Peyton kmp_info_t *thread) { 537*3041982dSJonathan Peyton KA_TRACE(30, ("__kmp_free_task: T#%d freeing data from task %p\n", gtid, 538*3041982dSJonathan Peyton taskdata)); 5397cc577a4SJonathan Peyton 5407cc577a4SJonathan Peyton // Check to make sure all flags and counters have the correct values 5417cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 5427cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0); 5437cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 1); 5447cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 545*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(TCR_4(taskdata->td_allocated_child_tasks) == 0 || 546*3041982dSJonathan Peyton taskdata->td_flags.task_serial == 1); 5477cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(TCR_4(taskdata->td_incomplete_child_tasks) == 0); 5487cc577a4SJonathan Peyton 5497cc577a4SJonathan Peyton taskdata->td_flags.freed = 1; 5507cc577a4SJonathan Peyton ANNOTATE_HAPPENS_BEFORE(taskdata); 5517cc577a4SJonathan Peyton // deallocate the taskdata and shared variable blocks associated with this task 5527cc577a4SJonathan Peyton #if USE_FAST_MEMORY 5537cc577a4SJonathan Peyton __kmp_fast_free(thread, taskdata); 5547cc577a4SJonathan Peyton #else /* ! USE_FAST_MEMORY */ 5557cc577a4SJonathan Peyton __kmp_thread_free(thread, taskdata); 5567cc577a4SJonathan Peyton #endif 5577cc577a4SJonathan Peyton 558*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n", gtid, taskdata)); 5597cc577a4SJonathan Peyton } 5607cc577a4SJonathan Peyton 561*3041982dSJonathan Peyton // __kmp_free_task_and_ancestors: free the current task and ancestors without 562*3041982dSJonathan Peyton // children 5637cc577a4SJonathan Peyton // 5647cc577a4SJonathan Peyton // gtid: Global thread ID of calling thread 5657cc577a4SJonathan Peyton // taskdata: task to free 5667cc577a4SJonathan Peyton // thread: thread data structure of caller 567*3041982dSJonathan Peyton static void __kmp_free_task_and_ancestors(kmp_int32 gtid, 568*3041982dSJonathan Peyton kmp_taskdata_t *taskdata, 569*3041982dSJonathan Peyton kmp_info_t *thread) { 5707cc577a4SJonathan Peyton #if OMP_45_ENABLED 5717cc577a4SJonathan Peyton // Proxy tasks must always be allowed to free their parents 5727cc577a4SJonathan Peyton // because they can be run in background even in serial mode. 573*3041982dSJonathan Peyton kmp_int32 team_serial = 574*3041982dSJonathan Peyton (taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) && 575*3041982dSJonathan Peyton !taskdata->td_flags.proxy; 5767cc577a4SJonathan Peyton #else 577*3041982dSJonathan Peyton kmp_int32 team_serial = 578*3041982dSJonathan Peyton taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser; 5797cc577a4SJonathan Peyton #endif 5807cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 5817cc577a4SJonathan Peyton 582*3041982dSJonathan Peyton kmp_int32 children = 583*3041982dSJonathan Peyton KMP_TEST_THEN_DEC32((kmp_int32 *)(&taskdata->td_allocated_child_tasks)) - 584*3041982dSJonathan Peyton 1; 5857cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(children >= 0); 5867cc577a4SJonathan Peyton 5877cc577a4SJonathan Peyton // Now, go up the ancestor tree to see if any ancestors can now be freed. 588*3041982dSJonathan Peyton while (children == 0) { 5897cc577a4SJonathan Peyton kmp_taskdata_t *parent_taskdata = taskdata->td_parent; 5907cc577a4SJonathan Peyton 5917cc577a4SJonathan Peyton KA_TRACE(20, ("__kmp_free_task_and_ancestors(enter): T#%d task %p complete " 592*3041982dSJonathan Peyton "and freeing itself\n", 593*3041982dSJonathan Peyton gtid, taskdata)); 5947cc577a4SJonathan Peyton 5957cc577a4SJonathan Peyton // --- Deallocate my ancestor task --- 5967cc577a4SJonathan Peyton __kmp_free_task(gtid, taskdata, thread); 5977cc577a4SJonathan Peyton 5987cc577a4SJonathan Peyton taskdata = parent_taskdata; 5997cc577a4SJonathan Peyton 600*3041982dSJonathan Peyton // Stop checking ancestors at implicit task instead of walking up ancestor 601*3041982dSJonathan Peyton // tree to avoid premature deallocation of ancestors. 6027cc577a4SJonathan Peyton if (team_serial || taskdata->td_flags.tasktype == TASK_IMPLICIT) 6037cc577a4SJonathan Peyton return; 6047cc577a4SJonathan Peyton 6057cc577a4SJonathan Peyton // Predecrement simulated by "- 1" calculation 606*3041982dSJonathan Peyton children = KMP_TEST_THEN_DEC32( 607*3041982dSJonathan Peyton (kmp_int32 *)(&taskdata->td_allocated_child_tasks)) - 608*3041982dSJonathan Peyton 1; 6097cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(children >= 0); 6107cc577a4SJonathan Peyton } 6117cc577a4SJonathan Peyton 612*3041982dSJonathan Peyton KA_TRACE( 613*3041982dSJonathan Peyton 20, ("__kmp_free_task_and_ancestors(exit): T#%d task %p has %d children; " 614*3041982dSJonathan Peyton "not freeing it yet\n", 615*3041982dSJonathan Peyton gtid, taskdata, children)); 6167cc577a4SJonathan Peyton } 6177cc577a4SJonathan Peyton 6187cc577a4SJonathan Peyton // __kmp_task_finish: bookkeeping to do when a task finishes execution 619*3041982dSJonathan Peyton // 6207cc577a4SJonathan Peyton // gtid: global thread ID for calling thread 6217cc577a4SJonathan Peyton // task: task to be finished 6227cc577a4SJonathan Peyton // resumed_task: task to be resumed. (may be NULL if task is serialized) 623*3041982dSJonathan Peyton static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task, 624*3041982dSJonathan Peyton kmp_taskdata_t *resumed_task) { 6257cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 6267cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 627*3041982dSJonathan Peyton kmp_task_team_t *task_team = 628*3041982dSJonathan Peyton thread->th.th_task_team; // might be NULL for serial teams... 6297cc577a4SJonathan Peyton kmp_int32 children = 0; 6307cc577a4SJonathan Peyton 6317cc577a4SJonathan Peyton #if OMPT_SUPPORT 632*3041982dSJonathan Peyton if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_end)) { 6337cc577a4SJonathan Peyton kmp_taskdata_t *parent = taskdata->td_parent; 6347cc577a4SJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_task_end)( 6357cc577a4SJonathan Peyton taskdata->ompt_task_info.task_id); 6367cc577a4SJonathan Peyton } 6377cc577a4SJonathan Peyton #endif 6387cc577a4SJonathan Peyton 639*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_task_finish(enter): T#%d finishing task %p and resuming " 640*3041982dSJonathan Peyton "task %p\n", 6417cc577a4SJonathan Peyton gtid, taskdata, resumed_task)); 6427cc577a4SJonathan Peyton 6437cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 6447cc577a4SJonathan Peyton 6457cc577a4SJonathan Peyton // Pop task from stack if tied 6467cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK 647*3041982dSJonathan Peyton if (taskdata->td_flags.tiedness == TASK_TIED) { 6487cc577a4SJonathan Peyton __kmp_pop_task_stack(gtid, thread, taskdata); 6497cc577a4SJonathan Peyton } 6507cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */ 6517cc577a4SJonathan Peyton 6527cc577a4SJonathan Peyton if (taskdata->td_flags.tiedness == TASK_UNTIED) { 653*3041982dSJonathan Peyton // untied task needs to check the counter so that the task structure is not 654*3041982dSJonathan Peyton // freed prematurely 6557cc577a4SJonathan Peyton kmp_int32 counter = KMP_TEST_THEN_DEC32(&taskdata->td_untied_count) - 1; 656*3041982dSJonathan Peyton KA_TRACE( 657*3041982dSJonathan Peyton 20, 658*3041982dSJonathan Peyton ("__kmp_task_finish: T#%d untied_count (%d) decremented for task %p\n", 6597cc577a4SJonathan Peyton gtid, counter, taskdata)); 6607cc577a4SJonathan Peyton if (counter > 0) { 661*3041982dSJonathan Peyton // untied task is not done, to be continued possibly by other thread, do 662*3041982dSJonathan Peyton // not free it now 6637cc577a4SJonathan Peyton if (resumed_task == NULL) { 6647cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.task_serial); 665*3041982dSJonathan Peyton resumed_task = taskdata->td_parent; // In a serialized task, the resumed 666*3041982dSJonathan Peyton // task is the parent 6677cc577a4SJonathan Peyton } 6687cc577a4SJonathan Peyton thread->th.th_current_task = resumed_task; // restore current_task 6697cc577a4SJonathan Peyton resumed_task->td_flags.executing = 1; // resume previous task 670*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_task_finish(exit): T#%d partially done task %p, " 671*3041982dSJonathan Peyton "resuming task %p\n", 6727cc577a4SJonathan Peyton gtid, taskdata, resumed_task)); 6737cc577a4SJonathan Peyton return; 6747cc577a4SJonathan Peyton } 6757cc577a4SJonathan Peyton } 6767cc577a4SJonathan Peyton 6777cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0); 6787cc577a4SJonathan Peyton taskdata->td_flags.complete = 1; // mark the task as completed 6797cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.started == 1); 6807cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 6817cc577a4SJonathan Peyton 682*3041982dSJonathan Peyton // Only need to keep track of count if team parallel and tasking not 683*3041982dSJonathan Peyton // serialized 6847cc577a4SJonathan Peyton if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) { 6857cc577a4SJonathan Peyton // Predecrement simulated by "- 1" calculation 686*3041982dSJonathan Peyton children = 687*3041982dSJonathan Peyton KMP_TEST_THEN_DEC32( 688*3041982dSJonathan Peyton (kmp_int32 *)(&taskdata->td_parent->td_incomplete_child_tasks)) - 689*3041982dSJonathan Peyton 1; 6907cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(children >= 0); 6917cc577a4SJonathan Peyton #if OMP_40_ENABLED 6927cc577a4SJonathan Peyton if (taskdata->td_taskgroup) 6937cc577a4SJonathan Peyton KMP_TEST_THEN_DEC32((kmp_int32 *)(&taskdata->td_taskgroup->count)); 6947cc577a4SJonathan Peyton #if OMP_45_ENABLED 6957cc577a4SJonathan Peyton } 6967cc577a4SJonathan Peyton // if we found proxy tasks there could exist a dependency chain 6977cc577a4SJonathan Peyton // with the proxy task as origin 698*3041982dSJonathan Peyton if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) || 699*3041982dSJonathan Peyton (task_team && task_team->tt.tt_found_proxy_tasks)) { 7007cc577a4SJonathan Peyton #endif 7017cc577a4SJonathan Peyton __kmp_release_deps(gtid, taskdata); 7027cc577a4SJonathan Peyton #endif 7037cc577a4SJonathan Peyton } 7047cc577a4SJonathan Peyton 705*3041982dSJonathan Peyton // td_flags.executing must be marked as 0 after __kmp_release_deps has been 706*3041982dSJonathan Peyton // called. Othertwise, if a task is executed immediately from the release_deps 707*3041982dSJonathan Peyton // code, the flag will be reset to 1 again by this same function 7087cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 1); 7097cc577a4SJonathan Peyton taskdata->td_flags.executing = 0; // suspend the finishing task 7107cc577a4SJonathan Peyton 711*3041982dSJonathan Peyton KA_TRACE( 712*3041982dSJonathan Peyton 20, ("__kmp_task_finish: T#%d finished task %p, %d incomplete children\n", 7137cc577a4SJonathan Peyton gtid, taskdata, children)); 7147cc577a4SJonathan Peyton 7157cc577a4SJonathan Peyton #if OMP_40_ENABLED 7167cc577a4SJonathan Peyton /* If the tasks' destructor thunk flag has been set, we need to invoke the 717*3041982dSJonathan Peyton destructor thunk that has been generated by the compiler. The code is 718*3041982dSJonathan Peyton placed here, since at this point other tasks might have been released 7197cc577a4SJonathan Peyton hence overlapping the destructor invokations with some other work in the 720*3041982dSJonathan Peyton released tasks. The OpenMP spec is not specific on when the destructors 721*3041982dSJonathan Peyton are invoked, so we should be free to choose. */ 7227cc577a4SJonathan Peyton if (taskdata->td_flags.destructors_thunk) { 7237cc577a4SJonathan Peyton kmp_routine_entry_t destr_thunk = task->data1.destructors; 7247cc577a4SJonathan Peyton KMP_ASSERT(destr_thunk); 7257cc577a4SJonathan Peyton destr_thunk(gtid, task); 7267cc577a4SJonathan Peyton } 7277cc577a4SJonathan Peyton #endif // OMP_40_ENABLED 7287cc577a4SJonathan Peyton 7297cc577a4SJonathan Peyton // bookkeeping for resuming task: 7307cc577a4SJonathan Peyton // GEH - note tasking_ser => task_serial 731*3041982dSJonathan Peyton KMP_DEBUG_ASSERT( 732*3041982dSJonathan Peyton (taskdata->td_flags.tasking_ser || taskdata->td_flags.task_serial) == 7337cc577a4SJonathan Peyton taskdata->td_flags.task_serial); 734*3041982dSJonathan Peyton if (taskdata->td_flags.task_serial) { 7357cc577a4SJonathan Peyton if (resumed_task == NULL) { 736*3041982dSJonathan Peyton resumed_task = taskdata->td_parent; // In a serialized task, the resumed 737*3041982dSJonathan Peyton // task is the parent 738*3041982dSJonathan Peyton } else 7397cc577a4SJonathan Peyton #if OMP_45_ENABLED 7407cc577a4SJonathan Peyton if (!(task_team && task_team->tt.tt_found_proxy_tasks)) 7417cc577a4SJonathan Peyton #endif 7427cc577a4SJonathan Peyton { 7437cc577a4SJonathan Peyton // verify resumed task passed in points to parent 7447cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(resumed_task == taskdata->td_parent); 7457cc577a4SJonathan Peyton } 746*3041982dSJonathan Peyton } else { 747*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(resumed_task != 748*3041982dSJonathan Peyton NULL); // verify that resumed task is passed as arguemnt 7497cc577a4SJonathan Peyton } 7507cc577a4SJonathan Peyton 7517cc577a4SJonathan Peyton // Free this task and then ancestor tasks if they have no children. 7527cc577a4SJonathan Peyton // Restore th_current_task first as suggested by John: 7537cc577a4SJonathan Peyton // johnmc: if an asynchronous inquiry peers into the runtime system 7547cc577a4SJonathan Peyton // it doesn't see the freed task as the current task. 7557cc577a4SJonathan Peyton thread->th.th_current_task = resumed_task; 7567cc577a4SJonathan Peyton __kmp_free_task_and_ancestors(gtid, taskdata, thread); 7577cc577a4SJonathan Peyton 7587cc577a4SJonathan Peyton // TODO: GEH - make sure root team implicit task is initialized properly. 7597cc577a4SJonathan Peyton // KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 ); 7607cc577a4SJonathan Peyton resumed_task->td_flags.executing = 1; // resume previous task 7617cc577a4SJonathan Peyton 762*3041982dSJonathan Peyton KA_TRACE( 763*3041982dSJonathan Peyton 10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n", 7647cc577a4SJonathan Peyton gtid, taskdata, resumed_task)); 7657cc577a4SJonathan Peyton 7667cc577a4SJonathan Peyton return; 7677cc577a4SJonathan Peyton } 7687cc577a4SJonathan Peyton 7697cc577a4SJonathan Peyton // __kmpc_omp_task_complete_if0: report that a task has completed execution 770*3041982dSJonathan Peyton // 7717cc577a4SJonathan Peyton // loc_ref: source location information; points to end of task block. 7727cc577a4SJonathan Peyton // gtid: global thread number. 7737cc577a4SJonathan Peyton // task: task thunk for the completed task. 774*3041982dSJonathan Peyton void __kmpc_omp_task_complete_if0(ident_t *loc_ref, kmp_int32 gtid, 775*3041982dSJonathan Peyton kmp_task_t *task) { 7767cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_complete_if0(enter): T#%d loc=%p task=%p\n", 7777cc577a4SJonathan Peyton gtid, loc_ref, KMP_TASK_TO_TASKDATA(task))); 778*3041982dSJonathan Peyton // this routine will provide task to resume 779*3041982dSJonathan Peyton __kmp_task_finish(gtid, task, NULL); 7807cc577a4SJonathan Peyton 7817cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_complete_if0(exit): T#%d loc=%p task=%p\n", 7827cc577a4SJonathan Peyton gtid, loc_ref, KMP_TASK_TO_TASKDATA(task))); 7837cc577a4SJonathan Peyton return; 7847cc577a4SJonathan Peyton } 7857cc577a4SJonathan Peyton 7867cc577a4SJonathan Peyton #ifdef TASK_UNUSED 7877cc577a4SJonathan Peyton // __kmpc_omp_task_complete: report that a task has completed execution 7887cc577a4SJonathan Peyton // NEVER GENERATED BY COMPILER, DEPRECATED!!! 789*3041982dSJonathan Peyton void __kmpc_omp_task_complete(ident_t *loc_ref, kmp_int32 gtid, 790*3041982dSJonathan Peyton kmp_task_t *task) { 791*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_complete(enter): T#%d loc=%p task=%p\n", gtid, 792*3041982dSJonathan Peyton loc_ref, KMP_TASK_TO_TASKDATA(task))); 7937cc577a4SJonathan Peyton 7947cc577a4SJonathan Peyton __kmp_task_finish(gtid, task, NULL); // Not sure how to find task to resume 7957cc577a4SJonathan Peyton 796*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_complete(exit): T#%d loc=%p task=%p\n", gtid, 797*3041982dSJonathan Peyton loc_ref, KMP_TASK_TO_TASKDATA(task))); 7987cc577a4SJonathan Peyton return; 7997cc577a4SJonathan Peyton } 8007cc577a4SJonathan Peyton #endif // TASK_UNUSED 8017cc577a4SJonathan Peyton 8027cc577a4SJonathan Peyton #if OMPT_SUPPORT 803*3041982dSJonathan Peyton // __kmp_task_init_ompt: Initialize OMPT fields maintained by a task. This will 804*3041982dSJonathan Peyton // only be called after ompt_tool, so we already know whether ompt is enabled 805*3041982dSJonathan Peyton // or not. 806*3041982dSJonathan Peyton static inline void __kmp_task_init_ompt(kmp_taskdata_t *task, int tid, 807*3041982dSJonathan Peyton void *function) { 8087cc577a4SJonathan Peyton if (ompt_enabled) { 8097cc577a4SJonathan Peyton task->ompt_task_info.task_id = __ompt_task_id_new(tid); 8107cc577a4SJonathan Peyton task->ompt_task_info.function = function; 8117cc577a4SJonathan Peyton task->ompt_task_info.frame.exit_runtime_frame = NULL; 8127cc577a4SJonathan Peyton task->ompt_task_info.frame.reenter_runtime_frame = NULL; 8137cc577a4SJonathan Peyton #if OMP_40_ENABLED 8147cc577a4SJonathan Peyton task->ompt_task_info.ndeps = 0; 8157cc577a4SJonathan Peyton task->ompt_task_info.deps = NULL; 8167cc577a4SJonathan Peyton #endif /* OMP_40_ENABLED */ 8177cc577a4SJonathan Peyton } 8187cc577a4SJonathan Peyton } 8197cc577a4SJonathan Peyton #endif 8207cc577a4SJonathan Peyton 821*3041982dSJonathan Peyton // __kmp_init_implicit_task: Initialize the appropriate fields in the implicit 822*3041982dSJonathan Peyton // task for a given thread 8237cc577a4SJonathan Peyton // 8247cc577a4SJonathan Peyton // loc_ref: reference to source location of parallel region 8257cc577a4SJonathan Peyton // this_thr: thread data structure corresponding to implicit task 8267cc577a4SJonathan Peyton // team: team for this_thr 8277cc577a4SJonathan Peyton // tid: thread id of given thread within team 8287cc577a4SJonathan Peyton // set_curr_task: TRUE if need to push current task to thread 829*3041982dSJonathan Peyton // NOTE: Routine does not set up the implicit task ICVS. This is assumed to 830*3041982dSJonathan Peyton // have already been done elsewhere. 8317cc577a4SJonathan Peyton // TODO: Get better loc_ref. Value passed in may be NULL 832*3041982dSJonathan Peyton void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr, 833*3041982dSJonathan Peyton kmp_team_t *team, int tid, int set_curr_task) { 8347cc577a4SJonathan Peyton kmp_taskdata_t *task = &team->t.t_implicit_task_taskdata[tid]; 8357cc577a4SJonathan Peyton 836*3041982dSJonathan Peyton KF_TRACE( 837*3041982dSJonathan Peyton 10, 838*3041982dSJonathan Peyton ("__kmp_init_implicit_task(enter): T#:%d team=%p task=%p, reinit=%s\n", 8397cc577a4SJonathan Peyton tid, team, task, set_curr_task ? "TRUE" : "FALSE")); 8407cc577a4SJonathan Peyton 8417cc577a4SJonathan Peyton task->td_task_id = KMP_GEN_TASK_ID(); 8427cc577a4SJonathan Peyton task->td_team = team; 843*3041982dSJonathan Peyton // task->td_parent = NULL; // fix for CQ230101 (broken parent task info 844*3041982dSJonathan Peyton // in debugger) 8457cc577a4SJonathan Peyton task->td_ident = loc_ref; 8467cc577a4SJonathan Peyton task->td_taskwait_ident = NULL; 8477cc577a4SJonathan Peyton task->td_taskwait_counter = 0; 8487cc577a4SJonathan Peyton task->td_taskwait_thread = 0; 8497cc577a4SJonathan Peyton 8507cc577a4SJonathan Peyton task->td_flags.tiedness = TASK_TIED; 8517cc577a4SJonathan Peyton task->td_flags.tasktype = TASK_IMPLICIT; 8527cc577a4SJonathan Peyton #if OMP_45_ENABLED 8537cc577a4SJonathan Peyton task->td_flags.proxy = TASK_FULL; 8547cc577a4SJonathan Peyton #endif 8557cc577a4SJonathan Peyton 8567cc577a4SJonathan Peyton // All implicit tasks are executed immediately, not deferred 8577cc577a4SJonathan Peyton task->td_flags.task_serial = 1; 8587cc577a4SJonathan Peyton task->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec); 8597cc577a4SJonathan Peyton task->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0; 8607cc577a4SJonathan Peyton 8617cc577a4SJonathan Peyton task->td_flags.started = 1; 8627cc577a4SJonathan Peyton task->td_flags.executing = 1; 8637cc577a4SJonathan Peyton task->td_flags.complete = 0; 8647cc577a4SJonathan Peyton task->td_flags.freed = 0; 8657cc577a4SJonathan Peyton 8667cc577a4SJonathan Peyton #if OMP_40_ENABLED 8677cc577a4SJonathan Peyton task->td_depnode = NULL; 8687cc577a4SJonathan Peyton #endif 8697cc577a4SJonathan Peyton 870*3041982dSJonathan Peyton if (set_curr_task) { // only do this init first time thread is created 8717cc577a4SJonathan Peyton task->td_incomplete_child_tasks = 0; 872*3041982dSJonathan Peyton task->td_allocated_child_tasks = 0; // Not used: don't need to 873*3041982dSJonathan Peyton // deallocate implicit task 8747cc577a4SJonathan Peyton #if OMP_40_ENABLED 8757cc577a4SJonathan Peyton task->td_taskgroup = NULL; // An implicit task does not have taskgroup 8767cc577a4SJonathan Peyton task->td_dephash = NULL; 8777cc577a4SJonathan Peyton #endif 8787cc577a4SJonathan Peyton __kmp_push_current_task_to_thread(this_thr, team, tid); 8797cc577a4SJonathan Peyton } else { 8807cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task->td_incomplete_child_tasks == 0); 8817cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task->td_allocated_child_tasks == 0); 8827cc577a4SJonathan Peyton } 8837cc577a4SJonathan Peyton 8847cc577a4SJonathan Peyton #if OMPT_SUPPORT 8857cc577a4SJonathan Peyton __kmp_task_init_ompt(task, tid, NULL); 8867cc577a4SJonathan Peyton #endif 8877cc577a4SJonathan Peyton 888*3041982dSJonathan Peyton KF_TRACE(10, ("__kmp_init_implicit_task(exit): T#:%d team=%p task=%p\n", tid, 889*3041982dSJonathan Peyton team, task)); 8907cc577a4SJonathan Peyton } 8917cc577a4SJonathan Peyton 892*3041982dSJonathan Peyton // __kmp_finish_implicit_task: Release resources associated to implicit tasks 893*3041982dSJonathan Peyton // at the end of parallel regions. Some resources are kept for reuse in the next 894*3041982dSJonathan Peyton // parallel region. 8957cc577a4SJonathan Peyton // 896*3041982dSJonathan Peyton // thread: thread data structure corresponding to implicit task 897*3041982dSJonathan Peyton void __kmp_finish_implicit_task(kmp_info_t *thread) { 8987cc577a4SJonathan Peyton kmp_taskdata_t *task = thread->th.th_current_task; 8997cc577a4SJonathan Peyton if (task->td_dephash) 9007cc577a4SJonathan Peyton __kmp_dephash_free_entries(thread, task->td_dephash); 9017cc577a4SJonathan Peyton } 9027cc577a4SJonathan Peyton 903*3041982dSJonathan Peyton // __kmp_free_implicit_task: Release resources associated to implicit tasks 904*3041982dSJonathan Peyton // when these are destroyed regions 9057cc577a4SJonathan Peyton // 906*3041982dSJonathan Peyton // thread: thread data structure corresponding to implicit task 907*3041982dSJonathan Peyton void __kmp_free_implicit_task(kmp_info_t *thread) { 9087cc577a4SJonathan Peyton kmp_taskdata_t *task = thread->th.th_current_task; 9097cc577a4SJonathan Peyton if (task->td_dephash) 9107cc577a4SJonathan Peyton __kmp_dephash_free(thread, task->td_dephash); 9117cc577a4SJonathan Peyton task->td_dephash = NULL; 9127cc577a4SJonathan Peyton } 9137cc577a4SJonathan Peyton 914*3041982dSJonathan Peyton // Round up a size to a power of two specified by val: Used to insert padding 915*3041982dSJonathan Peyton // between structures co-allocated using a single malloc() call 916*3041982dSJonathan Peyton static size_t __kmp_round_up_to_val(size_t size, size_t val) { 9177cc577a4SJonathan Peyton if (size & (val - 1)) { 9187cc577a4SJonathan Peyton size &= ~(val - 1); 9197cc577a4SJonathan Peyton if (size <= KMP_SIZE_T_MAX - val) { 9207cc577a4SJonathan Peyton size += val; // Round up if there is no overflow. 9217cc577a4SJonathan Peyton }; // if 9227cc577a4SJonathan Peyton }; // if 9237cc577a4SJonathan Peyton return size; 9247cc577a4SJonathan Peyton } // __kmp_round_up_to_va 9257cc577a4SJonathan Peyton 9267cc577a4SJonathan Peyton // __kmp_task_alloc: Allocate the taskdata and task data structures for a task 9277cc577a4SJonathan Peyton // 9287cc577a4SJonathan Peyton // loc_ref: source location information 9297cc577a4SJonathan Peyton // gtid: global thread number. 930*3041982dSJonathan Peyton // flags: include tiedness & task type (explicit vs. implicit) of the ''new'' 931*3041982dSJonathan Peyton // task encountered. Converted from kmp_int32 to kmp_tasking_flags_t in routine. 932*3041982dSJonathan Peyton // sizeof_kmp_task_t: Size in bytes of kmp_task_t data structure including 933*3041982dSJonathan Peyton // private vars accessed in task. 934*3041982dSJonathan Peyton // sizeof_shareds: Size in bytes of array of pointers to shared vars accessed 935*3041982dSJonathan Peyton // in task. 9367cc577a4SJonathan Peyton // task_entry: Pointer to task code entry point generated by compiler. 9377cc577a4SJonathan Peyton // returns: a pointer to the allocated kmp_task_t structure (task). 938*3041982dSJonathan Peyton kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid, 939*3041982dSJonathan Peyton kmp_tasking_flags_t *flags, 9407cc577a4SJonathan Peyton size_t sizeof_kmp_task_t, size_t sizeof_shareds, 941*3041982dSJonathan Peyton kmp_routine_entry_t task_entry) { 9427cc577a4SJonathan Peyton kmp_task_t *task; 9437cc577a4SJonathan Peyton kmp_taskdata_t *taskdata; 9447cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 9457cc577a4SJonathan Peyton kmp_team_t *team = thread->th.th_team; 9467cc577a4SJonathan Peyton kmp_taskdata_t *parent_task = thread->th.th_current_task; 9477cc577a4SJonathan Peyton size_t shareds_offset; 9487cc577a4SJonathan Peyton 9497cc577a4SJonathan Peyton KA_TRACE(10, ("__kmp_task_alloc(enter): T#%d loc=%p, flags=(0x%x) " 9507cc577a4SJonathan Peyton "sizeof_task=%ld sizeof_shared=%ld entry=%p\n", 9517cc577a4SJonathan Peyton gtid, loc_ref, *((kmp_int32 *)flags), sizeof_kmp_task_t, 9527cc577a4SJonathan Peyton sizeof_shareds, task_entry)); 9537cc577a4SJonathan Peyton 9547cc577a4SJonathan Peyton if (parent_task->td_flags.final) { 9557cc577a4SJonathan Peyton if (flags->merged_if0) { 9567cc577a4SJonathan Peyton } 9577cc577a4SJonathan Peyton flags->final = 1; 9587cc577a4SJonathan Peyton } 9597cc577a4SJonathan Peyton 9607cc577a4SJonathan Peyton #if OMP_45_ENABLED 9617cc577a4SJonathan Peyton if (flags->proxy == TASK_PROXY) { 9627cc577a4SJonathan Peyton flags->tiedness = TASK_UNTIED; 9637cc577a4SJonathan Peyton flags->merged_if0 = 1; 9647cc577a4SJonathan Peyton 965*3041982dSJonathan Peyton /* are we running in a sequential parallel or tskm_immediate_exec... we need 966*3041982dSJonathan Peyton tasking support enabled */ 9677cc577a4SJonathan Peyton if ((thread->th.th_task_team) == NULL) { 9687cc577a4SJonathan Peyton /* This should only happen if the team is serialized 969*3041982dSJonathan Peyton setup a task team and propagate it to the thread */ 9707cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(team->t.t_serialized); 971*3041982dSJonathan Peyton KA_TRACE(30, 972*3041982dSJonathan Peyton ("T#%d creating task team in __kmp_task_alloc for proxy task\n", 973*3041982dSJonathan Peyton gtid)); 974*3041982dSJonathan Peyton __kmp_task_team_setup( 975*3041982dSJonathan Peyton thread, team, 976*3041982dSJonathan Peyton 1); // 1 indicates setup the current team regardless of nthreads 9777cc577a4SJonathan Peyton thread->th.th_task_team = team->t.t_task_team[thread->th.th_task_state]; 9787cc577a4SJonathan Peyton } 9797cc577a4SJonathan Peyton kmp_task_team_t *task_team = thread->th.th_task_team; 9807cc577a4SJonathan Peyton 9817cc577a4SJonathan Peyton /* tasking must be enabled now as the task might not be pushed */ 9827cc577a4SJonathan Peyton if (!KMP_TASKING_ENABLED(task_team)) { 983*3041982dSJonathan Peyton KA_TRACE( 984*3041982dSJonathan Peyton 30, 985*3041982dSJonathan Peyton ("T#%d enabling tasking in __kmp_task_alloc for proxy task\n", gtid)); 9867cc577a4SJonathan Peyton __kmp_enable_tasking(task_team, thread); 9877cc577a4SJonathan Peyton kmp_int32 tid = thread->th.th_info.ds.ds_tid; 9887cc577a4SJonathan Peyton kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid]; 9897cc577a4SJonathan Peyton // No lock needed since only owner can allocate 9907cc577a4SJonathan Peyton if (thread_data->td.td_deque == NULL) { 9917cc577a4SJonathan Peyton __kmp_alloc_task_deque(thread, thread_data); 9927cc577a4SJonathan Peyton } 9937cc577a4SJonathan Peyton } 9947cc577a4SJonathan Peyton 9957cc577a4SJonathan Peyton if (task_team->tt.tt_found_proxy_tasks == FALSE) 9967cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_found_proxy_tasks, TRUE); 9977cc577a4SJonathan Peyton } 9987cc577a4SJonathan Peyton #endif 9997cc577a4SJonathan Peyton 10007cc577a4SJonathan Peyton // Calculate shared structure offset including padding after kmp_task_t struct 10017cc577a4SJonathan Peyton // to align pointers in shared struct 10027cc577a4SJonathan Peyton shareds_offset = sizeof(kmp_taskdata_t) + sizeof_kmp_task_t; 10037cc577a4SJonathan Peyton shareds_offset = __kmp_round_up_to_val(shareds_offset, sizeof(void *)); 10047cc577a4SJonathan Peyton 10057cc577a4SJonathan Peyton // Allocate a kmp_taskdata_t block and a kmp_task_t block. 1006*3041982dSJonathan Peyton KA_TRACE(30, ("__kmp_task_alloc: T#%d First malloc size: %ld\n", gtid, 1007*3041982dSJonathan Peyton shareds_offset)); 1008*3041982dSJonathan Peyton KA_TRACE(30, ("__kmp_task_alloc: T#%d Second malloc size: %ld\n", gtid, 1009*3041982dSJonathan Peyton sizeof_shareds)); 10107cc577a4SJonathan Peyton 10117cc577a4SJonathan Peyton // Avoid double allocation here by combining shareds with taskdata 10127cc577a4SJonathan Peyton #if USE_FAST_MEMORY 1013*3041982dSJonathan Peyton taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, shareds_offset + 1014*3041982dSJonathan Peyton sizeof_shareds); 10157cc577a4SJonathan Peyton #else /* ! USE_FAST_MEMORY */ 1016*3041982dSJonathan Peyton taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, shareds_offset + 1017*3041982dSJonathan Peyton sizeof_shareds); 10187cc577a4SJonathan Peyton #endif /* USE_FAST_MEMORY */ 10197cc577a4SJonathan Peyton ANNOTATE_HAPPENS_AFTER(taskdata); 10207cc577a4SJonathan Peyton 10217cc577a4SJonathan Peyton task = KMP_TASKDATA_TO_TASK(taskdata); 10227cc577a4SJonathan Peyton 10237cc577a4SJonathan Peyton // Make sure task & taskdata are aligned appropriately 10247cc577a4SJonathan Peyton #if KMP_ARCH_X86 || KMP_ARCH_PPC64 || !KMP_HAVE_QUAD 10257cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(double) - 1)) == 0); 10267cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(double) - 1)) == 0); 10277cc577a4SJonathan Peyton #else 10287cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(_Quad) - 1)) == 0); 10297cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(_Quad) - 1)) == 0); 10307cc577a4SJonathan Peyton #endif 10317cc577a4SJonathan Peyton if (sizeof_shareds > 0) { 10327cc577a4SJonathan Peyton // Avoid double allocation here by combining shareds with taskdata 10337cc577a4SJonathan Peyton task->shareds = &((char *)taskdata)[shareds_offset]; 10347cc577a4SJonathan Peyton // Make sure shareds struct is aligned to pointer size 1035*3041982dSJonathan Peyton KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) == 1036*3041982dSJonathan Peyton 0); 10377cc577a4SJonathan Peyton } else { 10387cc577a4SJonathan Peyton task->shareds = NULL; 10397cc577a4SJonathan Peyton } 10407cc577a4SJonathan Peyton task->routine = task_entry; 10417cc577a4SJonathan Peyton task->part_id = 0; // AC: Always start with 0 part id 10427cc577a4SJonathan Peyton 10437cc577a4SJonathan Peyton taskdata->td_task_id = KMP_GEN_TASK_ID(); 10447cc577a4SJonathan Peyton taskdata->td_team = team; 10457cc577a4SJonathan Peyton taskdata->td_alloc_thread = thread; 10467cc577a4SJonathan Peyton taskdata->td_parent = parent_task; 10477cc577a4SJonathan Peyton taskdata->td_level = parent_task->td_level + 1; // increment nesting level 10487cc577a4SJonathan Peyton taskdata->td_untied_count = 0; 10497cc577a4SJonathan Peyton taskdata->td_ident = loc_ref; 10507cc577a4SJonathan Peyton taskdata->td_taskwait_ident = NULL; 10517cc577a4SJonathan Peyton taskdata->td_taskwait_counter = 0; 10527cc577a4SJonathan Peyton taskdata->td_taskwait_thread = 0; 10537cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_parent != NULL); 10547cc577a4SJonathan Peyton #if OMP_45_ENABLED 10557cc577a4SJonathan Peyton // avoid copying icvs for proxy tasks 10567cc577a4SJonathan Peyton if (flags->proxy == TASK_FULL) 10577cc577a4SJonathan Peyton #endif 10587cc577a4SJonathan Peyton copy_icvs(&taskdata->td_icvs, &taskdata->td_parent->td_icvs); 10597cc577a4SJonathan Peyton 10607cc577a4SJonathan Peyton taskdata->td_flags.tiedness = flags->tiedness; 10617cc577a4SJonathan Peyton taskdata->td_flags.final = flags->final; 10627cc577a4SJonathan Peyton taskdata->td_flags.merged_if0 = flags->merged_if0; 10637cc577a4SJonathan Peyton #if OMP_40_ENABLED 10647cc577a4SJonathan Peyton taskdata->td_flags.destructors_thunk = flags->destructors_thunk; 10657cc577a4SJonathan Peyton #endif // OMP_40_ENABLED 10667cc577a4SJonathan Peyton #if OMP_45_ENABLED 10677cc577a4SJonathan Peyton taskdata->td_flags.proxy = flags->proxy; 10687cc577a4SJonathan Peyton taskdata->td_task_team = thread->th.th_task_team; 10697cc577a4SJonathan Peyton taskdata->td_size_alloc = shareds_offset + sizeof_shareds; 10707cc577a4SJonathan Peyton #endif 10717cc577a4SJonathan Peyton taskdata->td_flags.tasktype = TASK_EXPLICIT; 10727cc577a4SJonathan Peyton 10737cc577a4SJonathan Peyton // GEH - TODO: fix this to copy parent task's value of tasking_ser flag 10747cc577a4SJonathan Peyton taskdata->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec); 10757cc577a4SJonathan Peyton 10767cc577a4SJonathan Peyton // GEH - TODO: fix this to copy parent task's value of team_serial flag 10777cc577a4SJonathan Peyton taskdata->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0; 10787cc577a4SJonathan Peyton 1079*3041982dSJonathan Peyton // GEH - Note we serialize the task if the team is serialized to make sure 1080*3041982dSJonathan Peyton // implicit parallel region tasks are not left until program termination to 1081*3041982dSJonathan Peyton // execute. Also, it helps locality to execute immediately. 1082*3041982dSJonathan Peyton 1083*3041982dSJonathan Peyton taskdata->td_flags.task_serial = 1084*3041982dSJonathan Peyton (parent_task->td_flags.final || taskdata->td_flags.team_serial || 1085*3041982dSJonathan Peyton taskdata->td_flags.tasking_ser); 10867cc577a4SJonathan Peyton 10877cc577a4SJonathan Peyton taskdata->td_flags.started = 0; 10887cc577a4SJonathan Peyton taskdata->td_flags.executing = 0; 10897cc577a4SJonathan Peyton taskdata->td_flags.complete = 0; 10907cc577a4SJonathan Peyton taskdata->td_flags.freed = 0; 10917cc577a4SJonathan Peyton 10927cc577a4SJonathan Peyton taskdata->td_flags.native = flags->native; 10937cc577a4SJonathan Peyton 10947cc577a4SJonathan Peyton taskdata->td_incomplete_child_tasks = 0; 1095*3041982dSJonathan Peyton taskdata->td_allocated_child_tasks = 1; // start at one because counts current 1096*3041982dSJonathan Peyton // task and children 10977cc577a4SJonathan Peyton #if OMP_40_ENABLED 1098*3041982dSJonathan Peyton taskdata->td_taskgroup = 1099*3041982dSJonathan Peyton parent_task->td_taskgroup; // task inherits taskgroup from the parent task 11007cc577a4SJonathan Peyton taskdata->td_dephash = NULL; 11017cc577a4SJonathan Peyton taskdata->td_depnode = NULL; 11027cc577a4SJonathan Peyton #endif 11037cc577a4SJonathan Peyton 1104*3041982dSJonathan Peyton // Only need to keep track of child task counts if team parallel and tasking not 1105*3041982dSJonathan Peyton // serialized or if it is a proxy task 11067cc577a4SJonathan Peyton #if OMP_45_ENABLED 1107*3041982dSJonathan Peyton if (flags->proxy == TASK_PROXY || 1108*3041982dSJonathan Peyton !(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) 11097cc577a4SJonathan Peyton #else 11107cc577a4SJonathan Peyton if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) 11117cc577a4SJonathan Peyton #endif 11127cc577a4SJonathan Peyton { 11137cc577a4SJonathan Peyton KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_incomplete_child_tasks)); 11147cc577a4SJonathan Peyton #if OMP_40_ENABLED 11157cc577a4SJonathan Peyton if (parent_task->td_taskgroup) 11167cc577a4SJonathan Peyton KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_taskgroup->count)); 11177cc577a4SJonathan Peyton #endif 1118*3041982dSJonathan Peyton // Only need to keep track of allocated child tasks for explicit tasks since 1119*3041982dSJonathan Peyton // implicit not deallocated 11207cc577a4SJonathan Peyton if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT) { 1121*3041982dSJonathan Peyton KMP_TEST_THEN_INC32( 1122*3041982dSJonathan Peyton (kmp_int32 *)(&taskdata->td_parent->td_allocated_child_tasks)); 11237cc577a4SJonathan Peyton } 11247cc577a4SJonathan Peyton } 11257cc577a4SJonathan Peyton 11267cc577a4SJonathan Peyton KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n", 11277cc577a4SJonathan Peyton gtid, taskdata, taskdata->td_parent)); 11287cc577a4SJonathan Peyton ANNOTATE_HAPPENS_BEFORE(task); 11297cc577a4SJonathan Peyton 11307cc577a4SJonathan Peyton #if OMPT_SUPPORT 11317cc577a4SJonathan Peyton __kmp_task_init_ompt(taskdata, gtid, (void *)task_entry); 11327cc577a4SJonathan Peyton #endif 11337cc577a4SJonathan Peyton 11347cc577a4SJonathan Peyton return task; 11357cc577a4SJonathan Peyton } 11367cc577a4SJonathan Peyton 1137*3041982dSJonathan Peyton kmp_task_t *__kmpc_omp_task_alloc(ident_t *loc_ref, kmp_int32 gtid, 1138*3041982dSJonathan Peyton kmp_int32 flags, size_t sizeof_kmp_task_t, 1139*3041982dSJonathan Peyton size_t sizeof_shareds, 1140*3041982dSJonathan Peyton kmp_routine_entry_t task_entry) { 11417cc577a4SJonathan Peyton kmp_task_t *retval; 11427cc577a4SJonathan Peyton kmp_tasking_flags_t *input_flags = (kmp_tasking_flags_t *)&flags; 11437cc577a4SJonathan Peyton 11447cc577a4SJonathan Peyton input_flags->native = FALSE; 11457cc577a4SJonathan Peyton // __kmp_task_alloc() sets up all other runtime flags 11467cc577a4SJonathan Peyton 11477cc577a4SJonathan Peyton #if OMP_45_ENABLED 11487cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s %s) " 11497cc577a4SJonathan Peyton "sizeof_task=%ld sizeof_shared=%ld entry=%p\n", 11507cc577a4SJonathan Peyton gtid, loc_ref, input_flags->tiedness ? "tied " : "untied", 1151*3041982dSJonathan Peyton input_flags->proxy ? "proxy" : "", sizeof_kmp_task_t, 1152*3041982dSJonathan Peyton sizeof_shareds, task_entry)); 11537cc577a4SJonathan Peyton #else 11547cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s) " 11557cc577a4SJonathan Peyton "sizeof_task=%ld sizeof_shared=%ld entry=%p\n", 11567cc577a4SJonathan Peyton gtid, loc_ref, input_flags->tiedness ? "tied " : "untied", 11577cc577a4SJonathan Peyton sizeof_kmp_task_t, sizeof_shareds, task_entry)); 11587cc577a4SJonathan Peyton #endif 11597cc577a4SJonathan Peyton 11607cc577a4SJonathan Peyton retval = __kmp_task_alloc(loc_ref, gtid, input_flags, sizeof_kmp_task_t, 11617cc577a4SJonathan Peyton sizeof_shareds, task_entry); 11627cc577a4SJonathan Peyton 11637cc577a4SJonathan Peyton KA_TRACE(20, ("__kmpc_omp_task_alloc(exit): T#%d retval %p\n", gtid, retval)); 11647cc577a4SJonathan Peyton 11657cc577a4SJonathan Peyton return retval; 11667cc577a4SJonathan Peyton } 11677cc577a4SJonathan Peyton 11687cc577a4SJonathan Peyton // __kmp_invoke_task: invoke the specified task 11697cc577a4SJonathan Peyton // 11707cc577a4SJonathan Peyton // gtid: global thread ID of caller 11717cc577a4SJonathan Peyton // task: the task to invoke 11727cc577a4SJonathan Peyton // current_task: the task to resume after task invokation 1173*3041982dSJonathan Peyton static void __kmp_invoke_task(kmp_int32 gtid, kmp_task_t *task, 1174*3041982dSJonathan Peyton kmp_taskdata_t *current_task) { 11757cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 11767cc577a4SJonathan Peyton kmp_uint64 cur_time; 11777cc577a4SJonathan Peyton #if OMP_40_ENABLED 11787cc577a4SJonathan Peyton int discard = 0 /* false */; 11797cc577a4SJonathan Peyton #endif 1180*3041982dSJonathan Peyton KA_TRACE( 1181*3041982dSJonathan Peyton 30, ("__kmp_invoke_task(enter): T#%d invoking task %p, current_task=%p\n", 11827cc577a4SJonathan Peyton gtid, taskdata, current_task)); 11837cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task); 11847cc577a4SJonathan Peyton #if OMP_45_ENABLED 11857cc577a4SJonathan Peyton if (taskdata->td_flags.proxy == TASK_PROXY && 1186*3041982dSJonathan Peyton taskdata->td_flags.complete == 1) { 11877cc577a4SJonathan Peyton // This is a proxy task that was already completed but it needs to run 11887cc577a4SJonathan Peyton // its bottom-half finish 1189*3041982dSJonathan Peyton KA_TRACE( 1190*3041982dSJonathan Peyton 30, 1191*3041982dSJonathan Peyton ("__kmp_invoke_task: T#%d running bottom finish for proxy task %p\n", 11927cc577a4SJonathan Peyton gtid, taskdata)); 11937cc577a4SJonathan Peyton 11947cc577a4SJonathan Peyton __kmp_bottom_half_finish_proxy(gtid, task); 11957cc577a4SJonathan Peyton 1196*3041982dSJonathan Peyton KA_TRACE(30, ("__kmp_invoke_task(exit): T#%d completed bottom finish for " 1197*3041982dSJonathan Peyton "proxy task %p, resuming task %p\n", 1198*3041982dSJonathan Peyton gtid, taskdata, current_task)); 11997cc577a4SJonathan Peyton 12007cc577a4SJonathan Peyton return; 12017cc577a4SJonathan Peyton } 12027cc577a4SJonathan Peyton #endif 12037cc577a4SJonathan Peyton 12047cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY 12057cc577a4SJonathan Peyton if (__kmp_forkjoin_frames_mode == 3) { 1206*3041982dSJonathan Peyton // Get the current time stamp to measure task execution time to correct 1207*3041982dSJonathan Peyton // barrier imbalance time 12087cc577a4SJonathan Peyton cur_time = __itt_get_timestamp(); 12097cc577a4SJonathan Peyton } 12107cc577a4SJonathan Peyton #endif 12117cc577a4SJonathan Peyton 12127cc577a4SJonathan Peyton #if OMP_45_ENABLED 12137cc577a4SJonathan Peyton // Proxy tasks are not handled by the runtime 12147cc577a4SJonathan Peyton if (taskdata->td_flags.proxy != TASK_PROXY) { 12157cc577a4SJonathan Peyton #endif 12167cc577a4SJonathan Peyton ANNOTATE_HAPPENS_AFTER(task); 12177cc577a4SJonathan Peyton __kmp_task_start(gtid, task, current_task); 12187cc577a4SJonathan Peyton #if OMP_45_ENABLED 12197cc577a4SJonathan Peyton } 12207cc577a4SJonathan Peyton #endif 12217cc577a4SJonathan Peyton 12227cc577a4SJonathan Peyton #if OMPT_SUPPORT 12237cc577a4SJonathan Peyton ompt_thread_info_t oldInfo; 12247cc577a4SJonathan Peyton kmp_info_t *thread; 12257cc577a4SJonathan Peyton if (ompt_enabled) { 12267cc577a4SJonathan Peyton // Store the threads states and restore them after the task 12277cc577a4SJonathan Peyton thread = __kmp_threads[gtid]; 12287cc577a4SJonathan Peyton oldInfo = thread->th.ompt_thread_info; 12297cc577a4SJonathan Peyton thread->th.ompt_thread_info.wait_id = 0; 12307cc577a4SJonathan Peyton thread->th.ompt_thread_info.state = ompt_state_work_parallel; 1231*3041982dSJonathan Peyton taskdata->ompt_task_info.frame.exit_runtime_frame = 1232*3041982dSJonathan Peyton __builtin_frame_address(0); 12337cc577a4SJonathan Peyton } 12347cc577a4SJonathan Peyton #endif 12357cc577a4SJonathan Peyton 12367cc577a4SJonathan Peyton #if OMP_40_ENABLED 12377cc577a4SJonathan Peyton // TODO: cancel tasks if the parallel region has also been cancelled 12387cc577a4SJonathan Peyton // TODO: check if this sequence can be hoisted above __kmp_task_start 12397cc577a4SJonathan Peyton // if cancellation has been enabled for this run ... 12407cc577a4SJonathan Peyton if (__kmp_omp_cancellation) { 12417cc577a4SJonathan Peyton kmp_info_t *this_thr = __kmp_threads[gtid]; 12427cc577a4SJonathan Peyton kmp_team_t *this_team = this_thr->th.th_team; 12437cc577a4SJonathan Peyton kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup; 1244*3041982dSJonathan Peyton if ((taskgroup && taskgroup->cancel_request) || 1245*3041982dSJonathan Peyton (this_team->t.t_cancel_request == cancel_parallel)) { 12467cc577a4SJonathan Peyton KMP_COUNT_BLOCK(TASK_cancelled); 12477cc577a4SJonathan Peyton // this task belongs to a task group and we need to cancel it 12487cc577a4SJonathan Peyton discard = 1 /* true */; 12497cc577a4SJonathan Peyton } 12507cc577a4SJonathan Peyton } 12517cc577a4SJonathan Peyton 12527cc577a4SJonathan Peyton // Invoke the task routine and pass in relevant data. 12537cc577a4SJonathan Peyton // Thunks generated by gcc take a different argument list. 12547cc577a4SJonathan Peyton if (!discard) { 12557cc577a4SJonathan Peyton #if KMP_STATS_ENABLED 12567cc577a4SJonathan Peyton KMP_COUNT_BLOCK(TASK_executed); 12577cc577a4SJonathan Peyton switch (KMP_GET_THREAD_STATE()) { 1258*3041982dSJonathan Peyton case FORK_JOIN_BARRIER: 1259*3041982dSJonathan Peyton KMP_PUSH_PARTITIONED_TIMER(OMP_task_join_bar); 1260*3041982dSJonathan Peyton break; 1261*3041982dSJonathan Peyton case PLAIN_BARRIER: 1262*3041982dSJonathan Peyton KMP_PUSH_PARTITIONED_TIMER(OMP_task_plain_bar); 1263*3041982dSJonathan Peyton break; 1264*3041982dSJonathan Peyton case TASKYIELD: 1265*3041982dSJonathan Peyton KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskyield); 1266*3041982dSJonathan Peyton break; 1267*3041982dSJonathan Peyton case TASKWAIT: 1268*3041982dSJonathan Peyton KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskwait); 1269*3041982dSJonathan Peyton break; 1270*3041982dSJonathan Peyton case TASKGROUP: 1271*3041982dSJonathan Peyton KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskgroup); 1272*3041982dSJonathan Peyton break; 1273*3041982dSJonathan Peyton default: 1274*3041982dSJonathan Peyton KMP_PUSH_PARTITIONED_TIMER(OMP_task_immediate); 1275*3041982dSJonathan Peyton break; 12767cc577a4SJonathan Peyton } 12777cc577a4SJonathan Peyton #endif // KMP_STATS_ENABLED 12787cc577a4SJonathan Peyton #endif // OMP_40_ENABLED 12797cc577a4SJonathan Peyton 12807cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE 12817cc577a4SJonathan Peyton /* let OMPT know that we're about to run this task */ 1282*3041982dSJonathan Peyton if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_switch)) { 12837cc577a4SJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_task_switch)( 12847cc577a4SJonathan Peyton current_task->ompt_task_info.task_id, 12857cc577a4SJonathan Peyton taskdata->ompt_task_info.task_id); 12867cc577a4SJonathan Peyton } 12877cc577a4SJonathan Peyton #endif 12887cc577a4SJonathan Peyton 12897cc577a4SJonathan Peyton #ifdef KMP_GOMP_COMPAT 12907cc577a4SJonathan Peyton if (taskdata->td_flags.native) { 12917cc577a4SJonathan Peyton ((void (*)(void *))(*(task->routine)))(task->shareds); 1292*3041982dSJonathan Peyton } else 12937cc577a4SJonathan Peyton #endif /* KMP_GOMP_COMPAT */ 12947cc577a4SJonathan Peyton { 12957cc577a4SJonathan Peyton (*(task->routine))(gtid, task); 12967cc577a4SJonathan Peyton } 12977cc577a4SJonathan Peyton KMP_POP_PARTITIONED_TIMER(); 12987cc577a4SJonathan Peyton 12997cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE 13007cc577a4SJonathan Peyton /* let OMPT know that we're returning to the callee task */ 1301*3041982dSJonathan Peyton if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_switch)) { 13027cc577a4SJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_task_switch)( 13037cc577a4SJonathan Peyton taskdata->ompt_task_info.task_id, 13047cc577a4SJonathan Peyton current_task->ompt_task_info.task_id); 13057cc577a4SJonathan Peyton } 13067cc577a4SJonathan Peyton #endif 13077cc577a4SJonathan Peyton 13087cc577a4SJonathan Peyton #if OMP_40_ENABLED 13097cc577a4SJonathan Peyton } 13107cc577a4SJonathan Peyton #endif // OMP_40_ENABLED 13117cc577a4SJonathan Peyton 13127cc577a4SJonathan Peyton #if OMPT_SUPPORT 13137cc577a4SJonathan Peyton if (ompt_enabled) { 13147cc577a4SJonathan Peyton thread->th.ompt_thread_info = oldInfo; 13157cc577a4SJonathan Peyton taskdata->ompt_task_info.frame.exit_runtime_frame = NULL; 13167cc577a4SJonathan Peyton } 13177cc577a4SJonathan Peyton #endif 13187cc577a4SJonathan Peyton 13197cc577a4SJonathan Peyton #if OMP_45_ENABLED 13207cc577a4SJonathan Peyton // Proxy tasks are not handled by the runtime 13217cc577a4SJonathan Peyton if (taskdata->td_flags.proxy != TASK_PROXY) { 13227cc577a4SJonathan Peyton #endif 13237cc577a4SJonathan Peyton ANNOTATE_HAPPENS_BEFORE(taskdata->td_parent); 13247cc577a4SJonathan Peyton __kmp_task_finish(gtid, task, current_task); 13257cc577a4SJonathan Peyton #if OMP_45_ENABLED 13267cc577a4SJonathan Peyton } 13277cc577a4SJonathan Peyton #endif 13287cc577a4SJonathan Peyton 13297cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY 13307cc577a4SJonathan Peyton // Barrier imbalance - correct arrive time after the task finished 13317cc577a4SJonathan Peyton if (__kmp_forkjoin_frames_mode == 3) { 13327cc577a4SJonathan Peyton kmp_info_t *this_thr = __kmp_threads[gtid]; 13337cc577a4SJonathan Peyton if (this_thr->th.th_bar_arrive_time) { 13347cc577a4SJonathan Peyton this_thr->th.th_bar_arrive_time += (__itt_get_timestamp() - cur_time); 13357cc577a4SJonathan Peyton } 13367cc577a4SJonathan Peyton } 13377cc577a4SJonathan Peyton #endif 1338*3041982dSJonathan Peyton KA_TRACE( 1339*3041982dSJonathan Peyton 30, 1340*3041982dSJonathan Peyton ("__kmp_invoke_task(exit): T#%d completed task %p, resuming task %p\n", 13417cc577a4SJonathan Peyton gtid, taskdata, current_task)); 13427cc577a4SJonathan Peyton return; 13437cc577a4SJonathan Peyton } 13447cc577a4SJonathan Peyton 13457cc577a4SJonathan Peyton // __kmpc_omp_task_parts: Schedule a thread-switchable task for execution 13467cc577a4SJonathan Peyton // 13477cc577a4SJonathan Peyton // loc_ref: location of original task pragma (ignored) 13487cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread 13497cc577a4SJonathan Peyton // new_task: task thunk allocated by __kmp_omp_task_alloc() for the ''new task'' 13507cc577a4SJonathan Peyton // Returns: 1351*3041982dSJonathan Peyton // TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to 1352*3041982dSJonathan Peyton // be resumed later. 1353*3041982dSJonathan Peyton // TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be 1354*3041982dSJonathan Peyton // resumed later. 1355*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_task_parts(ident_t *loc_ref, kmp_int32 gtid, 1356*3041982dSJonathan Peyton kmp_task_t *new_task) { 13577cc577a4SJonathan Peyton kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task); 13587cc577a4SJonathan Peyton 1359*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task_parts(enter): T#%d loc=%p task=%p\n", gtid, 1360*3041982dSJonathan Peyton loc_ref, new_taskdata)); 13617cc577a4SJonathan Peyton 1362*3041982dSJonathan Peyton /* Should we execute the new task or queue it? For now, let's just always try 1363*3041982dSJonathan Peyton to queue it. If the queue fills up, then we'll execute it. */ 13647cc577a4SJonathan Peyton 13657cc577a4SJonathan Peyton if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer 13667cc577a4SJonathan Peyton { // Execute this task immediately 13677cc577a4SJonathan Peyton kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 13687cc577a4SJonathan Peyton new_taskdata->td_flags.task_serial = 1; 13697cc577a4SJonathan Peyton __kmp_invoke_task(gtid, new_task, current_task); 13707cc577a4SJonathan Peyton } 13717cc577a4SJonathan Peyton 1372*3041982dSJonathan Peyton KA_TRACE( 1373*3041982dSJonathan Peyton 10, 1374*3041982dSJonathan Peyton ("__kmpc_omp_task_parts(exit): T#%d returning TASK_CURRENT_NOT_QUEUED: " 1375*3041982dSJonathan Peyton "loc=%p task=%p, return: TASK_CURRENT_NOT_QUEUED\n", 1376*3041982dSJonathan Peyton gtid, loc_ref, new_taskdata)); 13777cc577a4SJonathan Peyton 13787cc577a4SJonathan Peyton ANNOTATE_HAPPENS_BEFORE(new_task); 13797cc577a4SJonathan Peyton return TASK_CURRENT_NOT_QUEUED; 13807cc577a4SJonathan Peyton } 13817cc577a4SJonathan Peyton 13827cc577a4SJonathan Peyton // __kmp_omp_task: Schedule a non-thread-switchable task for execution 1383*3041982dSJonathan Peyton // 13847cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread 13857cc577a4SJonathan Peyton // new_task:non-thread-switchable task thunk allocated by __kmp_omp_task_alloc() 1386*3041982dSJonathan Peyton // serialize_immediate: if TRUE then if the task is executed immediately its 1387*3041982dSJonathan Peyton // execution will be serialized 1388*3041982dSJonathan Peyton // Returns: 1389*3041982dSJonathan Peyton // TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to 1390*3041982dSJonathan Peyton // be resumed later. 1391*3041982dSJonathan Peyton // TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be 1392*3041982dSJonathan Peyton // resumed later. 1393*3041982dSJonathan Peyton kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task, 1394*3041982dSJonathan Peyton bool serialize_immediate) { 13957cc577a4SJonathan Peyton kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task); 13967cc577a4SJonathan Peyton 13977cc577a4SJonathan Peyton #if OMPT_SUPPORT 13987cc577a4SJonathan Peyton if (ompt_enabled) { 13997cc577a4SJonathan Peyton new_taskdata->ompt_task_info.frame.reenter_runtime_frame = 14007cc577a4SJonathan Peyton __builtin_frame_address(1); 14017cc577a4SJonathan Peyton } 14027cc577a4SJonathan Peyton #endif 14037cc577a4SJonathan Peyton 14047cc577a4SJonathan Peyton /* Should we execute the new task or queue it? For now, let's just always try to 14057cc577a4SJonathan Peyton queue it. If the queue fills up, then we'll execute it. */ 14067cc577a4SJonathan Peyton #if OMP_45_ENABLED 1407*3041982dSJonathan Peyton if (new_taskdata->td_flags.proxy == TASK_PROXY || 1408*3041982dSJonathan Peyton __kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer 14097cc577a4SJonathan Peyton #else 14107cc577a4SJonathan Peyton if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer 14117cc577a4SJonathan Peyton #endif 14127cc577a4SJonathan Peyton { // Execute this task immediately 14137cc577a4SJonathan Peyton kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task; 14147cc577a4SJonathan Peyton if (serialize_immediate) 14157cc577a4SJonathan Peyton new_taskdata->td_flags.task_serial = 1; 14167cc577a4SJonathan Peyton __kmp_invoke_task(gtid, new_task, current_task); 14177cc577a4SJonathan Peyton } 14187cc577a4SJonathan Peyton 14197cc577a4SJonathan Peyton #if OMPT_SUPPORT 14207cc577a4SJonathan Peyton if (ompt_enabled) { 14217cc577a4SJonathan Peyton new_taskdata->ompt_task_info.frame.reenter_runtime_frame = NULL; 14227cc577a4SJonathan Peyton } 14237cc577a4SJonathan Peyton #endif 14247cc577a4SJonathan Peyton 14257cc577a4SJonathan Peyton ANNOTATE_HAPPENS_BEFORE(new_task); 14267cc577a4SJonathan Peyton return TASK_CURRENT_NOT_QUEUED; 14277cc577a4SJonathan Peyton } 14287cc577a4SJonathan Peyton 1429*3041982dSJonathan Peyton // __kmpc_omp_task: Wrapper around __kmp_omp_task to schedule a 1430*3041982dSJonathan Peyton // non-thread-switchable task from the parent thread only! 1431*3041982dSJonathan Peyton // 14327cc577a4SJonathan Peyton // loc_ref: location of original task pragma (ignored) 14337cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread 1434*3041982dSJonathan Peyton // new_task: non-thread-switchable task thunk allocated by 1435*3041982dSJonathan Peyton // __kmp_omp_task_alloc() 1436*3041982dSJonathan Peyton // Returns: 1437*3041982dSJonathan Peyton // TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to 1438*3041982dSJonathan Peyton // be resumed later. 1439*3041982dSJonathan Peyton // TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be 1440*3041982dSJonathan Peyton // resumed later. 1441*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_task(ident_t *loc_ref, kmp_int32 gtid, 1442*3041982dSJonathan Peyton kmp_task_t *new_task) { 14437cc577a4SJonathan Peyton kmp_int32 res; 14447cc577a4SJonathan Peyton KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK); 14457cc577a4SJonathan Peyton 14467cc577a4SJonathan Peyton #if KMP_DEBUG 14477cc577a4SJonathan Peyton kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task); 14487cc577a4SJonathan Peyton #endif 1449*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref, 1450*3041982dSJonathan Peyton new_taskdata)); 14517cc577a4SJonathan Peyton 14527cc577a4SJonathan Peyton res = __kmp_omp_task(gtid, new_task, true); 14537cc577a4SJonathan Peyton 1454*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning " 1455*3041982dSJonathan Peyton "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n", 14567cc577a4SJonathan Peyton gtid, loc_ref, new_taskdata)); 14577cc577a4SJonathan Peyton return res; 14587cc577a4SJonathan Peyton } 14597cc577a4SJonathan Peyton 1460*3041982dSJonathan Peyton // __kmpc_omp_taskwait: Wait until all tasks generated by the current task are 1461*3041982dSJonathan Peyton // complete 1462*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_taskwait(ident_t *loc_ref, kmp_int32 gtid) { 14637cc577a4SJonathan Peyton kmp_taskdata_t *taskdata; 14647cc577a4SJonathan Peyton kmp_info_t *thread; 14657cc577a4SJonathan Peyton int thread_finished = FALSE; 14667cc577a4SJonathan Peyton KMP_SET_THREAD_STATE_BLOCK(TASKWAIT); 14677cc577a4SJonathan Peyton 14687cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_taskwait(enter): T#%d loc=%p\n", gtid, loc_ref)); 14697cc577a4SJonathan Peyton 14707cc577a4SJonathan Peyton if (__kmp_tasking_mode != tskm_immediate_exec) { 1471*3041982dSJonathan Peyton // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark 1472*3041982dSJonathan Peyton // begin wait? 14737cc577a4SJonathan Peyton 14747cc577a4SJonathan Peyton thread = __kmp_threads[gtid]; 14757cc577a4SJonathan Peyton taskdata = thread->th.th_current_task; 14767cc577a4SJonathan Peyton 14777cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE 14787cc577a4SJonathan Peyton ompt_task_id_t my_task_id; 14797cc577a4SJonathan Peyton ompt_parallel_id_t my_parallel_id; 14807cc577a4SJonathan Peyton 14817cc577a4SJonathan Peyton if (ompt_enabled) { 14827cc577a4SJonathan Peyton kmp_team_t *team = thread->th.th_team; 14837cc577a4SJonathan Peyton my_task_id = taskdata->ompt_task_info.task_id; 14847cc577a4SJonathan Peyton my_parallel_id = team->t.ompt_team_info.parallel_id; 14857cc577a4SJonathan Peyton 1486*3041982dSJonathan Peyton taskdata->ompt_task_info.frame.reenter_runtime_frame = 1487*3041982dSJonathan Peyton __builtin_frame_address(1); 14887cc577a4SJonathan Peyton if (ompt_callbacks.ompt_callback(ompt_event_taskwait_begin)) { 1489*3041982dSJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_taskwait_begin)(my_parallel_id, 1490*3041982dSJonathan Peyton my_task_id); 14917cc577a4SJonathan Peyton } 14927cc577a4SJonathan Peyton } 14937cc577a4SJonathan Peyton #endif 14947cc577a4SJonathan Peyton 1495*3041982dSJonathan Peyton // Debugger: The taskwait is active. Store location and thread encountered the 1496*3041982dSJonathan Peyton // taskwait. 14977cc577a4SJonathan Peyton #if USE_ITT_BUILD 14987cc577a4SJonathan Peyton // Note: These values are used by ITT events as well. 14997cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 15007cc577a4SJonathan Peyton taskdata->td_taskwait_counter += 1; 15017cc577a4SJonathan Peyton taskdata->td_taskwait_ident = loc_ref; 15027cc577a4SJonathan Peyton taskdata->td_taskwait_thread = gtid + 1; 15037cc577a4SJonathan Peyton 15047cc577a4SJonathan Peyton #if USE_ITT_BUILD 15057cc577a4SJonathan Peyton void *itt_sync_obj = __kmp_itt_taskwait_object(gtid); 15067cc577a4SJonathan Peyton if (itt_sync_obj != NULL) 15077cc577a4SJonathan Peyton __kmp_itt_taskwait_starting(gtid, itt_sync_obj); 15087cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 15097cc577a4SJonathan Peyton 1510*3041982dSJonathan Peyton bool must_wait = 1511*3041982dSJonathan Peyton !taskdata->td_flags.team_serial && !taskdata->td_flags.final; 15127cc577a4SJonathan Peyton 15137cc577a4SJonathan Peyton #if OMP_45_ENABLED 1514*3041982dSJonathan Peyton must_wait = must_wait || (thread->th.th_task_team != NULL && 1515*3041982dSJonathan Peyton thread->th.th_task_team->tt.tt_found_proxy_tasks); 15167cc577a4SJonathan Peyton #endif 1517*3041982dSJonathan Peyton if (must_wait) { 15187cc577a4SJonathan Peyton kmp_flag_32 flag(&(taskdata->td_incomplete_child_tasks), 0U); 15197cc577a4SJonathan Peyton while (TCR_4(taskdata->td_incomplete_child_tasks) != 0) { 1520*3041982dSJonathan Peyton flag.execute_tasks(thread, gtid, FALSE, 1521*3041982dSJonathan Peyton &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), 1522*3041982dSJonathan Peyton __kmp_task_stealing_constraint); 15237cc577a4SJonathan Peyton } 15247cc577a4SJonathan Peyton } 15257cc577a4SJonathan Peyton #if USE_ITT_BUILD 15267cc577a4SJonathan Peyton if (itt_sync_obj != NULL) 15277cc577a4SJonathan Peyton __kmp_itt_taskwait_finished(gtid, itt_sync_obj); 15287cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 15297cc577a4SJonathan Peyton 1530*3041982dSJonathan Peyton // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark 1531*3041982dSJonathan Peyton // end of wait? 1532*3041982dSJonathan Peyton // Debugger: The taskwait is completed. Location remains, but thread is 1533*3041982dSJonathan Peyton // negated. 15347cc577a4SJonathan Peyton taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread; 15357cc577a4SJonathan Peyton 15367cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE 15377cc577a4SJonathan Peyton if (ompt_enabled) { 15387cc577a4SJonathan Peyton if (ompt_callbacks.ompt_callback(ompt_event_taskwait_end)) { 1539*3041982dSJonathan Peyton ompt_callbacks.ompt_callback(ompt_event_taskwait_end)(my_parallel_id, 1540*3041982dSJonathan Peyton my_task_id); 15417cc577a4SJonathan Peyton } 15427cc577a4SJonathan Peyton taskdata->ompt_task_info.frame.reenter_runtime_frame = NULL; 15437cc577a4SJonathan Peyton } 15447cc577a4SJonathan Peyton #endif 15457cc577a4SJonathan Peyton ANNOTATE_HAPPENS_AFTER(taskdata); 15467cc577a4SJonathan Peyton } 15477cc577a4SJonathan Peyton 15487cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_taskwait(exit): T#%d task %p finished waiting, " 1549*3041982dSJonathan Peyton "returning TASK_CURRENT_NOT_QUEUED\n", 1550*3041982dSJonathan Peyton gtid, taskdata)); 15517cc577a4SJonathan Peyton 15527cc577a4SJonathan Peyton return TASK_CURRENT_NOT_QUEUED; 15537cc577a4SJonathan Peyton } 15547cc577a4SJonathan Peyton 15557cc577a4SJonathan Peyton // __kmpc_omp_taskyield: switch to a different task 1556*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_taskyield(ident_t *loc_ref, kmp_int32 gtid, int end_part) { 15577cc577a4SJonathan Peyton kmp_taskdata_t *taskdata; 15587cc577a4SJonathan Peyton kmp_info_t *thread; 15597cc577a4SJonathan Peyton int thread_finished = FALSE; 15607cc577a4SJonathan Peyton 15617cc577a4SJonathan Peyton KMP_COUNT_BLOCK(OMP_TASKYIELD); 15627cc577a4SJonathan Peyton KMP_SET_THREAD_STATE_BLOCK(TASKYIELD); 15637cc577a4SJonathan Peyton 15647cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_taskyield(enter): T#%d loc=%p end_part = %d\n", 15657cc577a4SJonathan Peyton gtid, loc_ref, end_part)); 15667cc577a4SJonathan Peyton 15677cc577a4SJonathan Peyton if (__kmp_tasking_mode != tskm_immediate_exec && __kmp_init_parallel) { 1568*3041982dSJonathan Peyton // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark 1569*3041982dSJonathan Peyton // begin wait? 15707cc577a4SJonathan Peyton 15717cc577a4SJonathan Peyton thread = __kmp_threads[gtid]; 15727cc577a4SJonathan Peyton taskdata = thread->th.th_current_task; 15737cc577a4SJonathan Peyton // Should we model this as a task wait or not? 1574*3041982dSJonathan Peyton // Debugger: The taskwait is active. Store location and thread encountered the 1575*3041982dSJonathan Peyton // taskwait. 15767cc577a4SJonathan Peyton #if USE_ITT_BUILD 15777cc577a4SJonathan Peyton // Note: These values are used by ITT events as well. 15787cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 15797cc577a4SJonathan Peyton taskdata->td_taskwait_counter += 1; 15807cc577a4SJonathan Peyton taskdata->td_taskwait_ident = loc_ref; 15817cc577a4SJonathan Peyton taskdata->td_taskwait_thread = gtid + 1; 15827cc577a4SJonathan Peyton 15837cc577a4SJonathan Peyton #if USE_ITT_BUILD 15847cc577a4SJonathan Peyton void *itt_sync_obj = __kmp_itt_taskwait_object(gtid); 15857cc577a4SJonathan Peyton if (itt_sync_obj != NULL) 15867cc577a4SJonathan Peyton __kmp_itt_taskwait_starting(gtid, itt_sync_obj); 15877cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 15887cc577a4SJonathan Peyton if (!taskdata->td_flags.team_serial) { 15897cc577a4SJonathan Peyton kmp_task_team_t *task_team = thread->th.th_task_team; 15907cc577a4SJonathan Peyton if (task_team != NULL) { 15917cc577a4SJonathan Peyton if (KMP_TASKING_ENABLED(task_team)) { 1592*3041982dSJonathan Peyton __kmp_execute_tasks_32( 1593*3041982dSJonathan Peyton thread, gtid, NULL, FALSE, 1594*3041982dSJonathan Peyton &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), 1595*3041982dSJonathan Peyton __kmp_task_stealing_constraint); 15967cc577a4SJonathan Peyton } 15977cc577a4SJonathan Peyton } 15987cc577a4SJonathan Peyton } 15997cc577a4SJonathan Peyton #if USE_ITT_BUILD 16007cc577a4SJonathan Peyton if (itt_sync_obj != NULL) 16017cc577a4SJonathan Peyton __kmp_itt_taskwait_finished(gtid, itt_sync_obj); 16027cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 16037cc577a4SJonathan Peyton 1604*3041982dSJonathan Peyton // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark 1605*3041982dSJonathan Peyton // end of wait? 1606*3041982dSJonathan Peyton // Debugger: The taskwait is completed. Location remains, but thread is 1607*3041982dSJonathan Peyton // negated. 16087cc577a4SJonathan Peyton taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread; 16097cc577a4SJonathan Peyton } 16107cc577a4SJonathan Peyton 16117cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_omp_taskyield(exit): T#%d task %p resuming, " 1612*3041982dSJonathan Peyton "returning TASK_CURRENT_NOT_QUEUED\n", 1613*3041982dSJonathan Peyton gtid, taskdata)); 16147cc577a4SJonathan Peyton 16157cc577a4SJonathan Peyton return TASK_CURRENT_NOT_QUEUED; 16167cc577a4SJonathan Peyton } 16177cc577a4SJonathan Peyton 161872ba2109SAndrey Churbanov // TODO: change to OMP_50_ENABLED, need to change build tools for this to work 161972ba2109SAndrey Churbanov #if OMP_45_ENABLED 162072ba2109SAndrey Churbanov // Task Reduction implementation 162172ba2109SAndrey Churbanov 162272ba2109SAndrey Churbanov typedef struct kmp_task_red_flags { 162372ba2109SAndrey Churbanov unsigned lazy_priv : 1; // hint: (1) use lazy allocation (big objects) 162472ba2109SAndrey Churbanov unsigned reserved31 : 31; 162572ba2109SAndrey Churbanov } kmp_task_red_flags_t; 162672ba2109SAndrey Churbanov 162772ba2109SAndrey Churbanov // internal structure for reduction data item related info 162872ba2109SAndrey Churbanov typedef struct kmp_task_red_data { 162972ba2109SAndrey Churbanov void *reduce_shar; // shared reduction item 163072ba2109SAndrey Churbanov size_t reduce_size; // size of data item 163172ba2109SAndrey Churbanov void *reduce_priv; // thread specific data 163272ba2109SAndrey Churbanov void *reduce_pend; // end of private data for comparison op 163372ba2109SAndrey Churbanov void *reduce_init; // data initialization routine 163472ba2109SAndrey Churbanov void *reduce_fini; // data finalization routine 163572ba2109SAndrey Churbanov void *reduce_comb; // data combiner routine 163672ba2109SAndrey Churbanov kmp_task_red_flags_t flags; // flags for additional info from compiler 163772ba2109SAndrey Churbanov } kmp_task_red_data_t; 163872ba2109SAndrey Churbanov 163972ba2109SAndrey Churbanov // structure sent us by compiler - one per reduction item 164072ba2109SAndrey Churbanov typedef struct kmp_task_red_input { 164172ba2109SAndrey Churbanov void *reduce_shar; // shared reduction item 164272ba2109SAndrey Churbanov size_t reduce_size; // size of data item 164372ba2109SAndrey Churbanov void *reduce_init; // data initialization routine 164472ba2109SAndrey Churbanov void *reduce_fini; // data finalization routine 164572ba2109SAndrey Churbanov void *reduce_comb; // data combiner routine 164672ba2109SAndrey Churbanov kmp_task_red_flags_t flags; // flags for additional info from compiler 164772ba2109SAndrey Churbanov } kmp_task_red_input_t; 164872ba2109SAndrey Churbanov 164972ba2109SAndrey Churbanov /*! 165072ba2109SAndrey Churbanov @ingroup TASKING 165172ba2109SAndrey Churbanov @param gtid Global thread ID 165272ba2109SAndrey Churbanov @param num Number of data items to reduce 165372ba2109SAndrey Churbanov @param data Array of data for reduction 165472ba2109SAndrey Churbanov @return The taskgroup identifier 165572ba2109SAndrey Churbanov 165672ba2109SAndrey Churbanov Initialize task reduction for the taskgroup. 165772ba2109SAndrey Churbanov */ 1658*3041982dSJonathan Peyton void *__kmpc_task_reduction_init(int gtid, int num, void *data) { 165972ba2109SAndrey Churbanov kmp_info_t *thread = __kmp_threads[gtid]; 166072ba2109SAndrey Churbanov kmp_taskgroup_t *tg = thread->th.th_current_task->td_taskgroup; 166172ba2109SAndrey Churbanov kmp_int32 nth = thread->th.th_team_nproc; 166272ba2109SAndrey Churbanov kmp_task_red_input_t *input = (kmp_task_red_input_t *)data; 166372ba2109SAndrey Churbanov kmp_task_red_data_t *arr; 166472ba2109SAndrey Churbanov 166572ba2109SAndrey Churbanov // check input data just in case 166672ba2109SAndrey Churbanov KMP_ASSERT(tg != NULL); 166772ba2109SAndrey Churbanov KMP_ASSERT(data != NULL); 166872ba2109SAndrey Churbanov KMP_ASSERT(num > 0); 166972ba2109SAndrey Churbanov if (nth == 1) { 167072ba2109SAndrey Churbanov KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, tg %p, exiting nth=1\n", 167172ba2109SAndrey Churbanov gtid, tg)); 167272ba2109SAndrey Churbanov return (void *)tg; 167372ba2109SAndrey Churbanov } 167472ba2109SAndrey Churbanov KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, taskgroup %p, #items %d\n", 167572ba2109SAndrey Churbanov gtid, tg, num)); 1676*3041982dSJonathan Peyton arr = (kmp_task_red_data_t *)__kmp_thread_malloc( 1677*3041982dSJonathan Peyton thread, num * sizeof(kmp_task_red_data_t)); 167872ba2109SAndrey Churbanov for (int i = 0; i < num; ++i) { 167972ba2109SAndrey Churbanov void (*f_init)(void *) = (void (*)(void *))(input[i].reduce_init); 168072ba2109SAndrey Churbanov size_t size = input[i].reduce_size - 1; 168172ba2109SAndrey Churbanov // round the size up to cache line per thread-specific item 168272ba2109SAndrey Churbanov size += CACHE_LINE - size % CACHE_LINE; 168372ba2109SAndrey Churbanov KMP_ASSERT(input[i].reduce_comb != NULL); // combiner is mandatory 168472ba2109SAndrey Churbanov arr[i].reduce_shar = input[i].reduce_shar; 168572ba2109SAndrey Churbanov arr[i].reduce_size = size; 168672ba2109SAndrey Churbanov arr[i].reduce_init = input[i].reduce_init; 168772ba2109SAndrey Churbanov arr[i].reduce_fini = input[i].reduce_fini; 168872ba2109SAndrey Churbanov arr[i].reduce_comb = input[i].reduce_comb; 168972ba2109SAndrey Churbanov arr[i].flags = input[i].flags; 169072ba2109SAndrey Churbanov if (!input[i].flags.lazy_priv) { 169172ba2109SAndrey Churbanov // allocate cache-line aligned block and fill it with zeros 169272ba2109SAndrey Churbanov arr[i].reduce_priv = __kmp_allocate(nth * size); 169372ba2109SAndrey Churbanov arr[i].reduce_pend = (char *)(arr[i].reduce_priv) + nth * size; 169472ba2109SAndrey Churbanov if (f_init != NULL) { 169572ba2109SAndrey Churbanov // initialize thread-specific items 169672ba2109SAndrey Churbanov for (int j = 0; j < nth; ++j) { 169772ba2109SAndrey Churbanov f_init((char *)(arr[i].reduce_priv) + j * size); 169872ba2109SAndrey Churbanov } 169972ba2109SAndrey Churbanov } 170072ba2109SAndrey Churbanov } else { 170172ba2109SAndrey Churbanov // only allocate space for pointers now, 170272ba2109SAndrey Churbanov // objects will be lazily allocated/initialized once requested 170372ba2109SAndrey Churbanov arr[i].reduce_priv = __kmp_allocate(nth * sizeof(void *)); 170472ba2109SAndrey Churbanov } 170572ba2109SAndrey Churbanov } 170672ba2109SAndrey Churbanov tg->reduce_data = (void *)arr; 170772ba2109SAndrey Churbanov tg->reduce_num_data = num; 170872ba2109SAndrey Churbanov return (void *)tg; 170972ba2109SAndrey Churbanov } 171072ba2109SAndrey Churbanov 171172ba2109SAndrey Churbanov /*! 171272ba2109SAndrey Churbanov @ingroup TASKING 171372ba2109SAndrey Churbanov @param gtid Global thread ID 171472ba2109SAndrey Churbanov @param tskgrp The taskgroup ID (optional) 171572ba2109SAndrey Churbanov @param data Shared location of the item 171672ba2109SAndrey Churbanov @return The pointer to per-thread data 171772ba2109SAndrey Churbanov 171872ba2109SAndrey Churbanov Get thread-specific location of data item 171972ba2109SAndrey Churbanov */ 1720*3041982dSJonathan Peyton void *__kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data) { 172172ba2109SAndrey Churbanov kmp_info_t *thread = __kmp_threads[gtid]; 172272ba2109SAndrey Churbanov kmp_int32 nth = thread->th.th_team_nproc; 172372ba2109SAndrey Churbanov if (nth == 1) 172472ba2109SAndrey Churbanov return data; // nothing to do 172572ba2109SAndrey Churbanov 172672ba2109SAndrey Churbanov kmp_taskgroup_t *tg = (kmp_taskgroup_t *)tskgrp; 172772ba2109SAndrey Churbanov if (tg == NULL) 172872ba2109SAndrey Churbanov tg = thread->th.th_current_task->td_taskgroup; 172972ba2109SAndrey Churbanov KMP_ASSERT(tg != NULL); 173072ba2109SAndrey Churbanov kmp_task_red_data_t *arr = (kmp_task_red_data_t *)(tg->reduce_data); 173172ba2109SAndrey Churbanov kmp_int32 num = tg->reduce_num_data; 173272ba2109SAndrey Churbanov kmp_int32 tid = thread->th.th_info.ds.ds_tid; 173372ba2109SAndrey Churbanov 173472ba2109SAndrey Churbanov KMP_ASSERT(data != NULL); 173572ba2109SAndrey Churbanov while (tg != NULL) { 173672ba2109SAndrey Churbanov for (int i = 0; i < num; ++i) { 173772ba2109SAndrey Churbanov if (!arr[i].flags.lazy_priv) { 173872ba2109SAndrey Churbanov if (data == arr[i].reduce_shar || 173972ba2109SAndrey Churbanov (data >= arr[i].reduce_priv && data < arr[i].reduce_pend)) 174072ba2109SAndrey Churbanov return (char *)(arr[i].reduce_priv) + tid * arr[i].reduce_size; 174172ba2109SAndrey Churbanov } else { 174272ba2109SAndrey Churbanov // check shared location first 174372ba2109SAndrey Churbanov void **p_priv = (void **)(arr[i].reduce_priv); 174472ba2109SAndrey Churbanov if (data == arr[i].reduce_shar) 174572ba2109SAndrey Churbanov goto found; 174672ba2109SAndrey Churbanov // check if we get some thread specific location as parameter 174772ba2109SAndrey Churbanov for (int j = 0; j < nth; ++j) 174872ba2109SAndrey Churbanov if (data == p_priv[j]) 174972ba2109SAndrey Churbanov goto found; 175072ba2109SAndrey Churbanov continue; // not found, continue search 175172ba2109SAndrey Churbanov found: 175272ba2109SAndrey Churbanov if (p_priv[tid] == NULL) { 175372ba2109SAndrey Churbanov // allocate thread specific object lazily 175472ba2109SAndrey Churbanov void (*f_init)(void *) = (void (*)(void *))(arr[i].reduce_init); 175572ba2109SAndrey Churbanov p_priv[tid] = __kmp_allocate(arr[i].reduce_size); 175672ba2109SAndrey Churbanov if (f_init != NULL) { 175772ba2109SAndrey Churbanov f_init(p_priv[tid]); 175872ba2109SAndrey Churbanov } 175972ba2109SAndrey Churbanov } 176072ba2109SAndrey Churbanov return p_priv[tid]; 176172ba2109SAndrey Churbanov } 176272ba2109SAndrey Churbanov } 176372ba2109SAndrey Churbanov tg = tg->parent; 176472ba2109SAndrey Churbanov arr = (kmp_task_red_data_t *)(tg->reduce_data); 176572ba2109SAndrey Churbanov num = tg->reduce_num_data; 176672ba2109SAndrey Churbanov } 176772ba2109SAndrey Churbanov KMP_ASSERT2(0, "Unknown task reduction item"); 176872ba2109SAndrey Churbanov return NULL; // ERROR, this line never executed 176972ba2109SAndrey Churbanov } 177072ba2109SAndrey Churbanov 177172ba2109SAndrey Churbanov // Finalize task reduction. 177272ba2109SAndrey Churbanov // Called from __kmpc_end_taskgroup() 1773*3041982dSJonathan Peyton static void __kmp_task_reduction_fini(kmp_info_t *th, kmp_taskgroup_t *tg) { 177472ba2109SAndrey Churbanov kmp_int32 nth = th->th.th_team_nproc; 177572ba2109SAndrey Churbanov KMP_DEBUG_ASSERT(nth > 1); // should not be called if nth == 1 177672ba2109SAndrey Churbanov kmp_task_red_data_t *arr = (kmp_task_red_data_t *)tg->reduce_data; 177772ba2109SAndrey Churbanov kmp_int32 num = tg->reduce_num_data; 177872ba2109SAndrey Churbanov for (int i = 0; i < num; ++i) { 177972ba2109SAndrey Churbanov void *sh_data = arr[i].reduce_shar; 178072ba2109SAndrey Churbanov void (*f_fini)(void *) = (void (*)(void *))(arr[i].reduce_fini); 1781*3041982dSJonathan Peyton void (*f_comb)(void *, void *) = 1782*3041982dSJonathan Peyton (void (*)(void *, void *))(arr[i].reduce_comb); 178372ba2109SAndrey Churbanov if (!arr[i].flags.lazy_priv) { 178472ba2109SAndrey Churbanov void *pr_data = arr[i].reduce_priv; 178572ba2109SAndrey Churbanov size_t size = arr[i].reduce_size; 178672ba2109SAndrey Churbanov for (int j = 0; j < nth; ++j) { 178772ba2109SAndrey Churbanov void *priv_data = (char *)pr_data + j * size; 178872ba2109SAndrey Churbanov f_comb(sh_data, priv_data); // combine results 178972ba2109SAndrey Churbanov if (f_fini) 179072ba2109SAndrey Churbanov f_fini(priv_data); // finalize if needed 179172ba2109SAndrey Churbanov } 179272ba2109SAndrey Churbanov } else { 179372ba2109SAndrey Churbanov void **pr_data = (void **)(arr[i].reduce_priv); 179472ba2109SAndrey Churbanov for (int j = 0; j < nth; ++j) { 179572ba2109SAndrey Churbanov if (pr_data[j] != NULL) { 179672ba2109SAndrey Churbanov f_comb(sh_data, pr_data[j]); // combine results 179772ba2109SAndrey Churbanov if (f_fini) 179872ba2109SAndrey Churbanov f_fini(pr_data[j]); // finalize if needed 179972ba2109SAndrey Churbanov __kmp_free(pr_data[j]); 180072ba2109SAndrey Churbanov } 180172ba2109SAndrey Churbanov } 180272ba2109SAndrey Churbanov } 180372ba2109SAndrey Churbanov __kmp_free(arr[i].reduce_priv); 180472ba2109SAndrey Churbanov } 180572ba2109SAndrey Churbanov __kmp_thread_free(th, arr); 180672ba2109SAndrey Churbanov tg->reduce_data = NULL; 180772ba2109SAndrey Churbanov tg->reduce_num_data = 0; 180872ba2109SAndrey Churbanov } 180972ba2109SAndrey Churbanov #endif 18107cc577a4SJonathan Peyton 18117cc577a4SJonathan Peyton #if OMP_40_ENABLED 18127cc577a4SJonathan Peyton // __kmpc_taskgroup: Start a new taskgroup 1813*3041982dSJonathan Peyton void __kmpc_taskgroup(ident_t *loc, int gtid) { 18147cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 18157cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = thread->th.th_current_task; 18167cc577a4SJonathan Peyton kmp_taskgroup_t *tg_new = 18177cc577a4SJonathan Peyton (kmp_taskgroup_t *)__kmp_thread_malloc(thread, sizeof(kmp_taskgroup_t)); 18187cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_taskgroup: T#%d loc=%p group=%p\n", gtid, loc, tg_new)); 18197cc577a4SJonathan Peyton tg_new->count = 0; 18207cc577a4SJonathan Peyton tg_new->cancel_request = cancel_noreq; 18217cc577a4SJonathan Peyton tg_new->parent = taskdata->td_taskgroup; 182272ba2109SAndrey Churbanov // TODO: change to OMP_50_ENABLED, need to change build tools for this to work 182372ba2109SAndrey Churbanov #if OMP_45_ENABLED 182472ba2109SAndrey Churbanov tg_new->reduce_data = NULL; 182572ba2109SAndrey Churbanov tg_new->reduce_num_data = 0; 182672ba2109SAndrey Churbanov #endif 18277cc577a4SJonathan Peyton taskdata->td_taskgroup = tg_new; 18287cc577a4SJonathan Peyton } 18297cc577a4SJonathan Peyton 18307cc577a4SJonathan Peyton // __kmpc_end_taskgroup: Wait until all tasks generated by the current task 18317cc577a4SJonathan Peyton // and its descendants are complete 1832*3041982dSJonathan Peyton void __kmpc_end_taskgroup(ident_t *loc, int gtid) { 18337cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 18347cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = thread->th.th_current_task; 18357cc577a4SJonathan Peyton kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup; 18367cc577a4SJonathan Peyton int thread_finished = FALSE; 18377cc577a4SJonathan Peyton 18387cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_end_taskgroup(enter): T#%d loc=%p\n", gtid, loc)); 18397cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskgroup != NULL); 18407cc577a4SJonathan Peyton KMP_SET_THREAD_STATE_BLOCK(TASKGROUP); 18417cc577a4SJonathan Peyton 18427cc577a4SJonathan Peyton if (__kmp_tasking_mode != tskm_immediate_exec) { 18437cc577a4SJonathan Peyton #if USE_ITT_BUILD 1844*3041982dSJonathan Peyton // For ITT the taskgroup wait is similar to taskwait until we need to 1845*3041982dSJonathan Peyton // distinguish them 18467cc577a4SJonathan Peyton void *itt_sync_obj = __kmp_itt_taskwait_object(gtid); 18477cc577a4SJonathan Peyton if (itt_sync_obj != NULL) 18487cc577a4SJonathan Peyton __kmp_itt_taskwait_starting(gtid, itt_sync_obj); 18497cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 18507cc577a4SJonathan Peyton 18517cc577a4SJonathan Peyton #if OMP_45_ENABLED 1852*3041982dSJonathan Peyton if (!taskdata->td_flags.team_serial || 1853*3041982dSJonathan Peyton (thread->th.th_task_team != NULL && 1854*3041982dSJonathan Peyton thread->th.th_task_team->tt.tt_found_proxy_tasks)) 18557cc577a4SJonathan Peyton #else 18567cc577a4SJonathan Peyton if (!taskdata->td_flags.team_serial) 18577cc577a4SJonathan Peyton #endif 18587cc577a4SJonathan Peyton { 18597cc577a4SJonathan Peyton kmp_flag_32 flag(&(taskgroup->count), 0U); 18607cc577a4SJonathan Peyton while (TCR_4(taskgroup->count) != 0) { 1861*3041982dSJonathan Peyton flag.execute_tasks(thread, gtid, FALSE, 1862*3041982dSJonathan Peyton &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), 1863*3041982dSJonathan Peyton __kmp_task_stealing_constraint); 18647cc577a4SJonathan Peyton } 18657cc577a4SJonathan Peyton } 18667cc577a4SJonathan Peyton 18677cc577a4SJonathan Peyton #if USE_ITT_BUILD 18687cc577a4SJonathan Peyton if (itt_sync_obj != NULL) 18697cc577a4SJonathan Peyton __kmp_itt_taskwait_finished(gtid, itt_sync_obj); 18707cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 18717cc577a4SJonathan Peyton } 18727cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskgroup->count == 0); 18737cc577a4SJonathan Peyton 187472ba2109SAndrey Churbanov // TODO: change to OMP_50_ENABLED, need to change build tools for this to work 187572ba2109SAndrey Churbanov #if OMP_45_ENABLED 187672ba2109SAndrey Churbanov if (taskgroup->reduce_data != NULL) // need to reduce? 187772ba2109SAndrey Churbanov __kmp_task_reduction_fini(thread, taskgroup); 187872ba2109SAndrey Churbanov #endif 18797cc577a4SJonathan Peyton // Restore parent taskgroup for the current task 18807cc577a4SJonathan Peyton taskdata->td_taskgroup = taskgroup->parent; 18817cc577a4SJonathan Peyton __kmp_thread_free(thread, taskgroup); 18827cc577a4SJonathan Peyton 1883*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_end_taskgroup(exit): T#%d task %p finished waiting\n", 1884*3041982dSJonathan Peyton gtid, taskdata)); 18857cc577a4SJonathan Peyton ANNOTATE_HAPPENS_AFTER(taskdata); 18867cc577a4SJonathan Peyton } 18877cc577a4SJonathan Peyton #endif 18887cc577a4SJonathan Peyton 18897cc577a4SJonathan Peyton // __kmp_remove_my_task: remove a task from my own deque 1890*3041982dSJonathan Peyton static kmp_task_t *__kmp_remove_my_task(kmp_info_t *thread, kmp_int32 gtid, 1891*3041982dSJonathan Peyton kmp_task_team_t *task_team, 1892*3041982dSJonathan Peyton kmp_int32 is_constrained) { 18937cc577a4SJonathan Peyton kmp_task_t *task; 18947cc577a4SJonathan Peyton kmp_taskdata_t *taskdata; 18957cc577a4SJonathan Peyton kmp_thread_data_t *thread_data; 18967cc577a4SJonathan Peyton kmp_uint32 tail; 18977cc577a4SJonathan Peyton 18987cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 1899*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(task_team->tt.tt_threads_data != 1900*3041982dSJonathan Peyton NULL); // Caller should check this condition 19017cc577a4SJonathan Peyton 19027cc577a4SJonathan Peyton thread_data = &task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)]; 19037cc577a4SJonathan Peyton 19047cc577a4SJonathan Peyton KA_TRACE(10, ("__kmp_remove_my_task(enter): T#%d ntasks=%d head=%u tail=%u\n", 1905*3041982dSJonathan Peyton gtid, thread_data->td.td_deque_ntasks, 1906*3041982dSJonathan Peyton thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 19077cc577a4SJonathan Peyton 19087cc577a4SJonathan Peyton if (TCR_4(thread_data->td.td_deque_ntasks) == 0) { 1909*3041982dSJonathan Peyton KA_TRACE(10, 1910*3041982dSJonathan Peyton ("__kmp_remove_my_task(exit #1): T#%d No tasks to remove: " 1911*3041982dSJonathan Peyton "ntasks=%d head=%u tail=%u\n", 1912*3041982dSJonathan Peyton gtid, thread_data->td.td_deque_ntasks, 1913*3041982dSJonathan Peyton thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 19147cc577a4SJonathan Peyton return NULL; 19157cc577a4SJonathan Peyton } 19167cc577a4SJonathan Peyton 19177cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 19187cc577a4SJonathan Peyton 19197cc577a4SJonathan Peyton if (TCR_4(thread_data->td.td_deque_ntasks) == 0) { 19207cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 1921*3041982dSJonathan Peyton KA_TRACE(10, 1922*3041982dSJonathan Peyton ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: " 1923*3041982dSJonathan Peyton "ntasks=%d head=%u tail=%u\n", 1924*3041982dSJonathan Peyton gtid, thread_data->td.td_deque_ntasks, 1925*3041982dSJonathan Peyton thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 19267cc577a4SJonathan Peyton return NULL; 19277cc577a4SJonathan Peyton } 19287cc577a4SJonathan Peyton 1929*3041982dSJonathan Peyton tail = (thread_data->td.td_deque_tail - 1) & 1930*3041982dSJonathan Peyton TASK_DEQUE_MASK(thread_data->td); // Wrap index. 19317cc577a4SJonathan Peyton taskdata = thread_data->td.td_deque[tail]; 19327cc577a4SJonathan Peyton 19337cc577a4SJonathan Peyton if (is_constrained && (taskdata->td_flags.tiedness == TASK_TIED)) { 19347cc577a4SJonathan Peyton // we need to check if the candidate obeys task scheduling constraint: 19357cc577a4SJonathan Peyton // only child of current task can be scheduled 19367cc577a4SJonathan Peyton kmp_taskdata_t *current = thread->th.th_current_task; 19377cc577a4SJonathan Peyton kmp_int32 level = current->td_level; 19387cc577a4SJonathan Peyton kmp_taskdata_t *parent = taskdata->td_parent; 19397cc577a4SJonathan Peyton while (parent != current && parent->td_level > level) { 1940*3041982dSJonathan Peyton parent = parent->td_parent; // check generation up to the level of the 1941*3041982dSJonathan Peyton // current task 19427cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(parent != NULL); 19437cc577a4SJonathan Peyton } 19447cc577a4SJonathan Peyton if (parent != current) { 1945*3041982dSJonathan Peyton // If the tail task is not a child, then no other child can appear in the 1946*3041982dSJonathan Peyton // deque. 19477cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 1948*3041982dSJonathan Peyton KA_TRACE(10, 1949*3041982dSJonathan Peyton ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: " 1950*3041982dSJonathan Peyton "ntasks=%d head=%u tail=%u\n", 1951*3041982dSJonathan Peyton gtid, thread_data->td.td_deque_ntasks, 1952*3041982dSJonathan Peyton thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 19537cc577a4SJonathan Peyton return NULL; 19547cc577a4SJonathan Peyton } 19557cc577a4SJonathan Peyton } 19567cc577a4SJonathan Peyton 19577cc577a4SJonathan Peyton thread_data->td.td_deque_tail = tail; 19587cc577a4SJonathan Peyton TCW_4(thread_data->td.td_deque_ntasks, thread_data->td.td_deque_ntasks - 1); 19597cc577a4SJonathan Peyton 19607cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 19617cc577a4SJonathan Peyton 1962*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_remove_my_task(exit #2): T#%d task %p removed: " 1963*3041982dSJonathan Peyton "ntasks=%d head=%u tail=%u\n", 1964*3041982dSJonathan Peyton gtid, taskdata, thread_data->td.td_deque_ntasks, 1965*3041982dSJonathan Peyton thread_data->td.td_deque_head, thread_data->td.td_deque_tail)); 19667cc577a4SJonathan Peyton 19677cc577a4SJonathan Peyton task = KMP_TASKDATA_TO_TASK(taskdata); 19687cc577a4SJonathan Peyton return task; 19697cc577a4SJonathan Peyton } 19707cc577a4SJonathan Peyton 19717cc577a4SJonathan Peyton // __kmp_steal_task: remove a task from another thread's deque 19727cc577a4SJonathan Peyton // Assume that calling thread has already checked existence of 19737cc577a4SJonathan Peyton // task_team thread_data before calling this routine. 19747cc577a4SJonathan Peyton static kmp_task_t * 19757cc577a4SJonathan Peyton __kmp_steal_task(kmp_info_t *victim, kmp_int32 gtid, kmp_task_team_t *task_team, 19767cc577a4SJonathan Peyton volatile kmp_uint32 *unfinished_threads, int *thread_finished, 19777cc577a4SJonathan Peyton kmp_int32 is_constrained) 19787cc577a4SJonathan Peyton { 19797cc577a4SJonathan Peyton kmp_task_t *task; 19807cc577a4SJonathan Peyton kmp_taskdata_t *taskdata; 19817cc577a4SJonathan Peyton kmp_thread_data_t *victim_td, *threads_data; 19827cc577a4SJonathan Peyton kmp_int32 victim_tid; 19837cc577a4SJonathan Peyton 19847cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 19857cc577a4SJonathan Peyton 19867cc577a4SJonathan Peyton threads_data = task_team->tt.tt_threads_data; 19877cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(threads_data != NULL); // Caller should check this condition 19887cc577a4SJonathan Peyton 19897cc577a4SJonathan Peyton victim_tid = victim->th.th_info.ds.ds_tid; 19907cc577a4SJonathan Peyton victim_td = &threads_data[victim_tid]; 19917cc577a4SJonathan Peyton 1992*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_steal_task(enter): T#%d try to steal from T#%d: " 1993*3041982dSJonathan Peyton "task_team=%p ntasks=%d " 19947cc577a4SJonathan Peyton "head=%u tail=%u\n", 1995*3041982dSJonathan Peyton gtid, __kmp_gtid_from_thread(victim), task_team, 1996*3041982dSJonathan Peyton victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head, 1997*3041982dSJonathan Peyton victim_td->td.td_deque_tail)); 19987cc577a4SJonathan Peyton 1999*3041982dSJonathan Peyton if ((TCR_4(victim_td->td.td_deque_ntasks) == 2000*3041982dSJonathan Peyton 0) || // Caller should not check this condition 2001*3041982dSJonathan Peyton (TCR_PTR(victim->th.th_task_team) != 2002*3041982dSJonathan Peyton task_team)) // GEH: why would this happen? 20037cc577a4SJonathan Peyton { 2004*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_steal_task(exit #1): T#%d could not steal from T#%d: " 2005*3041982dSJonathan Peyton "task_team=%p " 20067cc577a4SJonathan Peyton "ntasks=%d head=%u tail=%u\n", 2007*3041982dSJonathan Peyton gtid, __kmp_gtid_from_thread(victim), task_team, 2008*3041982dSJonathan Peyton victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head, 2009*3041982dSJonathan Peyton victim_td->td.td_deque_tail)); 20107cc577a4SJonathan Peyton return NULL; 20117cc577a4SJonathan Peyton } 20127cc577a4SJonathan Peyton 20137cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&victim_td->td.td_deque_lock); 20147cc577a4SJonathan Peyton 20157cc577a4SJonathan Peyton // Check again after we acquire the lock 20167cc577a4SJonathan Peyton if ((TCR_4(victim_td->td.td_deque_ntasks) == 0) || 2017*3041982dSJonathan Peyton (TCR_PTR(victim->th.th_task_team) != 2018*3041982dSJonathan Peyton task_team)) // GEH: why would this happen? 20197cc577a4SJonathan Peyton { 20207cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock); 2021*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: " 2022*3041982dSJonathan Peyton "task_team=%p " 20237cc577a4SJonathan Peyton "ntasks=%d head=%u tail=%u\n", 2024*3041982dSJonathan Peyton gtid, __kmp_gtid_from_thread(victim), task_team, 2025*3041982dSJonathan Peyton victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head, 2026*3041982dSJonathan Peyton victim_td->td.td_deque_tail)); 20277cc577a4SJonathan Peyton return NULL; 20287cc577a4SJonathan Peyton } 20297cc577a4SJonathan Peyton 20307cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(victim_td->td.td_deque != NULL); 20317cc577a4SJonathan Peyton 20327cc577a4SJonathan Peyton taskdata = victim_td->td.td_deque[victim_td->td.td_deque_head]; 20337cc577a4SJonathan Peyton if (is_constrained) { 20347cc577a4SJonathan Peyton // we need to check if the candidate obeys task scheduling constraint: 20357cc577a4SJonathan Peyton // only descendant of current task can be scheduled 20367cc577a4SJonathan Peyton kmp_taskdata_t *current = __kmp_threads[gtid]->th.th_current_task; 20377cc577a4SJonathan Peyton kmp_int32 level = current->td_level; 20387cc577a4SJonathan Peyton kmp_taskdata_t *parent = taskdata->td_parent; 20397cc577a4SJonathan Peyton while (parent != current && parent->td_level > level) { 2040*3041982dSJonathan Peyton parent = parent->td_parent; // check generation up to the level of the 2041*3041982dSJonathan Peyton // current task 20427cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(parent != NULL); 20437cc577a4SJonathan Peyton } 20447cc577a4SJonathan Peyton if (parent != current) { 20457cc577a4SJonathan Peyton // If the head task is not a descendant of the current task then do not 20467cc577a4SJonathan Peyton // steal it. No other task in victim's deque can be a descendant of the 20477cc577a4SJonathan Peyton // current task. 20487cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock); 2049*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from " 2050*3041982dSJonathan Peyton "T#%d: task_team=%p " 20517cc577a4SJonathan Peyton "ntasks=%d head=%u tail=%u\n", 2052*3041982dSJonathan Peyton gtid, 2053*3041982dSJonathan Peyton __kmp_gtid_from_thread(threads_data[victim_tid].td.td_thr), 20547cc577a4SJonathan Peyton task_team, victim_td->td.td_deque_ntasks, 20557cc577a4SJonathan Peyton victim_td->td.td_deque_head, victim_td->td.td_deque_tail)); 20567cc577a4SJonathan Peyton return NULL; 20577cc577a4SJonathan Peyton } 20587cc577a4SJonathan Peyton } 20597cc577a4SJonathan Peyton // Bump head pointer and Wrap. 2060*3041982dSJonathan Peyton victim_td->td.td_deque_head = 2061*3041982dSJonathan Peyton (victim_td->td.td_deque_head + 1) & TASK_DEQUE_MASK(victim_td->td); 20627cc577a4SJonathan Peyton if (*thread_finished) { 2063*3041982dSJonathan Peyton // We need to un-mark this victim as a finished victim. This must be done 2064*3041982dSJonathan Peyton // before releasing the lock, or else other threads (starting with the 2065*3041982dSJonathan Peyton // master victim) might be prematurely released from the barrier!!! 20667cc577a4SJonathan Peyton kmp_uint32 count; 20677cc577a4SJonathan Peyton 20687cc577a4SJonathan Peyton count = KMP_TEST_THEN_INC32((kmp_int32 *)unfinished_threads); 20697cc577a4SJonathan Peyton 2070*3041982dSJonathan Peyton KA_TRACE( 2071*3041982dSJonathan Peyton 20, 2072*3041982dSJonathan Peyton ("__kmp_steal_task: T#%d inc unfinished_threads to %d: task_team=%p\n", 20737cc577a4SJonathan Peyton gtid, count + 1, task_team)); 20747cc577a4SJonathan Peyton 20757cc577a4SJonathan Peyton *thread_finished = FALSE; 20767cc577a4SJonathan Peyton } 2077*3041982dSJonathan Peyton TCW_4(victim_td->td.td_deque_ntasks, 2078*3041982dSJonathan Peyton TCR_4(victim_td->td.td_deque_ntasks) - 1); 2079*3041982dSJonathan Peyton 20807cc577a4SJonathan Peyton 20817cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock); 20827cc577a4SJonathan Peyton 20837cc577a4SJonathan Peyton KMP_COUNT_BLOCK(TASK_stolen); 2084*3041982dSJonathan Peyton KA_TRACE( 2085*3041982dSJonathan Peyton 10, 2086*3041982dSJonathan Peyton ("__kmp_steal_task(exit #3): T#%d stole task %p from T#%d: task_team=%p " 20877cc577a4SJonathan Peyton "ntasks=%d head=%u tail=%u\n", 20887cc577a4SJonathan Peyton gtid, taskdata, __kmp_gtid_from_thread(victim), task_team, 20897cc577a4SJonathan Peyton victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head, 20907cc577a4SJonathan Peyton victim_td->td.td_deque_tail)); 20917cc577a4SJonathan Peyton 20927cc577a4SJonathan Peyton task = KMP_TASKDATA_TO_TASK(taskdata); 20937cc577a4SJonathan Peyton return task; 20947cc577a4SJonathan Peyton } 20957cc577a4SJonathan Peyton 20967cc577a4SJonathan Peyton 2097*3041982dSJonathan Peyton // __kmp_execute_tasks_template: Choose and execute tasks until either the 2098*3041982dSJonathan Peyton // condition is statisfied (return true) or there are none left (return false). 2099*3041982dSJonathan Peyton // 21007cc577a4SJonathan Peyton // final_spin is TRUE if this is the spin at the release barrier. 21017cc577a4SJonathan Peyton // thread_finished indicates whether the thread is finished executing all 21027cc577a4SJonathan Peyton // the tasks it has on its deque, and is at the release barrier. 21037cc577a4SJonathan Peyton // spinner is the location on which to spin. 21047cc577a4SJonathan Peyton // spinner == NULL means only execute a single task and return. 21057cc577a4SJonathan Peyton // checker is the value to check to terminate the spin. 21067cc577a4SJonathan Peyton template <class C> 2107*3041982dSJonathan Peyton static inline int __kmp_execute_tasks_template( 2108*3041982dSJonathan Peyton kmp_info_t *thread, kmp_int32 gtid, C *flag, int final_spin, 2109*3041982dSJonathan Peyton int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 2110*3041982dSJonathan Peyton kmp_int32 is_constrained) { 21117cc577a4SJonathan Peyton kmp_task_team_t *task_team = thread->th.th_task_team; 21127cc577a4SJonathan Peyton kmp_thread_data_t *threads_data; 21137cc577a4SJonathan Peyton kmp_task_t *task; 21147cc577a4SJonathan Peyton kmp_info_t *other_thread; 21157cc577a4SJonathan Peyton kmp_taskdata_t *current_task = thread->th.th_current_task; 21167cc577a4SJonathan Peyton volatile kmp_uint32 *unfinished_threads; 2117*3041982dSJonathan Peyton kmp_int32 nthreads, victim = -2, use_own_tasks = 1, new_victim = 0, 2118*3041982dSJonathan Peyton tid = thread->th.th_info.ds.ds_tid; 21197cc577a4SJonathan Peyton 21207cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 21217cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thread == __kmp_threads[gtid]); 21227cc577a4SJonathan Peyton 2123*3041982dSJonathan Peyton if (task_team == NULL) 2124*3041982dSJonathan Peyton return FALSE; 21257cc577a4SJonathan Peyton 2126*3041982dSJonathan Peyton KA_TRACE(15, ("__kmp_execute_tasks_template(enter): T#%d final_spin=%d " 2127*3041982dSJonathan Peyton "*thread_finished=%d\n", 21287cc577a4SJonathan Peyton gtid, final_spin, *thread_finished)); 21297cc577a4SJonathan Peyton 2130581490e7SAndrey Churbanov thread->th.th_reap_state = KMP_NOT_SAFE_TO_REAP; 21317cc577a4SJonathan Peyton threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data); 21327cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(threads_data != NULL); 21337cc577a4SJonathan Peyton 21347cc577a4SJonathan Peyton nthreads = task_team->tt.tt_nproc; 21357cc577a4SJonathan Peyton unfinished_threads = &(task_team->tt.tt_unfinished_threads); 21367cc577a4SJonathan Peyton #if OMP_45_ENABLED 21377cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(nthreads > 1 || task_team->tt.tt_found_proxy_tasks); 21387cc577a4SJonathan Peyton #else 21397cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(nthreads > 1); 21407cc577a4SJonathan Peyton #endif 21417cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((int)(TCR_4(*unfinished_threads)) >= 0); 21427cc577a4SJonathan Peyton 2143*3041982dSJonathan Peyton while (1) { // Outer loop keeps trying to find tasks in case of single thread 2144*3041982dSJonathan Peyton // getting tasks from target constructs 21457cc577a4SJonathan Peyton while (1) { // Inner loop to find a task and execute it 21467cc577a4SJonathan Peyton task = NULL; 21477cc577a4SJonathan Peyton if (use_own_tasks) { // check on own queue first 21487cc577a4SJonathan Peyton task = __kmp_remove_my_task(thread, gtid, task_team, is_constrained); 21497cc577a4SJonathan Peyton } 21507cc577a4SJonathan Peyton if ((task == NULL) && (nthreads > 1)) { // Steal a task 21517cc577a4SJonathan Peyton int asleep = 1; 21527cc577a4SJonathan Peyton use_own_tasks = 0; 21537cc577a4SJonathan Peyton // Try to steal from the last place I stole from successfully. 21547cc577a4SJonathan Peyton if (victim == -2) { // haven't stolen anything yet 21557cc577a4SJonathan Peyton victim = threads_data[tid].td.td_deque_last_stolen; 2156*3041982dSJonathan Peyton if (victim != 2157*3041982dSJonathan Peyton -1) // if we have a last stolen from victim, get the thread 21587cc577a4SJonathan Peyton other_thread = threads_data[victim].td.td_thr; 21597cc577a4SJonathan Peyton } 21607cc577a4SJonathan Peyton if (victim != -1) { // found last victim 21617cc577a4SJonathan Peyton asleep = 0; 2162*3041982dSJonathan Peyton } else if (!new_victim) { // no recent steals and we haven't already 2163*3041982dSJonathan Peyton // used a new victim; select a random thread 21647cc577a4SJonathan Peyton do { // Find a different thread to steal work from. 2165*3041982dSJonathan Peyton // Pick a random thread. Initial plan was to cycle through all the 2166*3041982dSJonathan Peyton // threads, and only return if we tried to steal from every thread, 2167*3041982dSJonathan Peyton // and failed. Arch says that's not such a great idea. 21687cc577a4SJonathan Peyton victim = __kmp_get_random(thread) % (nthreads - 1); 21697cc577a4SJonathan Peyton if (victim >= tid) { 21707cc577a4SJonathan Peyton ++victim; // Adjusts random distribution to exclude self 21717cc577a4SJonathan Peyton } 21727cc577a4SJonathan Peyton // Found a potential victim 21737cc577a4SJonathan Peyton other_thread = threads_data[victim].td.td_thr; 2174*3041982dSJonathan Peyton // There is a slight chance that __kmp_enable_tasking() did not wake 2175*3041982dSJonathan Peyton // up all threads waiting at the barrier. If victim is sleeping, 2176*3041982dSJonathan Peyton // then wake it up. Since we were going to pay the cache miss 2177*3041982dSJonathan Peyton // penalty for referencing another thread's kmp_info_t struct 2178*3041982dSJonathan Peyton // anyway, 2179*3041982dSJonathan Peyton // the check shouldn't cost too much performance at this point. In 2180*3041982dSJonathan Peyton // extra barrier mode, tasks do not sleep at the separate tasking 2181*3041982dSJonathan Peyton // barrier, so this isn't a problem. 21827cc577a4SJonathan Peyton asleep = 0; 21837cc577a4SJonathan Peyton if ((__kmp_tasking_mode == tskm_task_teams) && 21847cc577a4SJonathan Peyton (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) && 21857cc577a4SJonathan Peyton (TCR_PTR(other_thread->th.th_sleep_loc) != NULL)) { 21867cc577a4SJonathan Peyton asleep = 1; 2187*3041982dSJonathan Peyton __kmp_null_resume_wrapper(__kmp_gtid_from_thread(other_thread), 2188*3041982dSJonathan Peyton other_thread->th.th_sleep_loc); 2189*3041982dSJonathan Peyton // A sleeping thread should not have any tasks on it's queue. 2190*3041982dSJonathan Peyton // There is a slight possibility that it resumes, steals a task 2191*3041982dSJonathan Peyton // from another thread, which spawns more tasks, all in the time 2192*3041982dSJonathan Peyton // that it takes this thread to check => don't write an assertion 2193*3041982dSJonathan Peyton // that the victim's queue is empty. Try stealing from a 2194*3041982dSJonathan Peyton // different thread. 21957cc577a4SJonathan Peyton } 21967cc577a4SJonathan Peyton } while (asleep); 21977cc577a4SJonathan Peyton } 21987cc577a4SJonathan Peyton 21997cc577a4SJonathan Peyton if (!asleep) { 22007cc577a4SJonathan Peyton // We have a victim to try to steal from 2201*3041982dSJonathan Peyton task = __kmp_steal_task(other_thread, gtid, task_team, 2202*3041982dSJonathan Peyton unfinished_threads, thread_finished, 2203*3041982dSJonathan Peyton is_constrained); 22047cc577a4SJonathan Peyton } 22057cc577a4SJonathan Peyton if (task != NULL) { // set last stolen to victim 22067cc577a4SJonathan Peyton if (threads_data[tid].td.td_deque_last_stolen != victim) { 22077cc577a4SJonathan Peyton threads_data[tid].td.td_deque_last_stolen = victim; 2208*3041982dSJonathan Peyton // The pre-refactored code did not try more than 1 successful new 2209*3041982dSJonathan Peyton // vicitm, unless the last one generated more local tasks; 2210*3041982dSJonathan Peyton // new_victim keeps track of this 22117cc577a4SJonathan Peyton new_victim = 1; 22127cc577a4SJonathan Peyton } 2213*3041982dSJonathan Peyton } else { // No tasks found; unset last_stolen 22147cc577a4SJonathan Peyton KMP_CHECK_UPDATE(threads_data[tid].td.td_deque_last_stolen, -1); 22157cc577a4SJonathan Peyton victim = -2; // no successful victim found 22167cc577a4SJonathan Peyton } 22177cc577a4SJonathan Peyton } 22187cc577a4SJonathan Peyton 22197cc577a4SJonathan Peyton if (task == NULL) // break out of tasking loop 22207cc577a4SJonathan Peyton break; 22217cc577a4SJonathan Peyton 22227cc577a4SJonathan Peyton // Found a task; execute it 22237cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY 22247cc577a4SJonathan Peyton if (__itt_sync_create_ptr || KMP_ITT_DEBUG) { 2225*3041982dSJonathan Peyton if (itt_sync_obj == NULL) { // we are at fork barrier where we could not 2226*3041982dSJonathan Peyton // get the object reliably 22277cc577a4SJonathan Peyton itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier); 22287cc577a4SJonathan Peyton } 22297cc577a4SJonathan Peyton __kmp_itt_task_starting(itt_sync_obj); 22307cc577a4SJonathan Peyton } 22317cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */ 22327cc577a4SJonathan Peyton __kmp_invoke_task(gtid, task, current_task); 22337cc577a4SJonathan Peyton #if USE_ITT_BUILD 2234*3041982dSJonathan Peyton if (itt_sync_obj != NULL) 2235*3041982dSJonathan Peyton __kmp_itt_task_finished(itt_sync_obj); 22367cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 2237*3041982dSJonathan Peyton // If this thread is only partway through the barrier and the condition is 2238*3041982dSJonathan Peyton // met, then return now, so that the barrier gather/release pattern can 2239*3041982dSJonathan Peyton // proceed. If this thread is in the last spin loop in the barrier, 2240*3041982dSJonathan Peyton // waiting to be released, we know that the termination condition will not 2241*3041982dSJonathan Peyton // be satisified, so don't waste any cycles checking it. 22427cc577a4SJonathan Peyton if (flag == NULL || (!final_spin && flag->done_check())) { 2243*3041982dSJonathan Peyton KA_TRACE( 2244*3041982dSJonathan Peyton 15, 2245*3041982dSJonathan Peyton ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n", 2246*3041982dSJonathan Peyton gtid)); 22477cc577a4SJonathan Peyton return TRUE; 22487cc577a4SJonathan Peyton } 22497cc577a4SJonathan Peyton if (thread->th.th_task_team == NULL) { 22507cc577a4SJonathan Peyton break; 22517cc577a4SJonathan Peyton } 2252*3041982dSJonathan Peyton // Yield before executing next task 2253*3041982dSJonathan Peyton KMP_YIELD(__kmp_library == library_throughput); 2254*3041982dSJonathan Peyton // If execution of a stolen task results in more tasks being placed on our 2255*3041982dSJonathan Peyton // run queue, reset use_own_tasks 22567cc577a4SJonathan Peyton if (!use_own_tasks && TCR_4(threads_data[tid].td.td_deque_ntasks) != 0) { 2257*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d stolen task spawned " 2258*3041982dSJonathan Peyton "other tasks, restart\n", 2259*3041982dSJonathan Peyton gtid)); 22607cc577a4SJonathan Peyton use_own_tasks = 1; 22617cc577a4SJonathan Peyton new_victim = 0; 22627cc577a4SJonathan Peyton } 22637cc577a4SJonathan Peyton } 22647cc577a4SJonathan Peyton 2265*3041982dSJonathan Peyton // The task source has been exhausted. If in final spin loop of barrier, check 2266*3041982dSJonathan Peyton // if termination condition is satisfied. 22677cc577a4SJonathan Peyton #if OMP_45_ENABLED 2268*3041982dSJonathan Peyton // The work queue may be empty but there might be proxy tasks still 2269*3041982dSJonathan Peyton // executing 22707cc577a4SJonathan Peyton if (final_spin && TCR_4(current_task->td_incomplete_child_tasks) == 0) 22717cc577a4SJonathan Peyton #else 22727cc577a4SJonathan Peyton if (final_spin) 22737cc577a4SJonathan Peyton #endif 22747cc577a4SJonathan Peyton { 2275*3041982dSJonathan Peyton // First, decrement the #unfinished threads, if that has not already been 2276*3041982dSJonathan Peyton // done. This decrement might be to the spin location, and result in the 2277*3041982dSJonathan Peyton // termination condition being satisfied. 22787cc577a4SJonathan Peyton if (!*thread_finished) { 22797cc577a4SJonathan Peyton kmp_uint32 count; 22807cc577a4SJonathan Peyton 22817cc577a4SJonathan Peyton count = KMP_TEST_THEN_DEC32((kmp_int32 *)unfinished_threads) - 1; 2282*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d dec " 2283*3041982dSJonathan Peyton "unfinished_threads to %d task_team=%p\n", 22847cc577a4SJonathan Peyton gtid, count, task_team)); 22857cc577a4SJonathan Peyton *thread_finished = TRUE; 22867cc577a4SJonathan Peyton } 22877cc577a4SJonathan Peyton 22887cc577a4SJonathan Peyton // It is now unsafe to reference thread->th.th_team !!! 2289*3041982dSJonathan Peyton // Decrementing task_team->tt.tt_unfinished_threads can allow the master 2290*3041982dSJonathan Peyton // thread to pass through the barrier, where it might reset each thread's 2291*3041982dSJonathan Peyton // th.th_team field for the next parallel region. If we can steal more 2292*3041982dSJonathan Peyton // work, we know that this has not happened yet. 22937cc577a4SJonathan Peyton if (flag != NULL && flag->done_check()) { 2294*3041982dSJonathan Peyton KA_TRACE( 2295*3041982dSJonathan Peyton 15, 2296*3041982dSJonathan Peyton ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n", 2297*3041982dSJonathan Peyton gtid)); 22987cc577a4SJonathan Peyton return TRUE; 22997cc577a4SJonathan Peyton } 23007cc577a4SJonathan Peyton } 23017cc577a4SJonathan Peyton 2302*3041982dSJonathan Peyton // If this thread's task team is NULL, master has recognized that there are 2303*3041982dSJonathan Peyton // no more tasks; bail out 23047cc577a4SJonathan Peyton if (thread->th.th_task_team == NULL) { 2305*3041982dSJonathan Peyton KA_TRACE(15, 2306*3041982dSJonathan Peyton ("__kmp_execute_tasks_template: T#%d no more tasks\n", gtid)); 23077cc577a4SJonathan Peyton return FALSE; 23087cc577a4SJonathan Peyton } 23097cc577a4SJonathan Peyton 23107cc577a4SJonathan Peyton #if OMP_45_ENABLED 2311*3041982dSJonathan Peyton // We could be getting tasks from target constructs; if this is the only 2312*3041982dSJonathan Peyton // thread, keep trying to execute tasks from own queue 23137cc577a4SJonathan Peyton if (nthreads == 1) 23147cc577a4SJonathan Peyton use_own_tasks = 1; 23157cc577a4SJonathan Peyton else 23167cc577a4SJonathan Peyton #endif 23177cc577a4SJonathan Peyton { 2318*3041982dSJonathan Peyton KA_TRACE(15, 2319*3041982dSJonathan Peyton ("__kmp_execute_tasks_template: T#%d can't find work\n", gtid)); 23207cc577a4SJonathan Peyton return FALSE; 23217cc577a4SJonathan Peyton } 23227cc577a4SJonathan Peyton } 23237cc577a4SJonathan Peyton } 23247cc577a4SJonathan Peyton 2325*3041982dSJonathan Peyton int __kmp_execute_tasks_32( 2326*3041982dSJonathan Peyton kmp_info_t *thread, kmp_int32 gtid, kmp_flag_32 *flag, int final_spin, 2327*3041982dSJonathan Peyton int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 2328*3041982dSJonathan Peyton kmp_int32 is_constrained) { 2329*3041982dSJonathan Peyton return __kmp_execute_tasks_template( 2330*3041982dSJonathan Peyton thread, gtid, flag, final_spin, 2331*3041982dSJonathan Peyton thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained); 23327cc577a4SJonathan Peyton } 23337cc577a4SJonathan Peyton 2334*3041982dSJonathan Peyton int __kmp_execute_tasks_64( 2335*3041982dSJonathan Peyton kmp_info_t *thread, kmp_int32 gtid, kmp_flag_64 *flag, int final_spin, 2336*3041982dSJonathan Peyton int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 2337*3041982dSJonathan Peyton kmp_int32 is_constrained) { 2338*3041982dSJonathan Peyton return __kmp_execute_tasks_template( 2339*3041982dSJonathan Peyton thread, gtid, flag, final_spin, 2340*3041982dSJonathan Peyton thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained); 23417cc577a4SJonathan Peyton } 23427cc577a4SJonathan Peyton 2343*3041982dSJonathan Peyton int __kmp_execute_tasks_oncore( 2344*3041982dSJonathan Peyton kmp_info_t *thread, kmp_int32 gtid, kmp_flag_oncore *flag, int final_spin, 2345*3041982dSJonathan Peyton int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj), 2346*3041982dSJonathan Peyton kmp_int32 is_constrained) { 2347*3041982dSJonathan Peyton return __kmp_execute_tasks_template( 2348*3041982dSJonathan Peyton thread, gtid, flag, final_spin, 2349*3041982dSJonathan Peyton thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained); 23507cc577a4SJonathan Peyton } 23517cc577a4SJonathan Peyton 23527cc577a4SJonathan Peyton // __kmp_enable_tasking: Allocate task team and resume threads sleeping at the 23537cc577a4SJonathan Peyton // next barrier so they can assist in executing enqueued tasks. 23547cc577a4SJonathan Peyton // First thread in allocates the task team atomically. 2355*3041982dSJonathan Peyton static void __kmp_enable_tasking(kmp_task_team_t *task_team, 2356*3041982dSJonathan Peyton kmp_info_t *this_thr) { 23577cc577a4SJonathan Peyton kmp_thread_data_t *threads_data; 23587cc577a4SJonathan Peyton int nthreads, i, is_init_thread; 23597cc577a4SJonathan Peyton 23607cc577a4SJonathan Peyton KA_TRACE(10, ("__kmp_enable_tasking(enter): T#%d\n", 23617cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr))); 23627cc577a4SJonathan Peyton 23637cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_team != NULL); 23647cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(this_thr->th.th_team != NULL); 23657cc577a4SJonathan Peyton 23667cc577a4SJonathan Peyton nthreads = task_team->tt.tt_nproc; 23677cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(nthreads > 0); 23687cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(nthreads == this_thr->th.th_team->t.t_nproc); 23697cc577a4SJonathan Peyton 23707cc577a4SJonathan Peyton // Allocate or increase the size of threads_data if necessary 23717cc577a4SJonathan Peyton is_init_thread = __kmp_realloc_task_threads_data(this_thr, task_team); 23727cc577a4SJonathan Peyton 23737cc577a4SJonathan Peyton if (!is_init_thread) { 23747cc577a4SJonathan Peyton // Some other thread already set up the array. 2375*3041982dSJonathan Peyton KA_TRACE( 2376*3041982dSJonathan Peyton 20, 2377*3041982dSJonathan Peyton ("__kmp_enable_tasking(exit): T#%d: threads array already set up.\n", 23787cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr))); 23797cc577a4SJonathan Peyton return; 23807cc577a4SJonathan Peyton } 23817cc577a4SJonathan Peyton threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data); 23827cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(threads_data != NULL); 23837cc577a4SJonathan Peyton 23847cc577a4SJonathan Peyton if ((__kmp_tasking_mode == tskm_task_teams) && 2385*3041982dSJonathan Peyton (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME)) { 23867cc577a4SJonathan Peyton // Release any threads sleeping at the barrier, so that they can steal 23877cc577a4SJonathan Peyton // tasks and execute them. In extra barrier mode, tasks do not sleep 23887cc577a4SJonathan Peyton // at the separate tasking barrier, so this isn't a problem. 23897cc577a4SJonathan Peyton for (i = 0; i < nthreads; i++) { 23907cc577a4SJonathan Peyton volatile void *sleep_loc; 23917cc577a4SJonathan Peyton kmp_info_t *thread = threads_data[i].td.td_thr; 23927cc577a4SJonathan Peyton 23937cc577a4SJonathan Peyton if (i == this_thr->th.th_info.ds.ds_tid) { 23947cc577a4SJonathan Peyton continue; 23957cc577a4SJonathan Peyton } 23967cc577a4SJonathan Peyton // Since we haven't locked the thread's suspend mutex lock at this 23977cc577a4SJonathan Peyton // point, there is a small window where a thread might be putting 23987cc577a4SJonathan Peyton // itself to sleep, but hasn't set the th_sleep_loc field yet. 23997cc577a4SJonathan Peyton // To work around this, __kmp_execute_tasks_template() periodically checks 2400*3041982dSJonathan Peyton // see if other threads are sleeping (using the same random mechanism that 2401*3041982dSJonathan Peyton // is used for task stealing) and awakens them if they are. 2402*3041982dSJonathan Peyton if ((sleep_loc = TCR_PTR(thread->th.th_sleep_loc)) != NULL) { 24037cc577a4SJonathan Peyton KF_TRACE(50, ("__kmp_enable_tasking: T#%d waking up thread T#%d\n", 24047cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), 24057cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread))); 24067cc577a4SJonathan Peyton __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc); 2407*3041982dSJonathan Peyton } else { 24087cc577a4SJonathan Peyton KF_TRACE(50, ("__kmp_enable_tasking: T#%d don't wake up thread T#%d\n", 24097cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), 24107cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread))); 24117cc577a4SJonathan Peyton } 24127cc577a4SJonathan Peyton } 24137cc577a4SJonathan Peyton } 24147cc577a4SJonathan Peyton 24157cc577a4SJonathan Peyton KA_TRACE(10, ("__kmp_enable_tasking(exit): T#%d\n", 24167cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr))); 24177cc577a4SJonathan Peyton } 24187cc577a4SJonathan Peyton 24197cc577a4SJonathan Peyton /* // TODO: Check the comment consistency 24207cc577a4SJonathan Peyton * Utility routines for "task teams". A task team (kmp_task_t) is kind of 24217cc577a4SJonathan Peyton * like a shadow of the kmp_team_t data struct, with a different lifetime. 24227cc577a4SJonathan Peyton * After a child * thread checks into a barrier and calls __kmp_release() from 24237cc577a4SJonathan Peyton * the particular variant of __kmp_<barrier_kind>_barrier_gather(), it can no 24247cc577a4SJonathan Peyton * longer assume that the kmp_team_t structure is intact (at any moment, the 24257cc577a4SJonathan Peyton * master thread may exit the barrier code and free the team data structure, 24267cc577a4SJonathan Peyton * and return the threads to the thread pool). 24277cc577a4SJonathan Peyton * 24287cc577a4SJonathan Peyton * This does not work with the the tasking code, as the thread is still 24297cc577a4SJonathan Peyton * expected to participate in the execution of any tasks that may have been 24307cc577a4SJonathan Peyton * spawned my a member of the team, and the thread still needs access to all 24317cc577a4SJonathan Peyton * to each thread in the team, so that it can steal work from it. 24327cc577a4SJonathan Peyton * 24337cc577a4SJonathan Peyton * Enter the existence of the kmp_task_team_t struct. It employs a reference 24347cc577a4SJonathan Peyton * counting mechanims, and is allocated by the master thread before calling 24357cc577a4SJonathan Peyton * __kmp_<barrier_kind>_release, and then is release by the last thread to 24367cc577a4SJonathan Peyton * exit __kmp_<barrier_kind>_release at the next barrier. I.e. the lifetimes 24377cc577a4SJonathan Peyton * of the kmp_task_team_t structs for consecutive barriers can overlap 24387cc577a4SJonathan Peyton * (and will, unless the master thread is the last thread to exit the barrier 24397cc577a4SJonathan Peyton * release phase, which is not typical). 24407cc577a4SJonathan Peyton * 24417cc577a4SJonathan Peyton * The existence of such a struct is useful outside the context of tasking, 24427cc577a4SJonathan Peyton * but for now, I'm trying to keep it specific to the OMP_30_ENABLED macro, 24437cc577a4SJonathan Peyton * so that any performance differences show up when comparing the 2.5 vs. 3.0 24447cc577a4SJonathan Peyton * libraries. 24457cc577a4SJonathan Peyton * 24467cc577a4SJonathan Peyton * We currently use the existence of the threads array as an indicator that 24477cc577a4SJonathan Peyton * tasks were spawned since the last barrier. If the structure is to be 24487cc577a4SJonathan Peyton * useful outside the context of tasking, then this will have to change, but 24497cc577a4SJonathan Peyton * not settting the field minimizes the performance impact of tasking on 24507cc577a4SJonathan Peyton * barriers, when no explicit tasks were spawned (pushed, actually). 24517cc577a4SJonathan Peyton */ 24527cc577a4SJonathan Peyton 2453*3041982dSJonathan Peyton static kmp_task_team_t *__kmp_free_task_teams = 2454*3041982dSJonathan Peyton NULL; // Free list for task_team data structures 24557cc577a4SJonathan Peyton // Lock for task team data structures 2456*3041982dSJonathan Peyton static kmp_bootstrap_lock_t __kmp_task_team_lock = 2457*3041982dSJonathan Peyton KMP_BOOTSTRAP_LOCK_INITIALIZER(__kmp_task_team_lock); 24587cc577a4SJonathan Peyton 24597cc577a4SJonathan Peyton // __kmp_alloc_task_deque: 24607cc577a4SJonathan Peyton // Allocates a task deque for a particular thread, and initialize the necessary 24617cc577a4SJonathan Peyton // data structures relating to the deque. This only happens once per thread 2462*3041982dSJonathan Peyton // per task team since task teams are recycled. No lock is needed during 2463*3041982dSJonathan Peyton // allocation since each thread allocates its own deque. 2464*3041982dSJonathan Peyton static void __kmp_alloc_task_deque(kmp_info_t *thread, 2465*3041982dSJonathan Peyton kmp_thread_data_t *thread_data) { 24667cc577a4SJonathan Peyton __kmp_init_bootstrap_lock(&thread_data->td.td_deque_lock); 24677cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thread_data->td.td_deque == NULL); 24687cc577a4SJonathan Peyton 24697cc577a4SJonathan Peyton // Initialize last stolen task field to "none" 24707cc577a4SJonathan Peyton thread_data->td.td_deque_last_stolen = -1; 24717cc577a4SJonathan Peyton 24727cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) == 0); 24737cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thread_data->td.td_deque_head == 0); 24747cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thread_data->td.td_deque_tail == 0); 24757cc577a4SJonathan Peyton 2476*3041982dSJonathan Peyton KE_TRACE( 2477*3041982dSJonathan Peyton 10, 2478*3041982dSJonathan Peyton ("__kmp_alloc_task_deque: T#%d allocating deque[%d] for thread_data %p\n", 24797cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread), INITIAL_TASK_DEQUE_SIZE, thread_data)); 24807cc577a4SJonathan Peyton // Allocate space for task deque, and zero the deque 24817cc577a4SJonathan Peyton // Cannot use __kmp_thread_calloc() because threads not around for 24827cc577a4SJonathan Peyton // kmp_reap_task_team( ). 2483*3041982dSJonathan Peyton thread_data->td.td_deque = (kmp_taskdata_t **)__kmp_allocate( 2484*3041982dSJonathan Peyton INITIAL_TASK_DEQUE_SIZE * sizeof(kmp_taskdata_t *)); 24857cc577a4SJonathan Peyton thread_data->td.td_deque_size = INITIAL_TASK_DEQUE_SIZE; 24867cc577a4SJonathan Peyton } 24877cc577a4SJonathan Peyton 24887cc577a4SJonathan Peyton // __kmp_realloc_task_deque: 2489*3041982dSJonathan Peyton // Re-allocates a task deque for a particular thread, copies the content from 2490*3041982dSJonathan Peyton // the old deque and adjusts the necessary data structures relating to the 2491*3041982dSJonathan Peyton // deque. This operation must be done with a the deque_lock being held 2492*3041982dSJonathan Peyton static void __kmp_realloc_task_deque(kmp_info_t *thread, 2493*3041982dSJonathan Peyton kmp_thread_data_t *thread_data) { 24947cc577a4SJonathan Peyton kmp_int32 size = TASK_DEQUE_SIZE(thread_data->td); 24957cc577a4SJonathan Peyton kmp_int32 new_size = 2 * size; 24967cc577a4SJonathan Peyton 2497*3041982dSJonathan Peyton KE_TRACE(10, ("__kmp_realloc_task_deque: T#%d reallocating deque[from %d to " 2498*3041982dSJonathan Peyton "%d] for thread_data %p\n", 24997cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread), size, new_size, thread_data)); 25007cc577a4SJonathan Peyton 2501*3041982dSJonathan Peyton kmp_taskdata_t **new_deque = 2502*3041982dSJonathan Peyton (kmp_taskdata_t **)__kmp_allocate(new_size * sizeof(kmp_taskdata_t *)); 25037cc577a4SJonathan Peyton 25047cc577a4SJonathan Peyton int i, j; 2505*3041982dSJonathan Peyton for (i = thread_data->td.td_deque_head, j = 0; j < size; 2506*3041982dSJonathan Peyton i = (i + 1) & TASK_DEQUE_MASK(thread_data->td), j++) 25077cc577a4SJonathan Peyton new_deque[j] = thread_data->td.td_deque[i]; 25087cc577a4SJonathan Peyton 25097cc577a4SJonathan Peyton __kmp_free(thread_data->td.td_deque); 25107cc577a4SJonathan Peyton 25117cc577a4SJonathan Peyton thread_data->td.td_deque_head = 0; 25127cc577a4SJonathan Peyton thread_data->td.td_deque_tail = size; 25137cc577a4SJonathan Peyton thread_data->td.td_deque = new_deque; 25147cc577a4SJonathan Peyton thread_data->td.td_deque_size = new_size; 25157cc577a4SJonathan Peyton } 25167cc577a4SJonathan Peyton 25177cc577a4SJonathan Peyton // __kmp_free_task_deque: 2518*3041982dSJonathan Peyton // Deallocates a task deque for a particular thread. Happens at library 2519*3041982dSJonathan Peyton // deallocation so don't need to reset all thread data fields. 2520*3041982dSJonathan Peyton static void __kmp_free_task_deque(kmp_thread_data_t *thread_data) { 25217cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 25227cc577a4SJonathan Peyton 25237cc577a4SJonathan Peyton if (thread_data->td.td_deque != NULL) { 25247cc577a4SJonathan Peyton TCW_4(thread_data->td.td_deque_ntasks, 0); 25257cc577a4SJonathan Peyton __kmp_free(thread_data->td.td_deque); 25267cc577a4SJonathan Peyton thread_data->td.td_deque = NULL; 25277cc577a4SJonathan Peyton } 25287cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 25297cc577a4SJonathan Peyton 25307cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK 25317cc577a4SJonathan Peyton // GEH: Figure out what to do here for td_susp_tied_tasks 25327cc577a4SJonathan Peyton if (thread_data->td.td_susp_tied_tasks.ts_entries != TASK_STACK_EMPTY) { 25337cc577a4SJonathan Peyton __kmp_free_task_stack(__kmp_thread_from_gtid(gtid), thread_data); 25347cc577a4SJonathan Peyton } 25357cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK 25367cc577a4SJonathan Peyton } 25377cc577a4SJonathan Peyton 25387cc577a4SJonathan Peyton // __kmp_realloc_task_threads_data: 2539*3041982dSJonathan Peyton // Allocates a threads_data array for a task team, either by allocating an 2540*3041982dSJonathan Peyton // initial array or enlarging an existing array. Only the first thread to get 2541*3041982dSJonathan Peyton // the lock allocs or enlarges the array and re-initializes the array eleemnts. 25427cc577a4SJonathan Peyton // That thread returns "TRUE", the rest return "FALSE". 25437cc577a4SJonathan Peyton // Assumes that the new array size is given by task_team -> tt.tt_nproc. 25447cc577a4SJonathan Peyton // The current size is given by task_team -> tt.tt_max_threads. 2545*3041982dSJonathan Peyton static int __kmp_realloc_task_threads_data(kmp_info_t *thread, 2546*3041982dSJonathan Peyton kmp_task_team_t *task_team) { 25477cc577a4SJonathan Peyton kmp_thread_data_t **threads_data_p; 25487cc577a4SJonathan Peyton kmp_int32 nthreads, maxthreads; 25497cc577a4SJonathan Peyton int is_init_thread = FALSE; 25507cc577a4SJonathan Peyton 25517cc577a4SJonathan Peyton if (TCR_4(task_team->tt.tt_found_tasks)) { 25527cc577a4SJonathan Peyton // Already reallocated and initialized. 25537cc577a4SJonathan Peyton return FALSE; 25547cc577a4SJonathan Peyton } 25557cc577a4SJonathan Peyton 25567cc577a4SJonathan Peyton threads_data_p = &task_team->tt.tt_threads_data; 25577cc577a4SJonathan Peyton nthreads = task_team->tt.tt_nproc; 25587cc577a4SJonathan Peyton maxthreads = task_team->tt.tt_max_threads; 25597cc577a4SJonathan Peyton 2560*3041982dSJonathan Peyton // All threads must lock when they encounter the first task of the implicit 2561*3041982dSJonathan Peyton // task region to make sure threads_data fields are (re)initialized before 2562*3041982dSJonathan Peyton // used. 25637cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock); 25647cc577a4SJonathan Peyton 25657cc577a4SJonathan Peyton if (!TCR_4(task_team->tt.tt_found_tasks)) { 25667cc577a4SJonathan Peyton // first thread to enable tasking 25677cc577a4SJonathan Peyton kmp_team_t *team = thread->th.th_team; 25687cc577a4SJonathan Peyton int i; 25697cc577a4SJonathan Peyton 25707cc577a4SJonathan Peyton is_init_thread = TRUE; 25717cc577a4SJonathan Peyton if (maxthreads < nthreads) { 25727cc577a4SJonathan Peyton 25737cc577a4SJonathan Peyton if (*threads_data_p != NULL) { 25747cc577a4SJonathan Peyton kmp_thread_data_t *old_data = *threads_data_p; 25757cc577a4SJonathan Peyton kmp_thread_data_t *new_data = NULL; 25767cc577a4SJonathan Peyton 2577*3041982dSJonathan Peyton KE_TRACE( 2578*3041982dSJonathan Peyton 10, 2579*3041982dSJonathan Peyton ("__kmp_realloc_task_threads_data: T#%d reallocating " 25807cc577a4SJonathan Peyton "threads data for task_team %p, new_size = %d, old_size = %d\n", 2581*3041982dSJonathan Peyton __kmp_gtid_from_thread(thread), task_team, nthreads, maxthreads)); 25827cc577a4SJonathan Peyton // Reallocate threads_data to have more elements than current array 25837cc577a4SJonathan Peyton // Cannot use __kmp_thread_realloc() because threads not around for 25847cc577a4SJonathan Peyton // kmp_reap_task_team( ). Note all new array entries are initialized 25857cc577a4SJonathan Peyton // to zero by __kmp_allocate(). 2586*3041982dSJonathan Peyton new_data = (kmp_thread_data_t *)__kmp_allocate( 2587*3041982dSJonathan Peyton nthreads * sizeof(kmp_thread_data_t)); 25887cc577a4SJonathan Peyton // copy old data to new data 25897cc577a4SJonathan Peyton KMP_MEMCPY_S((void *)new_data, nthreads * sizeof(kmp_thread_data_t), 2590*3041982dSJonathan Peyton (void *)old_data, maxthreads * sizeof(kmp_taskdata_t *)); 25917cc577a4SJonathan Peyton 25927cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK 25937cc577a4SJonathan Peyton // GEH: Figure out if this is the right thing to do 25947cc577a4SJonathan Peyton for (i = maxthreads; i < nthreads; i++) { 25957cc577a4SJonathan Peyton kmp_thread_data_t *thread_data = &(*threads_data_p)[i]; 25967cc577a4SJonathan Peyton __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data); 25977cc577a4SJonathan Peyton } 25987cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK 25997cc577a4SJonathan Peyton // Install the new data and free the old data 26007cc577a4SJonathan Peyton (*threads_data_p) = new_data; 26017cc577a4SJonathan Peyton __kmp_free(old_data); 2602*3041982dSJonathan Peyton } else { 26037cc577a4SJonathan Peyton KE_TRACE(10, ("__kmp_realloc_task_threads_data: T#%d allocating " 26047cc577a4SJonathan Peyton "threads data for task_team %p, size = %d\n", 26057cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread), task_team, nthreads)); 26067cc577a4SJonathan Peyton // Make the initial allocate for threads_data array, and zero entries 26077cc577a4SJonathan Peyton // Cannot use __kmp_thread_calloc() because threads not around for 26087cc577a4SJonathan Peyton // kmp_reap_task_team( ). 26097cc577a4SJonathan Peyton ANNOTATE_IGNORE_WRITES_BEGIN(); 2610*3041982dSJonathan Peyton *threads_data_p = (kmp_thread_data_t *)__kmp_allocate( 2611*3041982dSJonathan Peyton nthreads * sizeof(kmp_thread_data_t)); 26127cc577a4SJonathan Peyton ANNOTATE_IGNORE_WRITES_END(); 26137cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK 26147cc577a4SJonathan Peyton // GEH: Figure out if this is the right thing to do 26157cc577a4SJonathan Peyton for (i = 0; i < nthreads; i++) { 26167cc577a4SJonathan Peyton kmp_thread_data_t *thread_data = &(*threads_data_p)[i]; 26177cc577a4SJonathan Peyton __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data); 26187cc577a4SJonathan Peyton } 26197cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK 26207cc577a4SJonathan Peyton } 26217cc577a4SJonathan Peyton task_team->tt.tt_max_threads = nthreads; 2622*3041982dSJonathan Peyton } else { 26237cc577a4SJonathan Peyton // If array has (more than) enough elements, go ahead and use it 26247cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(*threads_data_p != NULL); 26257cc577a4SJonathan Peyton } 26267cc577a4SJonathan Peyton 26277cc577a4SJonathan Peyton // initialize threads_data pointers back to thread_info structures 26287cc577a4SJonathan Peyton for (i = 0; i < nthreads; i++) { 26297cc577a4SJonathan Peyton kmp_thread_data_t *thread_data = &(*threads_data_p)[i]; 26307cc577a4SJonathan Peyton thread_data->td.td_thr = team->t.t_threads[i]; 26317cc577a4SJonathan Peyton 26327cc577a4SJonathan Peyton if (thread_data->td.td_deque_last_stolen >= nthreads) { 26337cc577a4SJonathan Peyton // The last stolen field survives across teams / barrier, and the number 26347cc577a4SJonathan Peyton // of threads may have changed. It's possible (likely?) that a new 2635*3041982dSJonathan Peyton // parallel region will exhibit the same behavior as previous region. 26367cc577a4SJonathan Peyton thread_data->td.td_deque_last_stolen = -1; 26377cc577a4SJonathan Peyton } 26387cc577a4SJonathan Peyton } 26397cc577a4SJonathan Peyton 26407cc577a4SJonathan Peyton KMP_MB(); 26417cc577a4SJonathan Peyton TCW_SYNC_4(task_team->tt.tt_found_tasks, TRUE); 26427cc577a4SJonathan Peyton } 26437cc577a4SJonathan Peyton 26447cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock); 26457cc577a4SJonathan Peyton return is_init_thread; 26467cc577a4SJonathan Peyton } 26477cc577a4SJonathan Peyton 26487cc577a4SJonathan Peyton // __kmp_free_task_threads_data: 26497cc577a4SJonathan Peyton // Deallocates a threads_data array for a task team, including any attached 26507cc577a4SJonathan Peyton // tasking deques. Only occurs at library shutdown. 2651*3041982dSJonathan Peyton static void __kmp_free_task_threads_data(kmp_task_team_t *task_team) { 26527cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock); 26537cc577a4SJonathan Peyton if (task_team->tt.tt_threads_data != NULL) { 26547cc577a4SJonathan Peyton int i; 26557cc577a4SJonathan Peyton for (i = 0; i < task_team->tt.tt_max_threads; i++) { 26567cc577a4SJonathan Peyton __kmp_free_task_deque(&task_team->tt.tt_threads_data[i]); 26577cc577a4SJonathan Peyton } 26587cc577a4SJonathan Peyton __kmp_free(task_team->tt.tt_threads_data); 26597cc577a4SJonathan Peyton task_team->tt.tt_threads_data = NULL; 26607cc577a4SJonathan Peyton } 26617cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock); 26627cc577a4SJonathan Peyton } 26637cc577a4SJonathan Peyton 26647cc577a4SJonathan Peyton // __kmp_allocate_task_team: 26657cc577a4SJonathan Peyton // Allocates a task team associated with a specific team, taking it from 2666*3041982dSJonathan Peyton // the global task team free list if possible. Also initializes data 2667*3041982dSJonathan Peyton // structures. 2668*3041982dSJonathan Peyton static kmp_task_team_t *__kmp_allocate_task_team(kmp_info_t *thread, 2669*3041982dSJonathan Peyton kmp_team_t *team) { 26707cc577a4SJonathan Peyton kmp_task_team_t *task_team = NULL; 26717cc577a4SJonathan Peyton int nthreads; 26727cc577a4SJonathan Peyton 26737cc577a4SJonathan Peyton KA_TRACE(20, ("__kmp_allocate_task_team: T#%d entering; team = %p\n", 26747cc577a4SJonathan Peyton (thread ? __kmp_gtid_from_thread(thread) : -1), team)); 26757cc577a4SJonathan Peyton 26767cc577a4SJonathan Peyton if (TCR_PTR(__kmp_free_task_teams) != NULL) { 26777cc577a4SJonathan Peyton // Take a task team from the task team pool 26787cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock); 26797cc577a4SJonathan Peyton if (__kmp_free_task_teams != NULL) { 26807cc577a4SJonathan Peyton task_team = __kmp_free_task_teams; 26817cc577a4SJonathan Peyton TCW_PTR(__kmp_free_task_teams, task_team->tt.tt_next); 26827cc577a4SJonathan Peyton task_team->tt.tt_next = NULL; 26837cc577a4SJonathan Peyton } 26847cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&__kmp_task_team_lock); 26857cc577a4SJonathan Peyton } 26867cc577a4SJonathan Peyton 26877cc577a4SJonathan Peyton if (task_team == NULL) { 26887cc577a4SJonathan Peyton KE_TRACE(10, ("__kmp_allocate_task_team: T#%d allocating " 26897cc577a4SJonathan Peyton "task team for team %p\n", 26907cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread), team)); 26917cc577a4SJonathan Peyton // Allocate a new task team if one is not available. 26927cc577a4SJonathan Peyton // Cannot use __kmp_thread_malloc() because threads not around for 26937cc577a4SJonathan Peyton // kmp_reap_task_team( ). 26947cc577a4SJonathan Peyton task_team = (kmp_task_team_t *)__kmp_allocate(sizeof(kmp_task_team_t)); 26957cc577a4SJonathan Peyton __kmp_init_bootstrap_lock(&task_team->tt.tt_threads_lock); 2696*3041982dSJonathan Peyton // AC: __kmp_allocate zeroes returned memory 2697*3041982dSJonathan Peyton // task_team -> tt.tt_threads_data = NULL; 26987cc577a4SJonathan Peyton // task_team -> tt.tt_max_threads = 0; 26997cc577a4SJonathan Peyton // task_team -> tt.tt_next = NULL; 27007cc577a4SJonathan Peyton } 27017cc577a4SJonathan Peyton 27027cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_found_tasks, FALSE); 27037cc577a4SJonathan Peyton #if OMP_45_ENABLED 27047cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE); 27057cc577a4SJonathan Peyton #endif 27067cc577a4SJonathan Peyton task_team->tt.tt_nproc = nthreads = team->t.t_nproc; 27077cc577a4SJonathan Peyton 27087cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_unfinished_threads, nthreads); 27097cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_active, TRUE); 27107cc577a4SJonathan Peyton 2711*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_allocate_task_team: T#%d exiting; task_team = %p " 2712*3041982dSJonathan Peyton "unfinished_threads init'd to %d\n", 2713*3041982dSJonathan Peyton (thread ? __kmp_gtid_from_thread(thread) : -1), task_team, 2714*3041982dSJonathan Peyton task_team->tt.tt_unfinished_threads)); 27157cc577a4SJonathan Peyton return task_team; 27167cc577a4SJonathan Peyton } 27177cc577a4SJonathan Peyton 27187cc577a4SJonathan Peyton // __kmp_free_task_team: 27197cc577a4SJonathan Peyton // Frees the task team associated with a specific thread, and adds it 27207cc577a4SJonathan Peyton // to the global task team free list. 2721*3041982dSJonathan Peyton void __kmp_free_task_team(kmp_info_t *thread, kmp_task_team_t *task_team) { 27227cc577a4SJonathan Peyton KA_TRACE(20, ("__kmp_free_task_team: T#%d task_team = %p\n", 27237cc577a4SJonathan Peyton thread ? __kmp_gtid_from_thread(thread) : -1, task_team)); 27247cc577a4SJonathan Peyton 27257cc577a4SJonathan Peyton // Put task team back on free list 27267cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock); 27277cc577a4SJonathan Peyton 27287cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_team->tt.tt_next == NULL); 27297cc577a4SJonathan Peyton task_team->tt.tt_next = __kmp_free_task_teams; 27307cc577a4SJonathan Peyton TCW_PTR(__kmp_free_task_teams, task_team); 27317cc577a4SJonathan Peyton 27327cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&__kmp_task_team_lock); 27337cc577a4SJonathan Peyton } 27347cc577a4SJonathan Peyton 27357cc577a4SJonathan Peyton // __kmp_reap_task_teams: 27367cc577a4SJonathan Peyton // Free all the task teams on the task team free list. 27377cc577a4SJonathan Peyton // Should only be done during library shutdown. 2738*3041982dSJonathan Peyton // Cannot do anything that needs a thread structure or gtid since they are 2739*3041982dSJonathan Peyton // already gone. 2740*3041982dSJonathan Peyton void __kmp_reap_task_teams(void) { 27417cc577a4SJonathan Peyton kmp_task_team_t *task_team; 27427cc577a4SJonathan Peyton 27437cc577a4SJonathan Peyton if (TCR_PTR(__kmp_free_task_teams) != NULL) { 27447cc577a4SJonathan Peyton // Free all task_teams on the free list 27457cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock); 27467cc577a4SJonathan Peyton while ((task_team = __kmp_free_task_teams) != NULL) { 27477cc577a4SJonathan Peyton __kmp_free_task_teams = task_team->tt.tt_next; 27487cc577a4SJonathan Peyton task_team->tt.tt_next = NULL; 27497cc577a4SJonathan Peyton 27507cc577a4SJonathan Peyton // Free threads_data if necessary 27517cc577a4SJonathan Peyton if (task_team->tt.tt_threads_data != NULL) { 27527cc577a4SJonathan Peyton __kmp_free_task_threads_data(task_team); 27537cc577a4SJonathan Peyton } 27547cc577a4SJonathan Peyton __kmp_free(task_team); 27557cc577a4SJonathan Peyton } 27567cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&__kmp_task_team_lock); 27577cc577a4SJonathan Peyton } 27587cc577a4SJonathan Peyton } 27597cc577a4SJonathan Peyton 27607cc577a4SJonathan Peyton // __kmp_wait_to_unref_task_teams: 27617cc577a4SJonathan Peyton // Some threads could still be in the fork barrier release code, possibly 27627cc577a4SJonathan Peyton // trying to steal tasks. Wait for each thread to unreference its task team. 2763*3041982dSJonathan Peyton void __kmp_wait_to_unref_task_teams(void) { 27647cc577a4SJonathan Peyton kmp_info_t *thread; 27657cc577a4SJonathan Peyton kmp_uint32 spins; 27667cc577a4SJonathan Peyton int done; 27677cc577a4SJonathan Peyton 27687cc577a4SJonathan Peyton KMP_INIT_YIELD(spins); 27697cc577a4SJonathan Peyton 27707cc577a4SJonathan Peyton for (;;) { 27717cc577a4SJonathan Peyton done = TRUE; 27727cc577a4SJonathan Peyton 27737cc577a4SJonathan Peyton // TODO: GEH - this may be is wrong because some sync would be necessary 2774*3041982dSJonathan Peyton // in case threads are added to the pool during the traversal. Need to 2775*3041982dSJonathan Peyton // verify that lock for thread pool is held when calling this routine. 2776*3041982dSJonathan Peyton for (thread = (kmp_info_t *)__kmp_thread_pool; thread != NULL; 2777*3041982dSJonathan Peyton thread = thread->th.th_next_pool) { 27787cc577a4SJonathan Peyton #if KMP_OS_WINDOWS 27797cc577a4SJonathan Peyton DWORD exit_val; 27807cc577a4SJonathan Peyton #endif 27817cc577a4SJonathan Peyton if (TCR_PTR(thread->th.th_task_team) == NULL) { 27827cc577a4SJonathan Peyton KA_TRACE(10, ("__kmp_wait_to_unref_task_team: T#%d task_team == NULL\n", 27837cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread))); 27847cc577a4SJonathan Peyton continue; 27857cc577a4SJonathan Peyton } 27867cc577a4SJonathan Peyton #if KMP_OS_WINDOWS 27877cc577a4SJonathan Peyton // TODO: GEH - add this check for Linux* OS / OS X* as well? 27887cc577a4SJonathan Peyton if (!__kmp_is_thread_alive(thread, &exit_val)) { 27897cc577a4SJonathan Peyton thread->th.th_task_team = NULL; 27907cc577a4SJonathan Peyton continue; 27917cc577a4SJonathan Peyton } 27927cc577a4SJonathan Peyton #endif 27937cc577a4SJonathan Peyton 27947cc577a4SJonathan Peyton done = FALSE; // Because th_task_team pointer is not NULL for this thread 27957cc577a4SJonathan Peyton 2796*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_wait_to_unref_task_team: Waiting for T#%d to " 2797*3041982dSJonathan Peyton "unreference task_team\n", 27987cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread))); 27997cc577a4SJonathan Peyton 28007cc577a4SJonathan Peyton if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) { 28017cc577a4SJonathan Peyton volatile void *sleep_loc; 28027cc577a4SJonathan Peyton // If the thread is sleeping, awaken it. 28037cc577a4SJonathan Peyton if ((sleep_loc = TCR_PTR(thread->th.th_sleep_loc)) != NULL) { 2804*3041982dSJonathan Peyton KA_TRACE( 2805*3041982dSJonathan Peyton 10, 2806*3041982dSJonathan Peyton ("__kmp_wait_to_unref_task_team: T#%d waking up thread T#%d\n", 28077cc577a4SJonathan Peyton __kmp_gtid_from_thread(thread), __kmp_gtid_from_thread(thread))); 28087cc577a4SJonathan Peyton __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc); 28097cc577a4SJonathan Peyton } 28107cc577a4SJonathan Peyton } 28117cc577a4SJonathan Peyton } 28127cc577a4SJonathan Peyton if (done) { 28137cc577a4SJonathan Peyton break; 28147cc577a4SJonathan Peyton } 28157cc577a4SJonathan Peyton 2816*3041982dSJonathan Peyton // If we are oversubscribed, or have waited a bit (and library mode is 2817*3041982dSJonathan Peyton // throughput), yield. Pause is in the following code. 28187cc577a4SJonathan Peyton KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc); 28197cc577a4SJonathan Peyton KMP_YIELD_SPIN(spins); // Yields only if KMP_LIBRARY=throughput 28207cc577a4SJonathan Peyton } 28217cc577a4SJonathan Peyton } 28227cc577a4SJonathan Peyton 28237cc577a4SJonathan Peyton // __kmp_task_team_setup: Create a task_team for the current team, but use 28247cc577a4SJonathan Peyton // an already created, unused one if it already exists. 2825*3041982dSJonathan Peyton void __kmp_task_team_setup(kmp_info_t *this_thr, kmp_team_t *team, int always) { 28267cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 28277cc577a4SJonathan Peyton 2828*3041982dSJonathan Peyton // If this task_team hasn't been created yet, allocate it. It will be used in 2829*3041982dSJonathan Peyton // the region after the next. 2830*3041982dSJonathan Peyton // If it exists, it is the current task team and shouldn't be touched yet as 2831*3041982dSJonathan Peyton // it may still be in use. 2832*3041982dSJonathan Peyton if (team->t.t_task_team[this_thr->th.th_task_state] == NULL && 2833*3041982dSJonathan Peyton (always || team->t.t_nproc > 1)) { 2834*3041982dSJonathan Peyton team->t.t_task_team[this_thr->th.th_task_state] = 2835*3041982dSJonathan Peyton __kmp_allocate_task_team(this_thr, team); 2836*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created new task_team %p " 2837*3041982dSJonathan Peyton "for team %d at parity=%d\n", 2838*3041982dSJonathan Peyton __kmp_gtid_from_thread(this_thr), 2839*3041982dSJonathan Peyton team->t.t_task_team[this_thr->th.th_task_state], 2840*3041982dSJonathan Peyton ((team != NULL) ? team->t.t_id : -1), 2841*3041982dSJonathan Peyton this_thr->th.th_task_state)); 28427cc577a4SJonathan Peyton } 28437cc577a4SJonathan Peyton 2844*3041982dSJonathan Peyton // After threads exit the release, they will call sync, and then point to this 2845*3041982dSJonathan Peyton // other task_team; make sure it is allocated and properly initialized. As 2846*3041982dSJonathan Peyton // threads spin in the barrier release phase, they will continue to use the 2847*3041982dSJonathan Peyton // previous task_team struct(above), until they receive the signal to stop 2848*3041982dSJonathan Peyton // checking for tasks (they can't safely reference the kmp_team_t struct, 2849*3041982dSJonathan Peyton // which could be reallocated by the master thread). No task teams are formed 2850*3041982dSJonathan Peyton // for serialized teams. 28517cc577a4SJonathan Peyton if (team->t.t_nproc > 1) { 28527cc577a4SJonathan Peyton int other_team = 1 - this_thr->th.th_task_state; 28537cc577a4SJonathan Peyton if (team->t.t_task_team[other_team] == NULL) { // setup other team as well 2854*3041982dSJonathan Peyton team->t.t_task_team[other_team] = 2855*3041982dSJonathan Peyton __kmp_allocate_task_team(this_thr, team); 2856*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created second new " 2857*3041982dSJonathan Peyton "task_team %p for team %d at parity=%d\n", 2858*3041982dSJonathan Peyton __kmp_gtid_from_thread(this_thr), 2859*3041982dSJonathan Peyton team->t.t_task_team[other_team], 28607cc577a4SJonathan Peyton ((team != NULL) ? team->t.t_id : -1), other_team)); 2861*3041982dSJonathan Peyton } else { // Leave the old task team struct in place for the upcoming region; 2862*3041982dSJonathan Peyton // adjust as needed 28637cc577a4SJonathan Peyton kmp_task_team_t *task_team = team->t.t_task_team[other_team]; 2864*3041982dSJonathan Peyton if (!task_team->tt.tt_active || 2865*3041982dSJonathan Peyton team->t.t_nproc != task_team->tt.tt_nproc) { 28667cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_nproc, team->t.t_nproc); 28677cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_found_tasks, FALSE); 28687cc577a4SJonathan Peyton #if OMP_45_ENABLED 28697cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE); 28707cc577a4SJonathan Peyton #endif 28717cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_unfinished_threads, team->t.t_nproc); 28727cc577a4SJonathan Peyton TCW_4(task_team->tt.tt_active, TRUE); 28737cc577a4SJonathan Peyton } 2874*3041982dSJonathan Peyton // if team size has changed, the first thread to enable tasking will 2875*3041982dSJonathan Peyton // realloc threads_data if necessary 2876*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d reset next task_team " 2877*3041982dSJonathan Peyton "%p for team %d at parity=%d\n", 2878*3041982dSJonathan Peyton __kmp_gtid_from_thread(this_thr), 2879*3041982dSJonathan Peyton team->t.t_task_team[other_team], 28807cc577a4SJonathan Peyton ((team != NULL) ? team->t.t_id : -1), other_team)); 28817cc577a4SJonathan Peyton } 28827cc577a4SJonathan Peyton } 28837cc577a4SJonathan Peyton } 28847cc577a4SJonathan Peyton 28857cc577a4SJonathan Peyton // __kmp_task_team_sync: Propagation of task team data from team to threads 28867cc577a4SJonathan Peyton // which happens just after the release phase of a team barrier. This may be 28877cc577a4SJonathan Peyton // called by any thread, but only for teams with # threads > 1. 2888*3041982dSJonathan Peyton void __kmp_task_team_sync(kmp_info_t *this_thr, kmp_team_t *team) { 28897cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 28907cc577a4SJonathan Peyton 2891*3041982dSJonathan Peyton // Toggle the th_task_state field, to switch which task_team this thread 2892*3041982dSJonathan Peyton // refers to 28937cc577a4SJonathan Peyton this_thr->th.th_task_state = 1 - this_thr->th.th_task_state; 2894*3041982dSJonathan Peyton // It is now safe to propagate the task team pointer from the team struct to 2895*3041982dSJonathan Peyton // the current thread. 2896*3041982dSJonathan Peyton TCW_PTR(this_thr->th.th_task_team, 2897*3041982dSJonathan Peyton team->t.t_task_team[this_thr->th.th_task_state]); 2898*3041982dSJonathan Peyton KA_TRACE(20, 2899*3041982dSJonathan Peyton ("__kmp_task_team_sync: Thread T#%d task team switched to task_team " 2900*3041982dSJonathan Peyton "%p from Team #%d (parity=%d)\n", 29017cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), this_thr->th.th_task_team, 29027cc577a4SJonathan Peyton ((team != NULL) ? team->t.t_id : -1), this_thr->th.th_task_state)); 29037cc577a4SJonathan Peyton } 29047cc577a4SJonathan Peyton 2905*3041982dSJonathan Peyton // __kmp_task_team_wait: Master thread waits for outstanding tasks after the 2906*3041982dSJonathan Peyton // barrier gather phase. Only called by master thread if #threads in team > 1 or 2907*3041982dSJonathan Peyton // if proxy tasks were created. 2908*3041982dSJonathan Peyton // 2909*3041982dSJonathan Peyton // wait is a flag that defaults to 1 (see kmp.h), but waiting can be turned off 2910*3041982dSJonathan Peyton // by passing in 0 optionally as the last argument. When wait is zero, master 2911*3041982dSJonathan Peyton // thread does not wait for unfinished_threads to reach 0. 2912*3041982dSJonathan Peyton void __kmp_task_team_wait( 2913*3041982dSJonathan Peyton kmp_info_t *this_thr, 2914*3041982dSJonathan Peyton kmp_team_t *team USE_ITT_BUILD_ARG(void *itt_sync_obj), int wait) { 29157cc577a4SJonathan Peyton kmp_task_team_t *task_team = team->t.t_task_team[this_thr->th.th_task_state]; 29167cc577a4SJonathan Peyton 29177cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec); 29187cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_team == this_thr->th.th_task_team); 29197cc577a4SJonathan Peyton 29207cc577a4SJonathan Peyton if ((task_team != NULL) && KMP_TASKING_ENABLED(task_team)) { 29217cc577a4SJonathan Peyton if (wait) { 2922*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_task_team_wait: Master T#%d waiting for all tasks " 2923*3041982dSJonathan Peyton "(for unfinished_threads to reach 0) on task_team = %p\n", 29247cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), task_team)); 2925*3041982dSJonathan Peyton // Worker threads may have dropped through to release phase, but could 2926*3041982dSJonathan Peyton // still be executing tasks. Wait here for tasks to complete. To avoid 2927*3041982dSJonathan Peyton // memory contention, only master thread checks termination condition. 29287cc577a4SJonathan Peyton kmp_flag_32 flag(&task_team->tt.tt_unfinished_threads, 0U); 2929*3041982dSJonathan Peyton flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj)); 29307cc577a4SJonathan Peyton } 2931*3041982dSJonathan Peyton // Deactivate the old task team, so that the worker threads will stop 2932*3041982dSJonathan Peyton // referencing it while spinning. 2933*3041982dSJonathan Peyton KA_TRACE( 2934*3041982dSJonathan Peyton 20, 2935*3041982dSJonathan Peyton ("__kmp_task_team_wait: Master T#%d deactivating task_team %p: " 29367cc577a4SJonathan Peyton "setting active to false, setting local and team's pointer to NULL\n", 29377cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), task_team)); 29387cc577a4SJonathan Peyton #if OMP_45_ENABLED 2939*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(task_team->tt.tt_nproc > 1 || 2940*3041982dSJonathan Peyton task_team->tt.tt_found_proxy_tasks == TRUE); 29417cc577a4SJonathan Peyton TCW_SYNC_4(task_team->tt.tt_found_proxy_tasks, FALSE); 29427cc577a4SJonathan Peyton #else 29437cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_team->tt.tt_nproc > 1); 29447cc577a4SJonathan Peyton #endif 29457cc577a4SJonathan Peyton TCW_SYNC_4(task_team->tt.tt_active, FALSE); 29467cc577a4SJonathan Peyton KMP_MB(); 29477cc577a4SJonathan Peyton 29487cc577a4SJonathan Peyton TCW_PTR(this_thr->th.th_task_team, NULL); 29497cc577a4SJonathan Peyton } 29507cc577a4SJonathan Peyton } 29517cc577a4SJonathan Peyton 29527cc577a4SJonathan Peyton // __kmp_tasking_barrier: 29537cc577a4SJonathan Peyton // This routine may only called when __kmp_tasking_mode == tskm_extra_barrier. 2954*3041982dSJonathan Peyton // Internal function to execute all tasks prior to a regular barrier or a join 2955*3041982dSJonathan Peyton // barrier. It is a full barrier itself, which unfortunately turns regular 2956*3041982dSJonathan Peyton // barriers into double barriers and join barriers into 1 1/2 barriers. 2957*3041982dSJonathan Peyton void __kmp_tasking_barrier(kmp_team_t *team, kmp_info_t *thread, int gtid) { 2958*3041982dSJonathan Peyton volatile kmp_uint32 *spin = 2959*3041982dSJonathan Peyton &team->t.t_task_team[thread->th.th_task_state]->tt.tt_unfinished_threads; 29607cc577a4SJonathan Peyton int flag = FALSE; 29617cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_tasking_mode == tskm_extra_barrier); 29627cc577a4SJonathan Peyton 29637cc577a4SJonathan Peyton #if USE_ITT_BUILD 29647cc577a4SJonathan Peyton KMP_FSYNC_SPIN_INIT(spin, (kmp_uint32 *)NULL); 29657cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 29667cc577a4SJonathan Peyton kmp_flag_32 spin_flag(spin, 0U); 2967*3041982dSJonathan Peyton while (!spin_flag.execute_tasks(thread, gtid, TRUE, 2968*3041982dSJonathan Peyton &flag USE_ITT_BUILD_ARG(NULL), 0)) { 29697cc577a4SJonathan Peyton #if USE_ITT_BUILD 29707cc577a4SJonathan Peyton // TODO: What about itt_sync_obj?? 29717cc577a4SJonathan Peyton KMP_FSYNC_SPIN_PREPARE(spin); 29727cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 29737cc577a4SJonathan Peyton 29747cc577a4SJonathan Peyton if (TCR_4(__kmp_global.g.g_done)) { 29757cc577a4SJonathan Peyton if (__kmp_global.g.g_abort) 29767cc577a4SJonathan Peyton __kmp_abort_thread(); 29777cc577a4SJonathan Peyton break; 29787cc577a4SJonathan Peyton } 29797cc577a4SJonathan Peyton KMP_YIELD(TRUE); // GH: We always yield here 29807cc577a4SJonathan Peyton } 29817cc577a4SJonathan Peyton #if USE_ITT_BUILD 29827cc577a4SJonathan Peyton KMP_FSYNC_SPIN_ACQUIRED((void *)spin); 29837cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */ 29847cc577a4SJonathan Peyton } 29857cc577a4SJonathan Peyton 29867cc577a4SJonathan Peyton #if OMP_45_ENABLED 29877cc577a4SJonathan Peyton 2988*3041982dSJonathan Peyton // __kmp_give_task puts a task into a given thread queue if: 2989*3041982dSJonathan Peyton // - the queue for that thread was created 2990*3041982dSJonathan Peyton // - there's space in that queue 2991*3041982dSJonathan Peyton // Because of this, __kmp_push_task needs to check if there's space after 2992*3041982dSJonathan Peyton // getting the lock 2993*3041982dSJonathan Peyton static bool __kmp_give_task(kmp_info_t *thread, kmp_int32 tid, kmp_task_t *task, 2994*3041982dSJonathan Peyton kmp_int32 pass) { 29957cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 29967cc577a4SJonathan Peyton kmp_task_team_t *task_team = taskdata->td_task_team; 29977cc577a4SJonathan Peyton 2998*3041982dSJonathan Peyton KA_TRACE(20, ("__kmp_give_task: trying to give task %p to thread %d.\n", 2999*3041982dSJonathan Peyton taskdata, tid)); 30007cc577a4SJonathan Peyton 30017cc577a4SJonathan Peyton // If task_team is NULL something went really bad... 30027cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task_team != NULL); 30037cc577a4SJonathan Peyton 30047cc577a4SJonathan Peyton bool result = false; 30057cc577a4SJonathan Peyton kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid]; 30067cc577a4SJonathan Peyton 30077cc577a4SJonathan Peyton if (thread_data->td.td_deque == NULL) { 30087cc577a4SJonathan Peyton // There's no queue in this thread, go find another one 30097cc577a4SJonathan Peyton // We're guaranteed that at least one thread has a queue 3010*3041982dSJonathan Peyton KA_TRACE(30, 3011*3041982dSJonathan Peyton ("__kmp_give_task: thread %d has no queue while giving task %p.\n", 3012*3041982dSJonathan Peyton tid, taskdata)); 30137cc577a4SJonathan Peyton return result; 30147cc577a4SJonathan Peyton } 30157cc577a4SJonathan Peyton 3016*3041982dSJonathan Peyton if (TCR_4(thread_data->td.td_deque_ntasks) >= 3017*3041982dSJonathan Peyton TASK_DEQUE_SIZE(thread_data->td)) { 3018*3041982dSJonathan Peyton KA_TRACE( 3019*3041982dSJonathan Peyton 30, 3020*3041982dSJonathan Peyton ("__kmp_give_task: queue is full while giving task %p to thread %d.\n", 3021*3041982dSJonathan Peyton taskdata, tid)); 30227cc577a4SJonathan Peyton 3023*3041982dSJonathan Peyton // if this deque is bigger than the pass ratio give a chance to another 3024*3041982dSJonathan Peyton // thread 3025*3041982dSJonathan Peyton if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass) 3026*3041982dSJonathan Peyton return result; 30277cc577a4SJonathan Peyton 30287cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 30297cc577a4SJonathan Peyton __kmp_realloc_task_deque(thread, thread_data); 30307cc577a4SJonathan Peyton 30317cc577a4SJonathan Peyton } else { 30327cc577a4SJonathan Peyton 30337cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock); 30347cc577a4SJonathan Peyton 3035*3041982dSJonathan Peyton if (TCR_4(thread_data->td.td_deque_ntasks) >= 3036*3041982dSJonathan Peyton TASK_DEQUE_SIZE(thread_data->td)) { 3037*3041982dSJonathan Peyton KA_TRACE(30, ("__kmp_give_task: queue is full while giving task %p to " 3038*3041982dSJonathan Peyton "thread %d.\n", 3039*3041982dSJonathan Peyton taskdata, tid)); 30407cc577a4SJonathan Peyton 3041*3041982dSJonathan Peyton // if this deque is bigger than the pass ratio give a chance to another 3042*3041982dSJonathan Peyton // thread 30437cc577a4SJonathan Peyton if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass) 30447cc577a4SJonathan Peyton goto release_and_exit; 30457cc577a4SJonathan Peyton 30467cc577a4SJonathan Peyton __kmp_realloc_task_deque(thread, thread_data); 30477cc577a4SJonathan Peyton } 30487cc577a4SJonathan Peyton } 30497cc577a4SJonathan Peyton 30507cc577a4SJonathan Peyton // lock is held here, and there is space in the deque 30517cc577a4SJonathan Peyton 30527cc577a4SJonathan Peyton thread_data->td.td_deque[thread_data->td.td_deque_tail] = taskdata; 30537cc577a4SJonathan Peyton // Wrap index. 3054*3041982dSJonathan Peyton thread_data->td.td_deque_tail = 3055*3041982dSJonathan Peyton (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td); 3056*3041982dSJonathan Peyton TCW_4(thread_data->td.td_deque_ntasks, 3057*3041982dSJonathan Peyton TCR_4(thread_data->td.td_deque_ntasks) + 1); 30587cc577a4SJonathan Peyton 30597cc577a4SJonathan Peyton result = true; 3060*3041982dSJonathan Peyton KA_TRACE(30, ("__kmp_give_task: successfully gave task %p to thread %d.\n", 3061*3041982dSJonathan Peyton taskdata, tid)); 30627cc577a4SJonathan Peyton 30637cc577a4SJonathan Peyton release_and_exit: 30647cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock); 30657cc577a4SJonathan Peyton 30667cc577a4SJonathan Peyton return result; 30677cc577a4SJonathan Peyton } 30687cc577a4SJonathan Peyton 3069*3041982dSJonathan Peyton /* The finish of the proxy tasks is divided in two pieces: 30707cc577a4SJonathan Peyton - the top half is the one that can be done from a thread outside the team 30717cc577a4SJonathan Peyton - the bottom half must be run from a them within the team 30727cc577a4SJonathan Peyton 3073*3041982dSJonathan Peyton In order to run the bottom half the task gets queued back into one of the 3074*3041982dSJonathan Peyton threads of the team. Once the td_incomplete_child_task counter of the parent 3075*3041982dSJonathan Peyton is decremented the threads can leave the barriers. So, the bottom half needs 3076*3041982dSJonathan Peyton to be queued before the counter is decremented. The top half is therefore 3077*3041982dSJonathan Peyton divided in two parts: 30787cc577a4SJonathan Peyton - things that can be run before queuing the bottom half 30797cc577a4SJonathan Peyton - things that must be run after queuing the bottom half 30807cc577a4SJonathan Peyton 3081*3041982dSJonathan Peyton This creates a second race as the bottom half can free the task before the 3082*3041982dSJonathan Peyton second top half is executed. To avoid this we use the 3083*3041982dSJonathan Peyton td_incomplete_child_task of the proxy task to synchronize the top and bottom 3084*3041982dSJonathan Peyton half. */ 3085*3041982dSJonathan Peyton static void __kmp_first_top_half_finish_proxy(kmp_taskdata_t *taskdata) { 30867cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT); 30877cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 30887cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0); 30897cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0); 30907cc577a4SJonathan Peyton 30917cc577a4SJonathan Peyton taskdata->td_flags.complete = 1; // mark the task as completed 30927cc577a4SJonathan Peyton 30937cc577a4SJonathan Peyton if (taskdata->td_taskgroup) 30947cc577a4SJonathan Peyton KMP_TEST_THEN_DEC32((kmp_int32 *)(&taskdata->td_taskgroup->count)); 30957cc577a4SJonathan Peyton 3096*3041982dSJonathan Peyton // Create an imaginary children for this task so the bottom half cannot 3097*3041982dSJonathan Peyton // release the task before we have completed the second top half 30987cc577a4SJonathan Peyton TCI_4(taskdata->td_incomplete_child_tasks); 30997cc577a4SJonathan Peyton } 31007cc577a4SJonathan Peyton 3101*3041982dSJonathan Peyton static void __kmp_second_top_half_finish_proxy(kmp_taskdata_t *taskdata) { 31027cc577a4SJonathan Peyton kmp_int32 children = 0; 31037cc577a4SJonathan Peyton 31047cc577a4SJonathan Peyton // Predecrement simulated by "- 1" calculation 3105*3041982dSJonathan Peyton children = 3106*3041982dSJonathan Peyton KMP_TEST_THEN_DEC32( 3107*3041982dSJonathan Peyton (kmp_int32 *)(&taskdata->td_parent->td_incomplete_child_tasks)) - 3108*3041982dSJonathan Peyton 1; 31097cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(children >= 0); 31107cc577a4SJonathan Peyton 31117cc577a4SJonathan Peyton // Remove the imaginary children 31127cc577a4SJonathan Peyton TCD_4(taskdata->td_incomplete_child_tasks); 31137cc577a4SJonathan Peyton } 31147cc577a4SJonathan Peyton 3115*3041982dSJonathan Peyton static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask) { 31167cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask); 31177cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 31187cc577a4SJonathan Peyton 31197cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 3120*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 3121*3041982dSJonathan Peyton 1); // top half must run before bottom half 31227cc577a4SJonathan Peyton 31237cc577a4SJonathan Peyton // We need to wait to make sure the top half is finished 31247cc577a4SJonathan Peyton // Spinning here should be ok as this should happen quickly 3125*3041982dSJonathan Peyton while (TCR_4(taskdata->td_incomplete_child_tasks) > 0) 3126*3041982dSJonathan Peyton ; 31277cc577a4SJonathan Peyton 31287cc577a4SJonathan Peyton __kmp_release_deps(gtid, taskdata); 31297cc577a4SJonathan Peyton __kmp_free_task_and_ancestors(gtid, taskdata, thread); 31307cc577a4SJonathan Peyton } 31317cc577a4SJonathan Peyton 31327cc577a4SJonathan Peyton /*! 31337cc577a4SJonathan Peyton @ingroup TASKING 31347cc577a4SJonathan Peyton @param gtid Global Thread ID of encountering thread 31357cc577a4SJonathan Peyton @param ptask Task which execution is completed 31367cc577a4SJonathan Peyton 3137*3041982dSJonathan Peyton Execute the completation of a proxy task from a thread of that is part of the 3138*3041982dSJonathan Peyton team. Run first and bottom halves directly. 31397cc577a4SJonathan Peyton */ 3140*3041982dSJonathan Peyton void __kmpc_proxy_task_completed(kmp_int32 gtid, kmp_task_t *ptask) { 31417cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(ptask != NULL); 31427cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask); 3143*3041982dSJonathan Peyton KA_TRACE( 3144*3041982dSJonathan Peyton 10, ("__kmp_proxy_task_completed(enter): T#%d proxy task %p completing\n", 3145*3041982dSJonathan Peyton gtid, taskdata)); 31467cc577a4SJonathan Peyton 31477cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 31487cc577a4SJonathan Peyton 31497cc577a4SJonathan Peyton __kmp_first_top_half_finish_proxy(taskdata); 31507cc577a4SJonathan Peyton __kmp_second_top_half_finish_proxy(taskdata); 31517cc577a4SJonathan Peyton __kmp_bottom_half_finish_proxy(gtid, ptask); 31527cc577a4SJonathan Peyton 3153*3041982dSJonathan Peyton KA_TRACE(10, 3154*3041982dSJonathan Peyton ("__kmp_proxy_task_completed(exit): T#%d proxy task %p completing\n", 3155*3041982dSJonathan Peyton gtid, taskdata)); 31567cc577a4SJonathan Peyton } 31577cc577a4SJonathan Peyton 31587cc577a4SJonathan Peyton /*! 31597cc577a4SJonathan Peyton @ingroup TASKING 31607cc577a4SJonathan Peyton @param ptask Task which execution is completed 31617cc577a4SJonathan Peyton 3162*3041982dSJonathan Peyton Execute the completation of a proxy task from a thread that could not belong to 3163*3041982dSJonathan Peyton the team. 31647cc577a4SJonathan Peyton */ 3165*3041982dSJonathan Peyton void __kmpc_proxy_task_completed_ooo(kmp_task_t *ptask) { 31667cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(ptask != NULL); 31677cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask); 31687cc577a4SJonathan Peyton 3169*3041982dSJonathan Peyton KA_TRACE( 3170*3041982dSJonathan Peyton 10, 3171*3041982dSJonathan Peyton ("__kmp_proxy_task_completed_ooo(enter): proxy task completing ooo %p\n", 3172*3041982dSJonathan Peyton taskdata)); 31737cc577a4SJonathan Peyton 31747cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY); 31757cc577a4SJonathan Peyton 31767cc577a4SJonathan Peyton __kmp_first_top_half_finish_proxy(taskdata); 31777cc577a4SJonathan Peyton 3178*3041982dSJonathan Peyton // Enqueue task to complete bottom half completion from a thread within the 3179*3041982dSJonathan Peyton // corresponding team 31807cc577a4SJonathan Peyton kmp_team_t *team = taskdata->td_team; 31817cc577a4SJonathan Peyton kmp_int32 nthreads = team->t.t_nproc; 31827cc577a4SJonathan Peyton kmp_info_t *thread; 31837cc577a4SJonathan Peyton 3184*3041982dSJonathan Peyton // This should be similar to start_k = __kmp_get_random( thread ) % nthreads 3185*3041982dSJonathan Peyton // but we cannot use __kmp_get_random here 31867cc577a4SJonathan Peyton kmp_int32 start_k = 0; 31877cc577a4SJonathan Peyton kmp_int32 pass = 1; 31887cc577a4SJonathan Peyton kmp_int32 k = start_k; 31897cc577a4SJonathan Peyton 31907cc577a4SJonathan Peyton do { 31917cc577a4SJonathan Peyton // For now we're just linearly trying to find a thread 31927cc577a4SJonathan Peyton thread = team->t.t_threads[k]; 31937cc577a4SJonathan Peyton k = (k + 1) % nthreads; 31947cc577a4SJonathan Peyton 31957cc577a4SJonathan Peyton // we did a full pass through all the threads 3196*3041982dSJonathan Peyton if (k == start_k) 3197*3041982dSJonathan Peyton pass = pass << 1; 31987cc577a4SJonathan Peyton 31997cc577a4SJonathan Peyton } while (!__kmp_give_task(thread, k, ptask, pass)); 32007cc577a4SJonathan Peyton 32017cc577a4SJonathan Peyton __kmp_second_top_half_finish_proxy(taskdata); 32027cc577a4SJonathan Peyton 3203*3041982dSJonathan Peyton KA_TRACE( 3204*3041982dSJonathan Peyton 10, 3205*3041982dSJonathan Peyton ("__kmp_proxy_task_completed_ooo(exit): proxy task completing ooo %p\n", 3206*3041982dSJonathan Peyton taskdata)); 32077cc577a4SJonathan Peyton } 32087cc577a4SJonathan Peyton 3209*3041982dSJonathan Peyton // __kmp_task_dup_alloc: Allocate the taskdata and make a copy of source task 3210*3041982dSJonathan Peyton // for taskloop 32117cc577a4SJonathan Peyton // 32127cc577a4SJonathan Peyton // thread: allocating thread 32137cc577a4SJonathan Peyton // task_src: pointer to source task to be duplicated 32147cc577a4SJonathan Peyton // returns: a pointer to the allocated kmp_task_t structure (task). 3215*3041982dSJonathan Peyton kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src) { 32167cc577a4SJonathan Peyton kmp_task_t *task; 32177cc577a4SJonathan Peyton kmp_taskdata_t *taskdata; 32187cc577a4SJonathan Peyton kmp_taskdata_t *taskdata_src; 32197cc577a4SJonathan Peyton kmp_taskdata_t *parent_task = thread->th.th_current_task; 32207cc577a4SJonathan Peyton size_t shareds_offset; 32217cc577a4SJonathan Peyton size_t task_size; 32227cc577a4SJonathan Peyton 3223*3041982dSJonathan Peyton KA_TRACE(10, ("__kmp_task_dup_alloc(enter): Th %p, source task %p\n", thread, 3224*3041982dSJonathan Peyton task_src)); 32257cc577a4SJonathan Peyton taskdata_src = KMP_TASK_TO_TASKDATA(task_src); 3226*3041982dSJonathan Peyton KMP_DEBUG_ASSERT(taskdata_src->td_flags.proxy == 3227*3041982dSJonathan Peyton TASK_FULL); // it should not be proxy task 32287cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(taskdata_src->td_flags.tasktype == TASK_EXPLICIT); 32297cc577a4SJonathan Peyton task_size = taskdata_src->td_size_alloc; 32307cc577a4SJonathan Peyton 32317cc577a4SJonathan Peyton // Allocate a kmp_taskdata_t block and a kmp_task_t block. 3232*3041982dSJonathan Peyton KA_TRACE(30, ("__kmp_task_dup_alloc: Th %p, malloc size %ld\n", thread, 3233*3041982dSJonathan Peyton task_size)); 32347cc577a4SJonathan Peyton #if USE_FAST_MEMORY 32357cc577a4SJonathan Peyton taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, task_size); 32367cc577a4SJonathan Peyton #else 32377cc577a4SJonathan Peyton taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, task_size); 32387cc577a4SJonathan Peyton #endif /* USE_FAST_MEMORY */ 32397cc577a4SJonathan Peyton KMP_MEMCPY(taskdata, taskdata_src, task_size); 32407cc577a4SJonathan Peyton 32417cc577a4SJonathan Peyton task = KMP_TASKDATA_TO_TASK(taskdata); 32427cc577a4SJonathan Peyton 32437cc577a4SJonathan Peyton // Initialize new task (only specific fields not affected by memcpy) 32447cc577a4SJonathan Peyton taskdata->td_task_id = KMP_GEN_TASK_ID(); 32457cc577a4SJonathan Peyton if (task->shareds != NULL) { // need setup shareds pointer 32467cc577a4SJonathan Peyton shareds_offset = (char *)task_src->shareds - (char *)taskdata_src; 32477cc577a4SJonathan Peyton task->shareds = &((char *)taskdata)[shareds_offset]; 3248*3041982dSJonathan Peyton KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) == 3249*3041982dSJonathan Peyton 0); 32507cc577a4SJonathan Peyton } 32517cc577a4SJonathan Peyton taskdata->td_alloc_thread = thread; 3252*3041982dSJonathan Peyton taskdata->td_taskgroup = 3253*3041982dSJonathan Peyton parent_task 3254*3041982dSJonathan Peyton ->td_taskgroup; // task inherits the taskgroup from the parent task 32557cc577a4SJonathan Peyton 3256*3041982dSJonathan Peyton // Only need to keep track of child task counts if team parallel and tasking 3257*3041982dSJonathan Peyton // not serialized 32587cc577a4SJonathan Peyton if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) { 32597cc577a4SJonathan Peyton KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_incomplete_child_tasks)); 32607cc577a4SJonathan Peyton if (parent_task->td_taskgroup) 32617cc577a4SJonathan Peyton KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_taskgroup->count)); 3262*3041982dSJonathan Peyton // Only need to keep track of allocated child tasks for explicit tasks since 3263*3041982dSJonathan Peyton // implicit not deallocated 32647cc577a4SJonathan Peyton if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT) 3265*3041982dSJonathan Peyton KMP_TEST_THEN_INC32( 3266*3041982dSJonathan Peyton (kmp_int32 *)(&taskdata->td_parent->td_allocated_child_tasks)); 32677cc577a4SJonathan Peyton } 32687cc577a4SJonathan Peyton 3269*3041982dSJonathan Peyton KA_TRACE(20, 3270*3041982dSJonathan Peyton ("__kmp_task_dup_alloc(exit): Th %p, created task %p, parent=%p\n", 32717cc577a4SJonathan Peyton thread, taskdata, taskdata->td_parent)); 32727cc577a4SJonathan Peyton #if OMPT_SUPPORT 3273*3041982dSJonathan Peyton __kmp_task_init_ompt(taskdata, thread->th.th_info.ds.ds_gtid, 3274*3041982dSJonathan Peyton (void *)task->routine); 32757cc577a4SJonathan Peyton #endif 32767cc577a4SJonathan Peyton return task; 32777cc577a4SJonathan Peyton } 32787cc577a4SJonathan Peyton 32797cc577a4SJonathan Peyton // Routine optionally generated by th ecompiler for setting the lastprivate flag 32807cc577a4SJonathan Peyton // and calling needed constructors for private/firstprivate objects 32817cc577a4SJonathan Peyton // (used to form taskloop tasks from pattern task) 32827cc577a4SJonathan Peyton typedef void (*p_task_dup_t)(kmp_task_t *, kmp_task_t *, kmp_int32); 32837cc577a4SJonathan Peyton 32847cc577a4SJonathan Peyton // __kmp_taskloop_linear: Start tasks of the taskloop linearly 32857cc577a4SJonathan Peyton // 32867cc577a4SJonathan Peyton // loc Source location information 32877cc577a4SJonathan Peyton // gtid Global thread ID 32887cc577a4SJonathan Peyton // task Task with whole loop iteration range 32897cc577a4SJonathan Peyton // lb Pointer to loop lower bound 32907cc577a4SJonathan Peyton // ub Pointer to loop upper bound 32917cc577a4SJonathan Peyton // st Loop stride 32927cc577a4SJonathan Peyton // sched Schedule specified 0/1/2 for none/grainsize/num_tasks 32937cc577a4SJonathan Peyton // grainsize Schedule value if specified 32947cc577a4SJonathan Peyton // task_dup Tasks duplication routine 3295*3041982dSJonathan Peyton void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task, 32967cc577a4SJonathan Peyton kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, 3297*3041982dSJonathan Peyton int sched, kmp_uint64 grainsize, void *task_dup) { 32987cc577a4SJonathan Peyton KMP_COUNT_BLOCK(OMP_TASKLOOP); 32997cc577a4SJonathan Peyton KMP_TIME_PARTITIONED_BLOCK(OMP_taskloop_scheduling); 33007cc577a4SJonathan Peyton p_task_dup_t ptask_dup = (p_task_dup_t)task_dup; 33017cc577a4SJonathan Peyton kmp_uint64 tc; 33027cc577a4SJonathan Peyton kmp_uint64 lower = *lb; // compiler provides global bounds here 33037cc577a4SJonathan Peyton kmp_uint64 upper = *ub; 33047cc577a4SJonathan Peyton kmp_uint64 i, num_tasks = 0, extras = 0; 33057cc577a4SJonathan Peyton kmp_info_t *thread = __kmp_threads[gtid]; 33067cc577a4SJonathan Peyton kmp_taskdata_t *current_task = thread->th.th_current_task; 33077cc577a4SJonathan Peyton kmp_task_t *next_task; 33087cc577a4SJonathan Peyton kmp_int32 lastpriv = 0; 3309*3041982dSJonathan Peyton size_t lower_offset = 3310*3041982dSJonathan Peyton (char *)lb - (char *)task; // remember offset of lb in the task structure 3311*3041982dSJonathan Peyton size_t upper_offset = 3312*3041982dSJonathan Peyton (char *)ub - (char *)task; // remember offset of ub in the task structure 33137cc577a4SJonathan Peyton 33147cc577a4SJonathan Peyton // compute trip count 33157cc577a4SJonathan Peyton if (st == 1) { // most common case 33167cc577a4SJonathan Peyton tc = upper - lower + 1; 33177cc577a4SJonathan Peyton } else if (st < 0) { 33187cc577a4SJonathan Peyton tc = (lower - upper) / (-st) + 1; 33197cc577a4SJonathan Peyton } else { // st > 0 33207cc577a4SJonathan Peyton tc = (upper - lower) / st + 1; 33217cc577a4SJonathan Peyton } 33227cc577a4SJonathan Peyton if (tc == 0) { 33237cc577a4SJonathan Peyton KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d zero-trip loop\n", gtid)); 33247cc577a4SJonathan Peyton // free the pattern task and exit 33257cc577a4SJonathan Peyton __kmp_task_start(gtid, task, current_task); 33267cc577a4SJonathan Peyton // do not execute anything for zero-trip loop 33277cc577a4SJonathan Peyton __kmp_task_finish(gtid, task, current_task); 33287cc577a4SJonathan Peyton return; 33297cc577a4SJonathan Peyton } 33307cc577a4SJonathan Peyton 33317cc577a4SJonathan Peyton // compute num_tasks/grainsize based on the input provided 33327cc577a4SJonathan Peyton switch (sched) { 33337cc577a4SJonathan Peyton case 0: // no schedule clause specified, we can choose the default 33347cc577a4SJonathan Peyton // let's try to schedule (team_size*10) tasks 33357cc577a4SJonathan Peyton grainsize = thread->th.th_team_nproc * 10; 33367cc577a4SJonathan Peyton case 2: // num_tasks provided 33377cc577a4SJonathan Peyton if (grainsize > tc) { 33387cc577a4SJonathan Peyton num_tasks = tc; // too big num_tasks requested, adjust values 33397cc577a4SJonathan Peyton grainsize = 1; 33407cc577a4SJonathan Peyton extras = 0; 33417cc577a4SJonathan Peyton } else { 33427cc577a4SJonathan Peyton num_tasks = grainsize; 33437cc577a4SJonathan Peyton grainsize = tc / num_tasks; 33447cc577a4SJonathan Peyton extras = tc % num_tasks; 33457cc577a4SJonathan Peyton } 33467cc577a4SJonathan Peyton break; 33477cc577a4SJonathan Peyton case 1: // grainsize provided 33487cc577a4SJonathan Peyton if (grainsize > tc) { 33497cc577a4SJonathan Peyton num_tasks = 1; // too big grainsize requested, adjust values 33507cc577a4SJonathan Peyton grainsize = tc; 33517cc577a4SJonathan Peyton extras = 0; 33527cc577a4SJonathan Peyton } else { 33537cc577a4SJonathan Peyton num_tasks = tc / grainsize; 3354*3041982dSJonathan Peyton grainsize = 3355*3041982dSJonathan Peyton tc / 3356*3041982dSJonathan Peyton num_tasks; // adjust grainsize for balanced distribution of iterations 33577cc577a4SJonathan Peyton extras = tc % num_tasks; 33587cc577a4SJonathan Peyton } 33597cc577a4SJonathan Peyton break; 33607cc577a4SJonathan Peyton default: 33617cc577a4SJonathan Peyton KMP_ASSERT2(0, "unknown scheduling of taskloop"); 33627cc577a4SJonathan Peyton } 33637cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras); 33647cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(num_tasks > extras); 33657cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(num_tasks > 0); 3366*3041982dSJonathan Peyton KA_TRACE(20, ("__kmpc_taskloop: T#%d will launch: num_tasks %lld, grainsize " 3367*3041982dSJonathan Peyton "%lld, extras %lld\n", 33687cc577a4SJonathan Peyton gtid, num_tasks, grainsize, extras)); 33697cc577a4SJonathan Peyton 33707cc577a4SJonathan Peyton // Main loop, launch num_tasks tasks, assign grainsize iterations each task 33717cc577a4SJonathan Peyton for (i = 0; i < num_tasks; ++i) { 33727cc577a4SJonathan Peyton kmp_uint64 chunk_minus_1; 33737cc577a4SJonathan Peyton if (extras == 0) { 33747cc577a4SJonathan Peyton chunk_minus_1 = grainsize - 1; 33757cc577a4SJonathan Peyton } else { 33767cc577a4SJonathan Peyton chunk_minus_1 = grainsize; 33777cc577a4SJonathan Peyton --extras; // first extras iterations get bigger chunk (grainsize+1) 33787cc577a4SJonathan Peyton } 33797cc577a4SJonathan Peyton upper = lower + st * chunk_minus_1; 33807cc577a4SJonathan Peyton if (i == num_tasks - 1) { 33817cc577a4SJonathan Peyton // schedule the last task, set lastprivate flag 33827cc577a4SJonathan Peyton lastpriv = 1; 33837cc577a4SJonathan Peyton #if KMP_DEBUG 33847cc577a4SJonathan Peyton if (st == 1) 33857cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(upper == *ub); 33867cc577a4SJonathan Peyton else if (st > 0) 33877cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(upper + st > *ub); 33887cc577a4SJonathan Peyton else 33897cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(upper + st < *ub); 33907cc577a4SJonathan Peyton #endif 33917cc577a4SJonathan Peyton } 33927cc577a4SJonathan Peyton next_task = __kmp_task_dup_alloc(thread, task); // allocate new task 3393*3041982dSJonathan Peyton *(kmp_uint64 *)((char *)next_task + lower_offset) = 3394*3041982dSJonathan Peyton lower; // adjust task-specific bounds 33957cc577a4SJonathan Peyton *(kmp_uint64 *)((char *)next_task + upper_offset) = upper; 33967cc577a4SJonathan Peyton if (ptask_dup != NULL) 3397*3041982dSJonathan Peyton ptask_dup(next_task, task, 3398*3041982dSJonathan Peyton lastpriv); // set lastprivate flag, construct fistprivates, etc. 3399*3041982dSJonathan Peyton KA_TRACE(20, ("__kmpc_taskloop: T#%d schedule task %p: lower %lld, upper " 3400*3041982dSJonathan Peyton "%lld (offsets %p %p)\n", 34017cc577a4SJonathan Peyton gtid, next_task, lower, upper, lower_offset, upper_offset)); 34027cc577a4SJonathan Peyton __kmp_omp_task(gtid, next_task, true); // schedule new task 34037cc577a4SJonathan Peyton lower = upper + st; // adjust lower bound for the next iteration 34047cc577a4SJonathan Peyton } 34057cc577a4SJonathan Peyton // free the pattern task and exit 34067cc577a4SJonathan Peyton __kmp_task_start(gtid, task, current_task); 34077cc577a4SJonathan Peyton // do not execute the pattern task, just do bookkeeping 34087cc577a4SJonathan Peyton __kmp_task_finish(gtid, task, current_task); 34097cc577a4SJonathan Peyton } 34107cc577a4SJonathan Peyton 34117cc577a4SJonathan Peyton /*! 34127cc577a4SJonathan Peyton @ingroup TASKING 34137cc577a4SJonathan Peyton @param loc Source location information 34147cc577a4SJonathan Peyton @param gtid Global thread ID 34157cc577a4SJonathan Peyton @param task Task structure 34167cc577a4SJonathan Peyton @param if_val Value of the if clause 34177cc577a4SJonathan Peyton @param lb Pointer to loop lower bound 34187cc577a4SJonathan Peyton @param ub Pointer to loop upper bound 34197cc577a4SJonathan Peyton @param st Loop stride 34207cc577a4SJonathan Peyton @param nogroup Flag, 1 if nogroup clause specified, 0 otherwise 34217cc577a4SJonathan Peyton @param sched Schedule specified 0/1/2 for none/grainsize/num_tasks 34227cc577a4SJonathan Peyton @param grainsize Schedule value if specified 34237cc577a4SJonathan Peyton @param task_dup Tasks duplication routine 34247cc577a4SJonathan Peyton 34257cc577a4SJonathan Peyton Execute the taskloop construct. 34267cc577a4SJonathan Peyton */ 3427*3041982dSJonathan Peyton void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, 3428*3041982dSJonathan Peyton kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, 3429*3041982dSJonathan Peyton int sched, kmp_uint64 grainsize, void *task_dup) { 34307cc577a4SJonathan Peyton kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task); 34317cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(task != NULL); 34327cc577a4SJonathan Peyton 3433*3041982dSJonathan Peyton KA_TRACE(10, ("__kmpc_taskloop(enter): T#%d, pattern task %p, lb %lld ub " 3434*3041982dSJonathan Peyton "%lld st %lld, grain %llu(%d)\n", 34357cc577a4SJonathan Peyton gtid, taskdata, *lb, *ub, st, grainsize, sched)); 34367cc577a4SJonathan Peyton 34377cc577a4SJonathan Peyton // check if clause value first 34387cc577a4SJonathan Peyton if (if_val == 0) { // if(0) specified, mark task as serial 34397cc577a4SJonathan Peyton taskdata->td_flags.task_serial = 1; 34407cc577a4SJonathan Peyton taskdata->td_flags.tiedness = TASK_TIED; // AC: serial task cannot be untied 34417cc577a4SJonathan Peyton } 34427cc577a4SJonathan Peyton if (nogroup == 0) { 34437cc577a4SJonathan Peyton __kmpc_taskgroup(loc, gtid); 34447cc577a4SJonathan Peyton } 34457cc577a4SJonathan Peyton 34467cc577a4SJonathan Peyton if (1 /* AC: use some heuristic here to choose task scheduling method */) { 3447*3041982dSJonathan Peyton __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, sched, grainsize, 3448*3041982dSJonathan Peyton task_dup); 34497cc577a4SJonathan Peyton } 34507cc577a4SJonathan Peyton 34517cc577a4SJonathan Peyton if (nogroup == 0) { 34527cc577a4SJonathan Peyton __kmpc_end_taskgroup(loc, gtid); 34537cc577a4SJonathan Peyton } 34547cc577a4SJonathan Peyton KA_TRACE(10, ("__kmpc_taskloop(exit): T#%d\n", gtid)); 34557cc577a4SJonathan Peyton } 34567cc577a4SJonathan Peyton 34577cc577a4SJonathan Peyton #endif 3458