/* __ompc_remove_task_from_pool_simple_2level: * Takes a task from the task pool. First tries to get a task from the current * thread's task queue. If that doesn't work, then it will look for work in * the community queue. If that's also empty, then it will attempt to steal a * task from another task queue (so long as there are no other tasks, not in a * barrier, that are tied to the current thread). * * Note: The restriction on stealing is overly conservative. Even if there are * tasks tied to the current thread and not in a barrier ([*]), we should be * able to steal any untied tasks, or tied tasks that descend from all tasks * in [*]. But this implementation does not separate untied tasks from tied * tasks, and also does not track descendants in the task pool. */ omp_task_t *__ompc_remove_task_from_pool_simple_2level(omp_task_pool_t *pool) { omp_task_t *task, *current_task; omp_team_t *team; omp_v_thread_t *current_thread; omp_queue_t *my_queue; omp_queue_t *victim_queue; omp_task_queue_level_t *per_thread, *community; int myid = __omp_myid; Is_True(pool != NULL, ("__ompc_remove_task_from_pool: task pool is uninitialized")); current_task = __omp_current_task; current_thread = __omp_current_v_thread; per_thread = &pool->level[PER_THREAD]; community = &pool->level[COMMUNITY]; task = __ompc_task_queue_get(&per_thread->task_queue[myid]); /* if no task in local queue, we will look in another queue so long as there * are no suspended tasks tied to thread and the current task is either in a * barrier or its not tied */ if (task == NULL && !current_thread->num_suspended_tied_tasks && (__ompc_task_state_is_in_barrier(current_task) || !__ompc_task_is_tied(current_task))) { if (__omp_task_chunk_size > 1) { /* this will steal a chunk of tasks, instead of just 1, from the * community * queue */ task = __ompc_task_queue_steal_chunk(community->task_queue, &per_thread->task_queue[myid], __omp_task_chunk_size); } else { task = __ompc_task_queue_steal(community->task_queue); } if (task == NULL) { int first_victim, victim = 0; int team_size = pool->team_size; victim = (rand_r(&__omp_seed) % (team_size - 1)); if (victim >= myid) victim++; /* cycle through to find a queue with work to steal */ first_victim = victim; while (1) { while (__ompc_queue_is_empty(&per_thread->task_queue[victim])) { victim++; if (victim == myid) victim++; if (victim == team_size) victim = 0; if (victim == first_victim) return NULL; } task = __ompc_task_queue_steal(&per_thread->task_queue[victim]); if ( task != NULL ) return task; } } } return task; }
/* __ompc_remove_task_from_pool_default: *Takes task from the task pool. * * Takes a task from the task pool. First tries to get a task from the current * thread's task queue. If that doesn't work, then it will attempt to steal a * task from another task queue (so long as there are no other tasks, not in a * barrier, that are tied to the current thread). */ omp_task_t *__ompc_remove_task_from_pool_default(omp_task_pool_t *pool) { omp_task_t *task, *current_task; omp_team_t *team; omp_v_thread_t *current_thread; omp_queue_t *my_queue; omp_queue_t *victim_queue; omp_task_queue_level_t *per_thread; int myid = __omp_myid; Is_True(pool != NULL, ("__ompc_remove_task_from_pool: task pool is uninitialized")); current_task = __omp_current_task; current_thread = __omp_current_v_thread; per_thread = &pool->level[PER_THREAD]; /* We get only from the tail for tied tasks. This is necessary to guarantee * that tied tasks are only scheduled if they are descendants of every * suspended tied task not at a barrier */ task = __ompc_queue_get_tail(&per_thread->task_queue[TIED_IDX(myid)]); /* for untied tasks, we can get from the head or tail, depending on what * O64_OMP_TASK_QUEUE is set to */ if (task == NULL) task = __ompc_task_queue_get(&per_thread->task_queue[UNTIED_IDX(myid)]); /* check if there are any untied tasks available in the other task queues */ if (task == NULL) { int first_victim, victim = 0; int team_size = pool->team_size; if (team_size < 2) return NULL; victim = (rand_r(&__omp_seed) % (team_size - 1)); if (victim >= myid) victim++; /* cycle through to find a queue with work to steal */ first_victim = victim; while (1) { while (__ompc_queue_lockless_is_empty( &per_thread->task_queue[UNTIED_IDX(victim)])) { victim++; if (victim == myid) victim++; if (victim == team_size) victim = 0; if (victim == first_victim) goto CHECK_TIED_TASK_QUEUES; } task = __ompc_task_queue_steal( &per_thread->task_queue[UNTIED_IDX(victim)]); if ( task != NULL ) { /* if (!__ompc_task_state_is_unscheduled(task)) { // Is_True(0, ("state of task from queue was not unscheduled")); printf("\n... (1) skipping over a task with state %s; queue size is %d \n", __ompc_task_get_state_string(task), __ompc_queue_num_used_slots(&per_thread->task_queue[UNTIED_IDX(victim)])); task = NULL; } */ return task; } } } /* if no task in local queue and no available untied tasks, we will look in * another queue so long as there are no suspended tasks tied to thread and * the current task is either in a barrier or its not tied */ CHECK_TIED_TASK_QUEUES: if (task == NULL && !current_thread->num_suspended_tied_tasks && (__ompc_task_state_is_in_barrier(current_task) || !__ompc_task_is_tied(current_task))) { int first_victim, victim = 0; int team_size = pool->team_size; victim = (rand_r(&__omp_seed) % (team_size - 1)); if (victim >= myid) victim++; /* cycle through to find a queue with work to steal */ first_victim = victim; while (1) { while (__ompc_queue_is_empty( &per_thread->task_queue[TIED_IDX(victim)])) { victim++; if (victim == myid) victim++; if (victim == team_size) victim = 0; if (victim == first_victim) return NULL; } /* Always steal from the head for tied tasks. Note also that by not * using the task_queue API, CFIFO implementation will not be used */ task = __ompc_queue_steal_head( &per_thread->task_queue[TIED_IDX(victim)]); if ( task != NULL ) { /* if (!__ompc_task_state_is_unscheduled(task)) { // Is_True(0, ("state of task from queue was not unscheduled")); printf("\n... (2) skipping over a task with state %s; queue size is %d \n", __ompc_task_get_state_string(task), __ompc_queue_num_used_slots(&per_thread->task_queue[TIED_IDX(victim)])); task = NULL; } */ return task; } } } /* if ( task != NULL ) { if (!__ompc_task_state_is_unscheduled(task)) { // Is_True(0, ("state of task from queue was not unscheduled")); printf("\n... (3) skipping over a task with state %s; queue size is %d \n", __ompc_task_get_state_string(task), __ompc_queue_num_used_slots(&per_thread->task_queue[UNTIED_IDX(myid)])); task = NULL; } } */ return task; }
/* __ompc_remove_task_from_pool_simple: * Takes a task from the task pool. First tries to get a task from the current * thread's task queue. If that doesn't work, then it will attempt to steal a * task from another task queue (so long as there are no other tasks, not in a * barrier, that are tied to the current thread). * * Note: The restriction on stealing is overly conservative. Even if there are * tasks tied to the current thread and not in a barrier ([*]), we should be * able to steal any untied tasks, or tied tasks that descend from all tasks * in [*]. But this implementation does not separate untied tasks from tied * tasks, and also does not track descendants in the task pool. */ omp_task_t *__ompc_remove_task_from_pool_simple(omp_task_pool_t *pool) { omp_task_t *task, *current_task; omp_team_t *team; omp_v_thread_t *current_thread; omp_queue_t *my_queue; omp_queue_t *victim_queue; omp_task_queue_level_t *per_thread; int myid = __omp_myid; int team_size; Is_True(pool != NULL, ("__ompc_remove_task_from_pool: task pool is uninitialized")); current_task = __omp_current_task; current_thread = __omp_current_v_thread; per_thread = &pool->level[PER_THREAD]; task = __ompc_task_queue_get(&per_thread->task_queue[myid]); /* if no task in local queue, we will look in another queue so long as there * are no suspended tasks tied to thread and the current task is either in a * barrier or its not tied */ team_size = pool->team_size; if (task == NULL && (team_size > 1) && !current_thread->num_suspended_tied_tasks && (__ompc_task_state_is_in_barrier(current_task) || !__ompc_task_is_tied(current_task))) { int first_victim, victim = 0, go_right; go_right = (rand_r(&__omp_seed) % (2)); victim = (rand_r(&__omp_seed) % (team_size - 1)); if (victim >= myid) victim++; first_victim = victim; if (go_right) { /* cycle through to find a queue with work to steal */ while (1) { while (__ompc_queue_is_empty(&per_thread->task_queue[victim])) { victim++; if (victim == myid) victim++; if (victim == team_size) victim = 0; if (victim == first_victim) return NULL; } task = __ompc_task_queue_steal(&per_thread->task_queue[victim]); if ( task != NULL ) return task; } } else { /* cycle through to find a queue with work to steal */ while (1) { while (__ompc_queue_is_empty(&per_thread->task_queue[victim])) { victim--; if (victim == myid) victim--; if (victim == -1) victim = team_size-1; if (victim == first_victim) return NULL; } task = __ompc_task_queue_steal(&per_thread->task_queue[victim]); if ( task != NULL ) return task; } } } return task; }