/** * @ingroup SCHED * @brief Create a predefined scheduler. * * \c ABT_sched_create_basic() creates a predefined scheduler and returns its * handle through \c 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 \c ABT_POOL_NULL, the corresponding pool is * automatically created. The pool array can be \c NULL. In this case, all * the pools will be created automatically. The config must have been created * by \c ABT_sched_config_create(), and will be used as argument in the * initialization. If no specific configuration is required, the parameter can * be \c ABT_CONFIG_NULL. * * NOTE: The new scheduler will be automatically freed when it is not used * anymore or its associated ES is terminated. Accordingly, the pools * associated with the new scheduler will be automatically freed if they are * exclusive to the scheduler and are not user-defined ones (i.e., created by * \c ABT_pool_create_basic() or implicitly created because \c pools is \c NULL * or a pool in the \c pools array is \c ABT_POOL_NULL). If the pools were * created using \c ABT_pool_create() by the user, they have to be freed * explicitly with \c ABT_pool_free(). * * @param[in] predef predefined scheduler * @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_basic(ABT_sched_predef predef, int num_pools, ABT_pool *pools, ABT_sched_config config, ABT_sched *newsched) { int abt_errno = ABT_SUCCESS; ABT_pool_access access; ABT_bool automatic; int p; /* We set the access to the default one */ access = ABT_POOL_ACCESS_MPSC; automatic = ABT_TRUE;; /* We read the config and set the configured parameters */ abt_errno = ABTI_sched_config_read_global(config, &access, &automatic); ABTI_CHECK_ERROR(abt_errno); /* A pool array is provided, predef has to be compatible */ if (pools != NULL) { /* 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, access, ABT_TRUE, &pool_list[p]); ABTI_CHECK_ERROR(abt_errno); } else { pool_list[p] = pools[p]; } } /* Creation of the scheduler */ switch (predef) { case ABT_SCHED_DEFAULT: case ABT_SCHED_BASIC: abt_errno = ABT_sched_create(ABTI_sched_get_basic_def(), num_pools, pool_list, ABT_SCHED_CONFIG_NULL, newsched); break; case ABT_SCHED_PRIO: abt_errno = ABT_sched_create(ABTI_sched_get_prio_def(), num_pools, pool_list, ABT_SCHED_CONFIG_NULL, newsched); break; case ABT_SCHED_RANDWS: abt_errno = ABT_sched_create(ABTI_sched_get_randws_def(), num_pools, pool_list, ABT_SCHED_CONFIG_NULL, newsched); break; default: abt_errno = ABT_ERR_INV_SCHED_PREDEF; break; } ABTI_CHECK_ERROR(abt_errno); ABTU_free(pool_list); } /* No pool array is provided, predef has to be compatible */ else { /* Set the number of pools */ switch (predef) { case ABT_SCHED_DEFAULT: case ABT_SCHED_BASIC: num_pools = 1; break; case ABT_SCHED_PRIO: num_pools = ABTI_SCHED_NUM_PRIO; break; case ABT_SCHED_RANDWS: num_pools = 1; break; default: abt_errno = ABT_ERR_INV_SCHED_PREDEF; ABTI_CHECK_ERROR(abt_errno); break; } /* Creation of the pools */ /* To avoid the malloc overhead, we use a stack array. */ ABT_pool pool_list[ABTI_SCHED_NUM_PRIO]; int p; for (p = 0; p < num_pools; p++) { abt_errno = ABT_pool_create_basic(ABT_POOL_FIFO, access, ABT_TRUE, pool_list+p); ABTI_CHECK_ERROR(abt_errno); } /* Creation of the scheduler */ switch (predef) { case ABT_SCHED_DEFAULT: case ABT_SCHED_BASIC: abt_errno = ABT_sched_create(ABTI_sched_get_basic_def(), num_pools, pool_list, config, newsched); break; case ABT_SCHED_PRIO: abt_errno = ABT_sched_create(ABTI_sched_get_prio_def(), num_pools, pool_list, config, newsched); break; case ABT_SCHED_RANDWS: abt_errno = ABT_sched_create(ABTI_sched_get_randws_def(), num_pools, pool_list, config, newsched); break; default: abt_errno = ABT_ERR_INV_SCHED_PREDEF; ABTI_CHECK_ERROR(abt_errno); break; } } ABTI_CHECK_ERROR(abt_errno); ABTI_sched *p_sched = ABTI_sched_get_ptr(*newsched); p_sched->automatic = automatic; fn_exit: return abt_errno; fn_fail: HANDLE_ERROR_FUNC_WITH_CODE(abt_errno); *newsched = ABT_SCHED_NULL; goto fn_exit; }
void rt1_launcher(void *arg) { int idx = (int)(intptr_t)arg; ABT_thread cur_thread; ABT_pool cur_pool; ABT_sched_config config; ABT_sched sched; size_t size; double t_start, t_end; ABT_sched_config_var cv_event_freq = { .idx = 0, .type = ABT_SCHED_CONFIG_INT }; ABT_sched_config_var cv_idx = { .idx = 1, .type = ABT_SCHED_CONFIG_INT }; ABT_sched_def sched_def = { .type = ABT_SCHED_TYPE_ULT, .init = sched_init, .run = sched_run, .free = sched_free, .get_migr_pool = NULL }; /* Create a scheduler */ ABT_sched_config_create(&config, cv_event_freq, 10, cv_idx, idx, ABT_sched_config_var_end); ABT_sched_create(&sched_def, 1, &rt1_data->pool, config, &sched); /* Push the scheduler to the current pool */ ABT_thread_self(&cur_thread); ABT_thread_get_last_pool(cur_thread, &cur_pool); ABT_pool_add_sched(cur_pool, sched); /* Free */ ABT_sched_config_free(&config); t_start = ABT_get_wtime(); while (1) { rt1_app(idx); ABT_pool_get_total_size(cur_pool, &size); if (size == 0) { ABT_sched_free(&sched); int rank; ABT_xstream_self_rank(&rank); printf("ES%d: finished\n", rank); ABT_mutex_lock(rt1_data->mutex); rt1_data->xstreams[rank] = ABT_XSTREAM_NULL; rt1_data->num_xstreams--; ABT_mutex_unlock(rt1_data->mutex); break; } t_end = ABT_get_wtime(); if ((t_end - t_start) > g_timeout) { ABT_sched_finish(sched); } } } static void rt1_app(int eid) { int i, num_comps; size_t size; ABT_thread cur_thread; ABT_pool cur_pool; ABT_thread_self(&cur_thread); ABT_thread_get_last_pool(cur_thread, &cur_pool); if (eid == 0) ABT_event_prof_start(); num_comps = rt1_data->num_comps; for (i = 0; i < num_comps * 2; i += 2) { ABT_thread_create(rt1_data->pool, rt1_app_compute, (void *)(intptr_t)(eid * num_comps * 2 + i), ABT_THREAD_ATTR_NULL, NULL); ABT_task_create(rt1_data->pool, rt1_app_compute, (void *)(intptr_t)(eid * num_comps * 2 + i + 1), NULL); } do { ABT_thread_yield(); /* If the size of cur_pool is zero, it means the stacked scheduler has * been terminated because of the shrinking event. */ ABT_pool_get_total_size(cur_pool, &size); if (size == 0) break; ABT_pool_get_total_size(rt1_data->pool, &size); } while (size > 0); if (eid == 0) { ABT_event_prof_stop(); int cnt = __atomic_exchange_n(&rt1_data->cnt, 0, __ATOMIC_SEQ_CST); double local_work = (double)(cnt * rt1_data->num_iters); ABT_event_prof_publish("ops", local_work, local_work); } } static void rt1_app_compute(void *arg) { int pos = (int)(intptr_t)arg; int i; rt1_data->app_data[pos] = 0; for (i = 0; i < rt1_data->num_iters; i++) { rt1_data->app_data[pos] += sin((double)pos); } __atomic_fetch_add(&rt1_data->cnt, 1, __ATOMIC_SEQ_CST); }
/* Create a work-stealing scheduler and push it to the pool */ static void thread_add_sched(void *arg) { int idx = (int)(intptr_t)arg; int i; ABT_thread cur_thread; ABT_pool cur_pool; ABT_pool *my_pools; ABT_sched_config config; ABT_sched sched; size_t size; double t_start, t_end; ABT_sched_config_var cv_event_freq = { .idx = 0, .type = ABT_SCHED_CONFIG_INT }; ABT_sched_config_var cv_idx = { .idx = 1, .type = ABT_SCHED_CONFIG_INT }; ABT_sched_def sched_def = { .type = ABT_SCHED_TYPE_ULT, .init = sched_init, .run = sched_run, .free = sched_free, .get_migr_pool = NULL }; /* Create a scheduler */ ABT_sched_config_create(&config, cv_event_freq, 10, cv_idx, idx, ABT_sched_config_var_end); my_pools = (ABT_pool *)malloc(sizeof(ABT_pool) * max_xstreams); for (i = 0; i < max_xstreams; i++) { my_pools[i] = g_pools[(idx + i) % max_xstreams]; } ABT_sched_create(&sched_def, max_xstreams, my_pools, config, &sched); /* Create a ULT for the new scheduler */ ABT_thread_create(my_pools[0], thread_work, arg, ABT_THREAD_ATTR_NULL, NULL); /* Push the scheduler to the current pool */ ABT_thread_self(&cur_thread); ABT_thread_get_last_pool(cur_thread, &cur_pool); ABT_pool_add_sched(cur_pool, sched); /* Free */ ABT_thread_release(cur_thread); ABT_sched_config_free(&config); free(my_pools); t_start = ABT_get_wtime(); while (1) { ABT_thread_yield(); ABT_pool_get_total_size(cur_pool, &size); if (size == 0) { ABT_sched_free(&sched); break; } t_end = ABT_get_wtime(); if ((t_end - t_start) > g_timeout) { ABT_sched_finish(sched); } } } static void thread_work(void *arg) { int idx = (int)(intptr_t)arg; int i; ABT_thread cur_thread; ABT_pool cur_pool; ABT_thread *threads; int num_threads; double t_start, t_end; ABT_thread_self(&cur_thread); ABT_thread_get_last_pool(cur_thread, &cur_pool); ABT_thread_release(cur_thread); t_start = ABT_get_wtime(); while (1) { num_threads = 2; threads = (ABT_thread *)malloc(sizeof(ABT_thread) * num_threads); for (i = 0; i < num_threads; i++) { ABT_thread_create(cur_pool, thread_hello, NULL, ABT_THREAD_ATTR_NULL, &threads[i]); } for (i = 0; i < num_threads; i++) { ABT_thread_free(&threads[i]); } free(threads); if (g_signal[idx]) { ABT_xstream xstream; ABT_xstream_self(&xstream); ABT_xstream_cancel(xstream); g_signal[idx] = 0; break; } t_end = ABT_get_wtime(); if ((t_end - t_start) > g_timeout) { break; } } } static void test_printf(const char *format, ...) { #if 0 va_start(list, format); vprintf(format, list); va_end(list); fflush(stdout); #endif }