Changeset View
Changeset View
Standalone View
Standalone View
runtime/src/kmp_tasking.c
Show First 20 Lines • Show All 1,776 Lines • ▼ Show 20 Lines | if ( (TCR_4(victim_td -> td.td_deque_ntasks) == 0) || | ||||
"ntasks=%d head=%u tail=%u\n", | "ntasks=%d head=%u tail=%u\n", | ||||
gtid, __kmp_gtid_from_thread( victim ), task_team, victim_td->td.td_deque_ntasks, | gtid, __kmp_gtid_from_thread( victim ), task_team, victim_td->td.td_deque_ntasks, | ||||
victim_td->td.td_deque_head, victim_td->td.td_deque_tail) ); | victim_td->td.td_deque_head, victim_td->td.td_deque_tail) ); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
KMP_DEBUG_ASSERT( victim_td -> td.td_deque != NULL ); | KMP_DEBUG_ASSERT( victim_td -> td.td_deque != NULL ); | ||||
if ( !is_constrained ) { | |||||
taskdata = victim_td -> td.td_deque[ victim_td -> td.td_deque_head ]; | taskdata = victim_td->td.td_deque[victim_td->td.td_deque_head]; | ||||
KMP_ASSERT(taskdata); | if ( is_constrained ) { | ||||
// Bump head pointer and Wrap. | |||||
victim_td -> td.td_deque_head = ( victim_td -> td.td_deque_head + 1 ) & TASK_DEQUE_MASK(victim_td->td); | |||||
} else { | |||||
// While we have postponed tasks let's steal from tail of the deque (smaller tasks) | |||||
kmp_int32 tail = ( victim_td -> td.td_deque_tail - 1 ) & TASK_DEQUE_MASK(victim_td->td); // Wrap index. | |||||
taskdata = victim_td -> td.td_deque[ tail ]; | |||||
KMP_ASSERT(taskdata); | |||||
// we need to check if the candidate obeys task scheduling constraint: | // we need to check if the candidate obeys task scheduling constraint: | ||||
// only child of current task can be scheduled | // only descendant of current task can be scheduled | ||||
kmp_taskdata_t * current = __kmp_threads[ gtid ]->th.th_current_task; | kmp_taskdata_t * current = __kmp_threads[ gtid ]->th.th_current_task; | ||||
kmp_int32 level = current->td_level; | kmp_int32 level = current->td_level; | ||||
kmp_taskdata_t * parent = taskdata->td_parent; | kmp_taskdata_t * parent = taskdata->td_parent; | ||||
while ( parent != current && parent->td_level > level ) { | while ( parent != current && parent->td_level > level ) { | ||||
parent = parent->td_parent; // check generation up to the level of the current task | parent = parent->td_parent; // check generation up to the level of the current task | ||||
KMP_DEBUG_ASSERT(parent != NULL); | KMP_DEBUG_ASSERT(parent != NULL); | ||||
} | } | ||||
if ( parent != current && (taskdata->td_flags.tiedness == TASK_TIED) ) { // untied is always allowed to be stolen | if ( parent != current && (taskdata->td_flags.tiedness == TASK_TIED) ) { // untied is always allowed to be stolen | ||||
// If the tail task is not a child, then no other childs can appear in the deque (?). | // If the tail task is not a child, then no other childs can appear in the deque (?). | ||||
Hahnfeld: Does this still hold then? I think currently a thread will add tasks to the tail so we have… | |||||
__kmp_release_bootstrap_lock( & victim_td -> td.td_deque_lock ); | __kmp_release_bootstrap_lock( & victim_td -> td.td_deque_lock ); | ||||
KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: task_team=%p " | KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: task_team=%p " | ||||
"ntasks=%d head=%u tail=%u\n", | "ntasks=%d head=%u tail=%u\n", | ||||
gtid, __kmp_gtid_from_thread( threads_data[victim_tid].td.td_thr ), | gtid, __kmp_gtid_from_thread( threads_data[victim_tid].td.td_thr ), | ||||
task_team, victim_td->td.td_deque_ntasks, | task_team, victim_td->td.td_deque_ntasks, | ||||
victim_td->td.td_deque_head, victim_td->td.td_deque_tail) ); | victim_td->td.td_deque_head, victim_td->td.td_deque_tail) ); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
victim_td -> td.td_deque_tail = tail; | |||||
} | } | ||||
// Bump head pointer and Wrap. | |||||
victim_td->td.td_deque_head = (victim_td->td.td_deque_head + 1) & TASK_DEQUE_MASK(victim_td->td); | |||||
if (*thread_finished) { | if (*thread_finished) { | ||||
// We need to un-mark this victim as a finished victim. This must be done before | // We need to un-mark this victim as a finished victim. This must be done before | ||||
// releasing the lock, or else other threads (starting with the master victim) | // releasing the lock, or else other threads (starting with the master victim) | ||||
// might be prematurely released from the barrier!!! | // might be prematurely released from the barrier!!! | ||||
kmp_uint32 count; | kmp_uint32 count; | ||||
count = KMP_TEST_THEN_INC32( (kmp_int32 *)unfinished_threads ); | count = KMP_TEST_THEN_INC32( (kmp_int32 *)unfinished_threads ); | ||||
▲ Show 20 Lines • Show All 1,325 Lines • Show Last 20 Lines |
Does this still hold then? I think currently a thread will add tasks to the tail so we have previously stolen the last generated task. However we are now going to take a task from the head.
If that is a problem, should we first try to steal from the head and afterwards check the tail if it's not a descendant task?