static void create_scheds_and_xstreams(void) { int i, k, ret; int num_scheds = g_data.num_scheds; ABT_sched *scheds = g_data.scheds; int *num_pools = g_data.num_pools; ABT_pool **pools = g_data.pools; ABT_xstream *xstreams = g_data.xstreams; for (i = 0; i < num_scheds; i++) { if (i == num_scheds-1) { /* Create pools and then create a scheduler */ num_pools[i] = 2; pools[i] = (ABT_pool *)malloc(num_pools[i] * sizeof(ABT_pool)); pools[i][0] = ABT_POOL_NULL; for (k = 1; k < num_pools[i]; k++) { ret = ABT_pool_create_basic(ABT_POOL_FIFO, ABT_POOL_ACCESS_MPSC, ABT_TRUE, &pools[i][k]); ABT_TEST_ERROR(ret, "ABT_pool_create_basic"); } ret = ABT_sched_create_basic(ABT_SCHED_PRIO, num_pools[i], pools[i], ABT_SCHED_CONFIG_NULL, &scheds[i]); ABT_TEST_ERROR(ret, "ABT_sched_create_basic"); } else { /* Create a scheduler and then get the list of pools */ ABT_sched_config config; ret = ABT_sched_config_create(&config, ABT_sched_config_access, accesses[i], ABT_sched_config_var_end); ABT_TEST_ERROR(ret, "ABT_sched_config_create"); ret = ABT_sched_create_basic(ABT_SCHED_PRIO, 0, NULL, config, &scheds[i]); ABT_TEST_ERROR(ret, "ABT_sched_create_basic"); ret = ABT_sched_config_free(&config); ABT_TEST_ERROR(ret, "ABT_sched_config_free"); ret = ABT_sched_get_num_pools(scheds[i], &num_pools[i]); ABT_TEST_ERROR(ret, "ABT_sched_get_num_pools"); pools[i] = (ABT_pool *)malloc(num_pools[i] * sizeof(ABT_pool)); } ret = ABT_sched_get_pools(scheds[i], num_pools[i], 0, pools[i]); ABT_TEST_ERROR(ret, "ABT_sched_get_pools"); /* Create ES */ if (i == 0) { ret = ABT_xstream_self(&xstreams[i]); ABT_TEST_ERROR(ret, "ABT_xstream_self"); ret = ABT_xstream_set_main_sched(xstreams[i], scheds[i]); ABT_TEST_ERROR(ret, "ABT_xstream_set_main_sched"); } else { /* If the predefined scheduler is associated with PW pools, we will stack it so that the primary ULT can add the initial work unit. */ if (accesses[i] == ABT_POOL_ACCESS_PRIV || accesses[i] == ABT_POOL_ACCESS_SPSC || accesses[i] == ABT_POOL_ACCESS_SPMC) { ret = ABT_xstream_create(ABT_SCHED_NULL, &xstreams[i]); ABT_TEST_ERROR(ret, "ABT_xstream_create"); } else { ret = ABT_xstream_create(scheds[i], &xstreams[i]); ABT_TEST_ERROR(ret, "ABT_xstream_create"); } } } }
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 }