static void sched_run(ABT_sched sched) { uint32_t work_count = 0; sched_data *p_data; int num_pools; ABT_pool *p_pools; ABT_unit unit; int target; unsigned seed = time(NULL); CNT_DECL(run_cnt); ABTI_xstream *p_xstream = ABTI_local_get_xstream(); ABTI_sched *p_sched = ABTI_sched_get_ptr(sched); ABT_sched_get_data(sched, (void **)&p_data); ABT_sched_get_num_pools(sched, &num_pools); p_pools = (ABT_pool *)ABTU_malloc(num_pools * sizeof(ABT_pool)); ABT_sched_get_pools(sched, num_pools, 0, p_pools); while (1) { CNT_INIT(run_cnt, 0); /* Execute one work unit from the scheduler's pool */ ABT_pool pool = p_pools[0]; ABTI_pool *p_pool = ABTI_pool_get_ptr(pool); size_t size = ABTI_pool_get_size(p_pool); if (size > 0) { unit = ABTI_pool_pop(p_pool); if (unit != ABT_UNIT_NULL) { ABTI_xstream_run_unit(p_xstream, unit, p_pool); CNT_INC(run_cnt); } } else if (num_pools > 1) { /* Steal a work unit from other pools */ target = (num_pools == 2) ? 1 : (rand_r(&seed) % (num_pools-1) + 1); pool = p_pools[target]; p_pool = ABTI_pool_get_ptr(pool); size = ABTI_pool_get_size(p_pool); if (size > 0) { unit = ABTI_pool_pop(p_pool); LOG_EVENT_POOL_POP(p_pool, unit); if (unit != ABT_UNIT_NULL) { ABT_unit_set_associated_pool(unit, pool); ABTI_xstream_run_unit(p_xstream, unit, p_pool); CNT_INC(run_cnt); } } } if (++work_count >= p_data->event_freq) { ABT_bool stop = ABTI_sched_has_to_stop(p_sched, p_xstream); if (stop == ABT_TRUE) break; work_count = 0; ABTI_xstream_check_events(p_xstream, sched); SCHED_SLEEP(run_cnt, p_data->sleep_time); } } ABTU_free(p_pools); }
int ABTI_sched_free(ABTI_sched *p_sched) { int abt_errno = ABT_SUCCESS; int p; /* If sched is currently used, free is not allowed. */ if (p_sched->used != ABTI_SCHED_NOT_USED) { abt_errno = ABT_ERR_SCHED; goto fn_fail; } /* If sched is a default provided one, it should free its pool here. * Otherwise, freeing the pool is the user's reponsibility. */ for (p = 0; p < p_sched->num_pools; p++) { ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[p]); int32_t num_scheds = ABTI_pool_release(p_pool); if (p_pool->automatic == ABT_TRUE && num_scheds == 0) { abt_errno = ABT_pool_free(p_sched->pools+p); ABTI_CHECK_ERROR(abt_errno); } } ABTU_free(p_sched->pools); /* Free the associated work unit */ if (p_sched->type == ABT_SCHED_TYPE_ULT) { if (p_sched->p_thread) { if (p_sched->p_thread->type == ABTI_THREAD_TYPE_MAIN_SCHED) { ABTI_thread_free_main_sched(p_sched->p_thread); } else { ABTI_thread_free(p_sched->p_thread); } } } else if (p_sched->type == ABT_SCHED_TYPE_TASK) { if (p_sched->p_task) { ABTI_task_free(p_sched->p_task); } } LOG_EVENT("[S%" PRIu64 "] freed\n", p_sched->id); p_sched->free(ABTI_sched_get_handle(p_sched)); p_sched->data = NULL; ABTU_free(p_sched); fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }
/* Compared to \c ABTI_sched_get_total_size, ABTI_sched_get_effective_size does * not count the number of blocked ULTs if a pool has more than one consumer or * the caller ES is not the latest consumer. This is necessary when the ES * associated with the target scheduler has to be joined and the pool is shared * between different schedulers associated with different ESs. */ size_t ABTI_sched_get_effective_size(ABTI_sched *p_sched) { size_t pool_size = 0; int p; #ifndef ABT_CONFIG_DISABLE_POOL_CONSUMER_CHECK ABTI_xstream *p_xstream = ABTI_local_get_xstream(); #endif for (p = 0; p < p_sched->num_pools; p++) { ABT_pool pool = p_sched->pools[p]; ABTI_pool *p_pool = ABTI_pool_get_ptr(pool); pool_size += p_pool->p_get_size(pool); pool_size += p_pool->num_migrations; switch (p_pool->access) { case ABT_POOL_ACCESS_PRIV: pool_size += p_pool->num_blocked; break; case ABT_POOL_ACCESS_SPSC: case ABT_POOL_ACCESS_MPSC: case ABT_POOL_ACCESS_SPMC: case ABT_POOL_ACCESS_MPMC: #ifdef ABT_CONFIG_DISABLE_POOL_CONSUMER_CHECK if (p_pool->num_scheds == 1) { pool_size += p_pool->num_blocked; } #else if (p_pool->num_scheds == 1 && p_pool->consumer == p_xstream) { pool_size += p_pool->num_blocked; } #endif break; default: break; } } return pool_size; }
void ABTI_sched_print(ABTI_sched *p_sched, FILE *p_os, int indent, ABT_bool print_sub) { char *prefix = ABTU_get_indent_str(indent); if (p_sched == NULL) { fprintf(p_os, "%s== NULL SCHED ==\n", prefix); goto fn_exit; } ABTI_sched_kind kind; char *kind_str, *type, *state, *used; char *pools_str; int i; size_t size, pos; kind = p_sched->kind; if (kind == ABTI_sched_get_kind(ABTI_sched_get_basic_def())) { kind_str = "BASIC"; } else if (kind == ABTI_sched_get_kind(ABTI_sched_get_prio_def())) { kind_str = "PRIO"; } else { kind_str = "USER"; } switch (p_sched->type) { case ABT_SCHED_TYPE_ULT: type = "ULT"; break; case ABT_SCHED_TYPE_TASK: type = "TASKLET"; break; default: type = "UNKNOWN"; break; } switch (p_sched->state) { case ABT_SCHED_STATE_READY: state = "READY"; break; case ABT_SCHED_STATE_RUNNING: state = "RUNNING"; break; case ABT_SCHED_STATE_STOPPED: state = "STOPPED"; break; case ABT_SCHED_STATE_TERMINATED: state = "TERMINATED"; break; default: state = "UNKNOWN"; break; } switch (p_sched->used) { case ABTI_SCHED_NOT_USED: used = "NOT_USED"; break; case ABTI_SCHED_MAIN: used = "MAIN"; break; case ABTI_SCHED_IN_POOL: used = "IN_POOL"; break; default: type = "UNKNOWN"; break; } size = sizeof(char) * (p_sched->num_pools * 20 + 4); pools_str = (char *)ABTU_calloc(size, 1); pools_str[0] = '['; pools_str[1] = ' '; pos = 2; for (i = 0; i < p_sched->num_pools; i++) { ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[i]); sprintf(&pools_str[pos], "%p ", p_pool); pos = strlen(pools_str); } pools_str[pos] = ']'; fprintf(p_os, "%s== SCHED (%p) ==\n" #ifdef ABT_CONFIG_USE_DEBUG_LOG "%sid : %" PRIu64 "\n" #endif "%skind : %" PRIu64 " (%s)\n" "%stype : %s\n" "%sstate : %s\n" "%sused : %s\n" "%sautomatic: %s\n" "%srequest : 0x%x\n" "%snum_pools: %d\n" "%spools : %s\n" "%ssize : %zu\n" "%stot_size : %zu\n" "%sdata : %p\n", prefix, p_sched, #ifdef ABT_CONFIG_USE_DEBUG_LOG prefix, p_sched->id, #endif prefix, p_sched->kind, kind_str, prefix, type, prefix, state, prefix, used, prefix, (p_sched->automatic == ABT_TRUE) ? "TRUE" : "FALSE", prefix, p_sched->request, prefix, p_sched->num_pools, prefix, pools_str, prefix, ABTI_sched_get_size(p_sched), prefix, ABTI_sched_get_total_size(p_sched), prefix, p_sched->data ); ABTU_free(pools_str); if (print_sub == ABT_TRUE) { for (i = 0; i < p_sched->num_pools; i++) { ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[i]); ABTI_pool_print(p_pool, p_os, indent + 2); } } fn_exit: fflush(p_os); ABTU_free(prefix); }
/** * @ingroup SCHED * @brief Create a new user-defined scheduler and return its handle through * newsched. * * The pools used by the new scheduler are provided by \c pools. The contents * of this array is copied, so it can be freed. If a pool in the array is * ABT_POOL_NULL, the corresponding pool is automatically created. * The config must have been created by ABT_sched_config_create, and will be * used as argument in the initialization. If no specific configuration is * required, the parameter will be ABT_CONFIG_NULL. * * @param[in] def definition required for scheduler creation * @param[in] num_pools number of pools associated with this scheduler * @param[in] pools pools associated with this scheduler * @param[in] config specific config used during the scheduler creation * @param[out] newsched handle to a new scheduler * @return Error code * @retval ABT_SUCCESS on success */ int ABT_sched_create(ABT_sched_def *def, int num_pools, ABT_pool *pools, ABT_sched_config config, ABT_sched *newsched) { int abt_errno = ABT_SUCCESS; ABTI_sched *p_sched; int p; ABTI_CHECK_TRUE(newsched != NULL, ABT_ERR_SCHED); p_sched = (ABTI_sched *)ABTU_malloc(sizeof(ABTI_sched)); /* Copy of the contents of pools */ ABT_pool *pool_list; pool_list = (ABT_pool *)ABTU_malloc(num_pools*sizeof(ABT_pool)); for (p = 0; p < num_pools; p++) { if (pools[p] == ABT_POOL_NULL) { abt_errno = ABT_pool_create_basic(ABT_POOL_FIFO, ABT_POOL_ACCESS_MPSC, ABT_TRUE, &pool_list[p]); ABTI_CHECK_ERROR(abt_errno); } else { pool_list[p] = pools[p]; } } /* Check if the pools are available */ for (p = 0; p < num_pools; p++) { ABTI_pool_retain(ABTI_pool_get_ptr(pool_list[p])); } p_sched->used = ABTI_SCHED_NOT_USED; p_sched->automatic = ABT_FALSE; p_sched->kind = ABTI_sched_get_kind(def); p_sched->state = ABT_SCHED_STATE_READY; p_sched->request = 0; p_sched->pools = pool_list; p_sched->num_pools = num_pools; p_sched->type = def->type; p_sched->p_thread = NULL; p_sched->p_task = NULL; p_sched->p_ctx = NULL; p_sched->init = def->init; p_sched->run = def->run; p_sched->free = def->free; p_sched->get_migr_pool = def->get_migr_pool; #ifdef ABT_CONFIG_USE_DEBUG_LOG p_sched->id = ABTI_sched_get_new_id(); #endif LOG_EVENT("[S%" PRIu64 "] created\n", p_sched->id); /* Return value */ *newsched = ABTI_sched_get_handle(p_sched); /* Specific initialization */ p_sched->init(*newsched, config); fn_exit: return abt_errno; fn_fail: *newsched = ABT_SCHED_NULL; HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); goto fn_exit; }