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