From 2417ada2e1f696180f72a685f3a220d66d66daeb Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Wed, 16 Dec 2015 20:29:24 -0600 Subject: [PATCH 1/6] first draft of blocking futures support --- inc/hclib.h | 20 +++++++--- inc/hcpp-ddf.h | 22 ++++++++--- src/hclib.c | 25 ++++++++++++ src/hcpp-ddf.c | 85 ++++++++++++++++++++++------------------- src/hcpp-runtime.c | 58 ++++++++++++++++++++++++---- src/inc/hcpp-internal.h | 6 +++ test/c/.gitignore | 2 + test/c/Makefile | 2 +- test/c/ddf/future0.c | 53 +++++++++++++++++++++++++ test/c/ddf/future1.c | 48 +++++++++++++++++++++++ 10 files changed, 263 insertions(+), 58 deletions(-) create mode 100644 test/c/ddf/future0.c create mode 100644 test/c/ddf/future1.c diff --git a/inc/hclib.h b/inc/hclib.h index e322870a..e2326864 100644 --- a/inc/hclib.h +++ b/inc/hclib.h @@ -83,6 +83,14 @@ void hclib_async(asyncFct_t fct_ptr, void * arg, struct hclib_ddf_st ** ddf_list, struct _phased_t * phased_clause, int property); +/* + * Spawn an async that automatically puts a DDF on termination. The put is + * performed with arg. + */ +hclib_ddf_t *hclib_async_future(generic_framePtr fp, void *arg, + hclib_ddf_t **ddf_list, struct _phased_t *phased_clause, + int property); + /* * Forasync definition and API */ @@ -102,7 +110,7 @@ typedef int forasync_mode_t; * @param[in] arg Argument to the loop iteration * @param[in] index Current iteration index */ -typedef void (*forasync1D_Fct_t) (void * arg,int index); +typedef void (*forasync1D_Fct_t)(void *arg, int index); /** * @brief Function prototype for a 2-dimensions forasync. @@ -110,7 +118,7 @@ typedef void (*forasync1D_Fct_t) (void * arg,int index); * @param[in] index_outer Current outer iteration index * @param[in] index_inner Current inner iteration index */ -typedef void (*forasync2D_Fct_t) (void * arg,int index_outer,int index_inner); +typedef void (*forasync2D_Fct_t)(void *arg, int index_outer, int index_inner); /** * @brief Function prototype for a 3-dimensions forasync. @@ -119,7 +127,8 @@ typedef void (*forasync2D_Fct_t) (void * arg,int index_outer,int index_inner); * @param[in] index_mid Current intermediate iteration index * @param[in] index_inner Current inner iteration index */ -typedef void (*forasync3D_Fct_t) (void * arg,int index_outer,int index_mid,int index_inner); +typedef void (*forasync3D_Fct_t)(void *arg, int index_outer, int index_mid, + int index_inner); /** * @brief Parallel for loop 'forasync' (up to 3 dimensions). @@ -136,8 +145,9 @@ typedef void (*forasync3D_Fct_t) (void * arg,int index_outer,int index_mid,int i * @param[in] domain Loop domains to iterate over (array of size 'dim'). * @param[in] mode Forasync mode to control chunking strategy (flat chunking or recursive). */ -void hclib_forasync(void* forasync_fct, void * argv, hclib_ddf_t ** ddf_list, struct _phased_t * phased_clause, - void *accumed_placeholder, int dim, loop_domain_t * domain, forasync_mode_t mode); +void hclib_forasync(void *forasync_fct, void *argv, hclib_ddf_t **ddf_list, + struct _phased_t *phased_clause, void *accumed_placeholder, int dim, + loop_domain_t *domain, forasync_mode_t mode); /** * @brief starts a new finish scope diff --git a/inc/hcpp-ddf.h b/inc/hcpp-ddf.h index cb5380c3..9bd26aa5 100644 --- a/inc/hcpp-ddf.h +++ b/inc/hcpp-ddf.h @@ -31,6 +31,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* * hcpp-ddf.h + * + * NOTE: Terminology + * DDF = data-driven future + * DDT = data-driven task (a task that triggers DDF objects) * * Author: Vivek Kumar (vivekk@rice.edu) * Ported from hclib @@ -67,15 +71,17 @@ typedef enum DDF_Kind { /** * DDT data-structure to associate DDTs and DDFs. - * This is exposed so that the runtime know the size of the struct. + * This is exposed so that the runtime knows the size of the struct. */ typedef struct ddt_st { // NULL-terminated list of DDFs the DDT is registered on struct hclib_ddf_st ** waitingFrontier; - // This allows us to chain all DDTs waiting on a same DDF - // Whenever a DDT wants to register on a DDF, and that DDF is - // not ready, we chain the current DDT and the DDF's headDDTWaitList - // and try to cas on the DDF's headDDTWaitList, with the current DDT. + /* + * This allows us to chain all DDTs waiting on a same DDF. Whenever a DDT + * wants to register on a DDF, and that DDF is not ready, we chain the + * current DDT and the DDF's headDDTWaitList and try to cas on the DDF's + * headDDTWaitList, with the current DDT. + */ struct ddt_st * nextDDTWaitingOnSameDDF; } ddt_t; @@ -132,6 +138,12 @@ void * hclib_ddf_get(hclib_ddf_t * ddf); */ void hclib_ddf_put(hclib_ddf_t * ddf, void * datum); +/* + * Block the currently executing task on the provided DDF. Returns the datum + * that was put on ddf. + */ +void *hclib_ddf_wait(hclib_ddf_t *ddf); + /* * Some extras */ diff --git a/src/hclib.c b/src/hclib.c index 6b0a3908..509e5cb9 100644 --- a/src/hclib.c +++ b/src/hclib.c @@ -37,6 +37,31 @@ void hclib_async(generic_framePtr fp, void *arg, hclib_ddf_t** ddf_list, } } +typedef struct _future_args_wrapper { + hclib_ddf_t event; + generic_framePtr fp; + void *actual_in; +} future_args_wrapper; + +static void future_caller(void *in) { + future_args_wrapper *args = (future_args_wrapper *)in; + (args->fp)(args->actual_in); + hclib_ddf_put(&args->event, NULL); +} + +hclib_ddf_t *hclib_async_future(generic_framePtr fp, void *arg, + hclib_ddf_t** ddf_list, struct _phased_t * phased_clause, + int property) { + future_args_wrapper *wrapper = (future_args_wrapper *)malloc( + sizeof(future_args_wrapper)); + hclib_ddf_init(&wrapper->event); + wrapper->fp = fp; + wrapper->actual_in = arg; + hclib_async(future_caller, wrapper, ddf_list, phased_clause, property); + + return (hclib_ddf_t *)wrapper; +} + /*** END ASYNC IMPLEMENTATION ***/ /*** START FORASYNC IMPLEMENTATION ***/ diff --git a/src/hcpp-ddf.c b/src/hcpp-ddf.c index b26336d8..7921e89b 100644 --- a/src/hcpp-ddf.c +++ b/src/hcpp-ddf.c @@ -49,10 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // For 'headDDTWaitList' when a DDF has been satisfied #define DDF_SATISFIED NULL -// Default value of a DDF datum -// #define UNINITIALIZED_DDF_DATA_PTR NULL -#define UNINITIALIZED_DDF_DATA_PTR ((void *) -1) - // For waiting frontier (last element of the list) #define UNINITIALIZED_DDF_WAITLIST_PTR ((ddt_t *) -1) #define EMPTY_DDF_WAITLIST_PTR NULL @@ -146,15 +142,22 @@ __inline__ int __registerIfDDFnotReady_AND(ddt_t* wrapperTask, /* waitListOfDDF can not be EMPTY_DDF_WAITLIST_PTR in here*/ wrapperTask->nextDDTWaitingOnSameDDF = waitListOfDDF; - success = __sync_bool_compare_and_swap(&(ddfToCheck -> headDDTWaitList), waitListOfDDF, wrapperTask); + success = __sync_bool_compare_and_swap( + &(ddfToCheck -> headDDTWaitList), waitListOfDDF, + wrapperTask); /* printf("task:%p registered to DDF:%p\n", pollingTask,ddfToCheck); */ - /* may have failed because either some other task tried to be the head or a put occurred. */ - if ( !success ) { - waitListOfDDF = ( ddt_t* ) ddfToCheck -> headDDTWaitList; - /* if waitListOfDDF was set to EMPTY_DDF_WAITLIST_PTR, the loop condition will handle that - * if another task was added, now try to add in front of that - * */ + /* + * may have failed because either some other task tried to be the + * head or a put occurred. + */ + if (!success) { + waitListOfDDF = (ddt_t*)ddfToCheck->headDDTWaitList; + /* + * if waitListOfDDF was set to EMPTY_DDF_WAITLIST_PTR, the loop + * condition will handle that if another task was added, now try + * to add in front of that + */ } } @@ -197,37 +200,39 @@ ddt_t * rt_async_task_to_ddt(task_t * async_task) { * DDF's frontier to try to advance DDTs that were waiting on this DDF. */ void hclib_ddf_put(hclib_ddf_t* ddfToBePut, void * datumToBePut) { - HASSERT (datumToBePut != UNINITIALIZED_DDF_DATA_PTR && EMPTY_DATUM_ERROR_MSG); - HASSERT (ddfToBePut != NULL && "can not put into NULL DDF"); - HASSERT (ddfToBePut-> datum == UNINITIALIZED_DDF_DATA_PTR && "violated single assignment property for DDFs"); - - volatile ddt_t* waitListOfDDF = NULL; - ddt_t* currDDT = NULL; - ddt_t* nextDDT = NULL; - - ddfToBePut-> datum = datumToBePut; - waitListOfDDF = ddfToBePut->headDDTWaitList; - /*seems like I can not avoid a CAS here*/ - while ( !__sync_bool_compare_and_swap( &(ddfToBePut -> headDDTWaitList), waitListOfDDF, EMPTY_DDF_WAITLIST_PTR)) { - waitListOfDDF = ddfToBePut -> headDDTWaitList; - } + HASSERT (datumToBePut != UNINITIALIZED_DDF_DATA_PTR && EMPTY_DATUM_ERROR_MSG); + HASSERT (ddfToBePut != NULL && "can not put into NULL DDF"); + HASSERT (ddfToBePut-> datum == UNINITIALIZED_DDF_DATA_PTR && + "violated single assignment property for DDFs"); + + volatile ddt_t* waitListOfDDF = NULL; + ddt_t* currDDT = NULL; + ddt_t* nextDDT = NULL; + + ddfToBePut-> datum = datumToBePut; + waitListOfDDF = ddfToBePut->headDDTWaitList; + /*seems like I can not avoid a CAS here*/ + while (!__sync_bool_compare_and_swap( &(ddfToBePut -> headDDTWaitList), + waitListOfDDF, EMPTY_DDF_WAITLIST_PTR)) { + waitListOfDDF = ddfToBePut -> headDDTWaitList; + } - currDDT = (ddt_t*)waitListOfDDF; + currDDT = (ddt_t*)waitListOfDDF; int iter_count = 0; - /* printf("DDF:%p was put:%p with value:%d\n", ddfToBePut, datumToBePut,*((int*)datumToBePut)); */ - while (currDDT != UNINITIALIZED_DDF_WAITLIST_PTR) { - - nextDDT = currDDT->nextDDTWaitingOnSameDDF; - if (iterate_ddt_frontier(currDDT) ) { - /* printf("pushed:%p\n", currDDT); */ - /*deque_push_default(currFrame);*/ - // DDT eligible to scheduling - task_t * async_task = rt_ddt_to_async_task(currDDT); - if (DEBUG_DDF) { printf("ddf: async_task %p\n", async_task); } - try_schedule_async(async_task, 0); - } - currDDT = nextDDT; + /* printf("DDF:%p was put:%p with value:%d\n", ddfToBePut, datumToBePut,*((int*)datumToBePut)); */ + while (currDDT != UNINITIALIZED_DDF_WAITLIST_PTR) { + + nextDDT = currDDT->nextDDTWaitingOnSameDDF; + if (iterate_ddt_frontier(currDDT)) { + /* printf("pushed:%p\n", currDDT); */ + /*deque_push_default(currFrame);*/ + // DDT eligible to scheduling + task_t * async_task = rt_ddt_to_async_task(currDDT); + if (DEBUG_DDF) { printf("ddf: async_task %p\n", async_task); } + try_schedule_async(async_task, 0); + } + currDDT = nextDDT; iter_count++; - } + } } diff --git a/src/hcpp-runtime.c b/src/hcpp-runtime.c index 27ca79e5..b51dbe2c 100644 --- a/src/hcpp-runtime.c +++ b/src/hcpp-runtime.c @@ -112,7 +112,7 @@ static void set_curr_lite_ctx(LiteCtx *ctx) { CURRENT_WS_INTERNAL->curr_ctx = ctx; } -static LiteCtx *get_curr_lite_ctx() { +LiteCtx *get_curr_lite_ctx() { return CURRENT_WS_INTERNAL->curr_ctx; } @@ -548,7 +548,7 @@ static void _hclib_finalize_ctx(LiteCtx *ctx) { assert(0); // Should never return here } -static void core_work_loop(void) { +void core_work_loop(void) { uint64_t wid; do { hc_workerState *ws = CURRENT_WS_INTERNAL; @@ -636,7 +636,7 @@ void teardown() { } #if HCLIB_LITECTX_STRATEGY -static void _finish_ctx_resume(void *arg) { +void _finish_ctx_resume(void *arg) { LiteCtx *currentCtx = get_curr_lite_ctx(); LiteCtx *finishCtx = arg; ctx_swap(currentCtx, finishCtx, __func__); @@ -648,10 +648,45 @@ static void _finish_ctx_resume(void *arg) { void crt_work_loop(LiteCtx *ctx); +// Based on _help_finish_ctx +void _help_wait(LiteCtx *ctx) { + hclib_ddf_t **continuation_deps = ctx->arg; + LiteCtx *wait_ctx = ctx->prev; + + hcpp_task_t *task = (hcpp_task_t *)malloc(sizeof(hcpp_task_t)); + task->async_task._fp = _finish_ctx_resume; // reuse _finish_ctx_resume + task->async_task.is_asyncAnyType = 0; + task->async_task.ddf_list = NULL; + task->async_task.args = wait_ctx; + + spawn_escaping((task_t *)task, continuation_deps); + + core_work_loop(); + assert(0); +} + +void *hclib_ddf_wait(hclib_ddf_t *ddf) { + if (ddf->datum != UNINITIALIZED_DDF_DATA_PTR) { + return (void *)ddf->datum; + } + hclib_ddf_t *continuation_deps[] = { ddf, NULL }; + LiteCtx *currentCtx = get_curr_lite_ctx(); + assert(currentCtx); + LiteCtx *newCtx = LiteCtx_create(_help_wait); + newCtx->arg = continuation_deps; + ctx_swap(currentCtx, newCtx, __func__); + LiteCtx_destroy(currentCtx->prev); + + assert(ddf->datum != UNINITIALIZED_DDF_DATA_PTR); + return (void *)ddf->datum; +} + static void _help_finish_ctx(LiteCtx *ctx) { - // Set up previous context to be stolen when the finish completes - // (note that the async must ESCAPE, otherwise this finish scope will deadlock on itself) - // finish_t *finish = ((volatile LiteCtx * volatile)ctx)->arg; + /* + * Set up previous context to be stolen when the finish completes (note that + * the async must ESCAPE, otherwise this finish scope will deadlock on + * itself). + */ finish_t *finish = ctx->arg; LiteCtx *hclib_finish_ctx = ctx->prev; @@ -661,10 +696,19 @@ static void _help_finish_ctx(LiteCtx *ctx) { task->async_task.ddf_list = NULL; task->async_task.args = hclib_finish_ctx; + /* + * Create an async to handle the continuation after the finish, whose state + * is captured in hclib_finish_ctx and whose execution is pending on + * finish->finish_deps. + */ spawn_escaping((task_t *)task, finish->finish_deps); - // keep workstealing until this context gets swapped out and destroyed + /* + * The main thread is now exiting the finish (albeit in a separate context), + * so check it out. + */ check_out_finish(finish); + // keep workstealing until this context gets swapped out and destroyed core_work_loop(); // this function never returns assert(0); // we should never return here } diff --git a/src/inc/hcpp-internal.h b/src/inc/hcpp-internal.h index d3126811..a397d97a 100644 --- a/src/inc/hcpp-internal.h +++ b/src/inc/hcpp-internal.h @@ -71,6 +71,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CACHE_LINE_L1 8 +// Default value of a DDF datum +#define UNINITIALIZED_DDF_DATA_PTR ((void *)-1) + typedef struct { volatile uint64_t flag; void * pad[CACHE_LINE_L1-1]; @@ -123,4 +126,7 @@ int iterate_ddt_frontier(ddt_t * ddt); ddt_t * rt_async_task_to_ddt(task_t * async_task); void try_schedule_async(task_t * async_task, int comm_task); +extern void _help_wait(LiteCtx *ctx); +extern LiteCtx *get_curr_lite_ctx(); + #endif /* HCPP_INTERNAL_H_ */ diff --git a/test/c/.gitignore b/test/c/.gitignore index 51179f1f..caf28627 100644 --- a/test/c/.gitignore +++ b/test/c/.gitignore @@ -4,6 +4,8 @@ async1 ddf/asyncAwait0 ddf/asyncAwait0Null ddf/asyncAwait1 +ddf/future0 +ddf/future1 finish0 finish1 finish2 diff --git a/test/c/Makefile b/test/c/Makefile index 3dbb1909..21b5c740 100644 --- a/test/c/Makefile +++ b/test/c/Makefile @@ -2,7 +2,7 @@ include $(HCPP_ROOT)/include/hcpp.mak TARGETS=async0 async1 finish0 finish1 finish2 forasync1DCh forasync1DRec \ forasync2DCh forasync2DRec forasync3DCh forasync3DRec \ - ddf/asyncAwait0 ddf/asyncAwait0Null ddf/asyncAwait1 + ddf/asyncAwait0 ddf/asyncAwait0Null ddf/asyncAwait1 ddf/future0 ddf/future1 FLAGS=-g diff --git a/test/c/ddf/future0.c b/test/c/ddf/future0.c new file mode 100644 index 00000000..9d720641 --- /dev/null +++ b/test/c/ddf/future0.c @@ -0,0 +1,53 @@ +/* + * RICE University + * Habanero Team + * + * This file is part of HC Test. + * + */ + +#include +#include + +#include "hclib.h" + +void async_fct(void *arg) { + int *count_ptr = (int *)arg; + + printf("Running async with count = %d\n", *count_ptr); + *count_ptr = *count_ptr + 1; +} + +void entrypoint(void *arg) { + + int n_asyncs = 5; + int *count = (int *)malloc(sizeof(int)); + assert(count); + *count = 0; + + hclib_start_finish(); + int i; + hclib_ddf_t *prev = NULL; + for (i = 0; i < n_asyncs; i++) { + if (prev) { + hclib_ddf_t **ddf_list = (hclib_ddf_t **)malloc( + 2 * sizeof(hclib_ddf_t *)); + assert(ddf_list); + ddf_list[0] = prev; + ddf_list[1] = NULL; + prev = hclib_async_future(async_fct, count, ddf_list, NULL, + NO_PROP); + } else { + prev = hclib_async_future(async_fct, count, NULL, NULL, NO_PROP); + } + } + hclib_end_finish(); + + assert(*count == n_asyncs); +} + +int main(int argc, char ** argv) { + hclib_launch(&argc, argv, entrypoint, NULL); + printf("Exiting...\n"); + return 0; +} diff --git a/test/c/ddf/future1.c b/test/c/ddf/future1.c new file mode 100644 index 00000000..24bbb2d5 --- /dev/null +++ b/test/c/ddf/future1.c @@ -0,0 +1,48 @@ +/* + * RICE University + * Habanero Team + * + * This file is part of HC Test. + * + */ + +#include +#include +#include + +#include "hclib.h" + +void producer(void *arg) { + hclib_ddf_t *event = (hclib_ddf_t *)arg; + int *signal = (int *)malloc(sizeof(int)); + assert(signal); + *signal = 42; + + sleep(5); + + hclib_ddf_put(event, signal); +} + +void consumer(void *arg) { + hclib_ddf_t *event = (hclib_ddf_t *)arg; + int *signal = (int *)hclib_ddf_wait(event); + assert(*signal == 42); + printf("signal = %d\n", *signal); +} + +void entrypoint(void *arg) { + + hclib_start_finish(); + + hclib_ddf_t *event = hclib_ddf_create(); + hclib_async(consumer, event, NULL, NULL, NO_PROP); + hclib_async(producer, event, NULL, NULL, NO_PROP); + + hclib_end_finish(); +} + +int main(int argc, char ** argv) { + hclib_launch(&argc, argv, entrypoint, NULL); + printf("Exiting...\n"); + return 0; +} From 1b9d2f97c47f18e7b72d57d712763e8d683612d6 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Wed, 16 Dec 2015 20:51:42 -0600 Subject: [PATCH 2/6] finish up c++ future support --- inc/hclib_cpp.h | 1 + inc/hcpp-async.h | 9 ++++++++ inc/hcpp-rt.h | 16 ++++++++------ src/hclib_cpp.cpp | 4 ++++ test/cpp/.gitignore | 2 ++ test/cpp/Makefile | 2 +- test/cpp/ddf/future0.cpp | 48 ++++++++++++++++++++++++++++++++++++++++ test/cpp/ddf/future1.cpp | 36 ++++++++++++++++++++++++++++++ 8 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 test/cpp/ddf/future0.cpp create mode 100644 test/cpp/ddf/future1.cpp diff --git a/inc/hclib_cpp.h b/inc/hclib_cpp.h index 3aa2aa09..4188ff5b 100644 --- a/inc/hclib_cpp.h +++ b/inc/hclib_cpp.h @@ -27,6 +27,7 @@ ddf_t *ddf_create(); void ddf_free(ddf_t *ddf); void ddf_put(ddf_t *ddf, void *datum); void *ddf_get(ddf_t *ddf); +void *ddf_wait(ddf_t *ddf); hc_workerState *current_ws(); int current_worker(); diff --git a/inc/hcpp-async.h b/inc/hcpp-async.h index 9f639265..24188957 100644 --- a/inc/hcpp-async.h +++ b/inc/hcpp-async.h @@ -168,6 +168,15 @@ inline void asyncComm(T lambda) { spawn_commTask(task); } +template +hclib_ddf_t *asyncFuture(T lambda) { + hclib_ddf_t *event = hclib_ddf_create(); + auto wrapper = [event, lambda]() { lambda(); hclib_ddf_put(event, NULL); }; + task_t* task = _allocate_async(wrapper, false); + spawn(task); + return event; +} + inline void finish(std::function lambda) { hclib_start_finish(); lambda(); diff --git a/inc/hcpp-rt.h b/inc/hcpp-rt.h index a1ca926a..6102b33c 100644 --- a/inc/hcpp-rt.h +++ b/inc/hcpp-rt.h @@ -59,16 +59,18 @@ struct hc_deque_t; struct finish_t; typedef struct hc_workerState { - pthread_t t; /* the pthread associated */ + pthread_t t; // the pthread associated struct finish_t* current_finish; - struct place_t * pl; /* the directly attached place */ - struct place_t ** hpt_path; /* Path from root to worker's leaf place. Array of places. */ + struct place_t * pl; // the directly attached place + // Path from root to worker's leaf place. Array of places. + struct place_t ** hpt_path; struct hc_context * context; - struct hc_workerState * next_worker; /* the link of other ws in the same place */ - struct hc_deque_t * current; /* the current deque/place worker is on */ + // the link of other ws in the same place + struct hc_workerState * next_worker; + struct hc_deque_t * current; // the current deque/place worker is on struct hc_deque_t * deques; - int id; /* The id, identify a worker */ - int did; /* the mapping device id */ + int id; // The id, identify a worker + int did; // the mapping device id LiteCtx *curr_ctx; LiteCtx *root_ctx; } hc_workerState; diff --git a/src/hclib_cpp.cpp b/src/hclib_cpp.cpp index a1b3ce52..50a2663f 100644 --- a/src/hclib_cpp.cpp +++ b/src/hclib_cpp.cpp @@ -43,3 +43,7 @@ int hclib::get_num_places(hclib::place_type_t type) { void hclib::get_places(hclib::place_t **pls, hclib::place_type_t type) { hclib_get_places(pls, type); } + +void *hclib::ddf_wait(hclib::ddf_t *ddf) { + hclib_ddf_wait(ddf); +} diff --git a/test/cpp/.gitignore b/test/cpp/.gitignore index 51179f1f..caf28627 100644 --- a/test/cpp/.gitignore +++ b/test/cpp/.gitignore @@ -4,6 +4,8 @@ async1 ddf/asyncAwait0 ddf/asyncAwait0Null ddf/asyncAwait1 +ddf/future0 +ddf/future1 finish0 finish1 finish2 diff --git a/test/cpp/Makefile b/test/cpp/Makefile index 8dfc981d..2a82e212 100644 --- a/test/cpp/Makefile +++ b/test/cpp/Makefile @@ -2,7 +2,7 @@ include $(HCPP_ROOT)/include/hcpp.mak TARGETS=async0 async1 finish0 finish1 finish2 forasync1DCh forasync1DRec \ forasync2DCh forasync2DRec forasync3DCh forasync3DRec \ - ddf/asyncAwait0 ddf/asyncAwait0Null ddf/asyncAwait1 + ddf/asyncAwait0 ddf/asyncAwait0Null ddf/asyncAwait1 ddf/future0 ddf/future1 FLAGS=-g -std=c++11 diff --git a/test/cpp/ddf/future0.cpp b/test/cpp/ddf/future0.cpp new file mode 100644 index 00000000..d5f18994 --- /dev/null +++ b/test/cpp/ddf/future0.cpp @@ -0,0 +1,48 @@ +/* + * RICE University + * Habanero Team + * + * This file is part of HC Test. + * + */ + +#include +#include + +#include "hclib_cpp.h" + +int main(int argc, char ** argv) { + hclib::launch(&argc, argv, []() { + int n_asyncs = 5; + int *count = (int *)malloc(sizeof(int)); + assert(count); + *count = 0; + + hclib::finish([=]() { + int i; + hclib_ddf_t *prev = NULL; + for (i = 0; i < n_asyncs; i++) { + if (prev) { + hclib_ddf_t **ddf_list = (hclib_ddf_t **)malloc( + 2 * sizeof(hclib_ddf_t *)); + assert(ddf_list); + ddf_list[0] = prev; + ddf_list[1] = NULL; + prev = hclib::asyncFuture([=]() { + printf("Running async with count = %d\n", *count); + *count = *count + 1; + }); + } else { + prev = hclib::asyncFuture([=]() { + printf("Running async with count = %d\n", *count); + *count = *count + 1; + }); + } + } + }); + + assert(*count == n_asyncs); + }); + printf("Exiting...\n"); + return 0; +} diff --git a/test/cpp/ddf/future1.cpp b/test/cpp/ddf/future1.cpp new file mode 100644 index 00000000..92a62217 --- /dev/null +++ b/test/cpp/ddf/future1.cpp @@ -0,0 +1,36 @@ +/* + * RICE University + * Habanero Team + * + * This file is part of HC Test. + * + */ + +#include +#include +#include + +#include "hclib_cpp.h" + +int main(int argc, char ** argv) { + hclib::launch(&argc, argv, []() { + hclib::finish([]() { + hclib::ddf_t *event = hclib::ddf_create(); + hclib::async([=]() { + int *signal = (int *)hclib::ddf_wait(event); + assert(*signal == 42); + printf("signal = %d\n", *signal); + }); + hclib::async([=]() { + int *signal = (int *)malloc(sizeof(int)); + assert(signal); + *signal = 42; + + sleep(5); + hclib::ddf_put(event, signal); + }); + }); + }); + printf("Exiting...\n"); + return 0; +} From 6264f824411a958a1b2a56d37be18939d61ea693 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Wed, 16 Dec 2015 20:54:59 -0600 Subject: [PATCH 3/6] fix misleading comment --- inc/hclib.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/inc/hclib.h b/inc/hclib.h index e2326864..d564ae5c 100644 --- a/inc/hclib.h +++ b/inc/hclib.h @@ -84,8 +84,7 @@ void hclib_async(asyncFct_t fct_ptr, void * arg, int property); /* - * Spawn an async that automatically puts a DDF on termination. The put is - * performed with arg. + * Spawn an async that automatically puts a DDF on termination. */ hclib_ddf_t *hclib_async_future(generic_framePtr fp, void *arg, hclib_ddf_t **ddf_list, struct _phased_t *phased_clause, From 03ee14cdc176e593f60811482379cdd584598818 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Wed, 16 Dec 2015 22:06:56 -0600 Subject: [PATCH 4/6] address nick's comments --- inc/hclib.h | 2 +- inc/hcpp-ddf.h | 2 +- src/hclib.c | 5 ++--- src/hcpp-runtime.c | 6 +++--- src/inc/hcpp-internal.h | 3 --- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/inc/hclib.h b/inc/hclib.h index d564ae5c..2651a008 100644 --- a/inc/hclib.h +++ b/inc/hclib.h @@ -86,7 +86,7 @@ void hclib_async(asyncFct_t fct_ptr, void * arg, /* * Spawn an async that automatically puts a DDF on termination. */ -hclib_ddf_t *hclib_async_future(generic_framePtr fp, void *arg, +hclib_ddf_t *hclib_async_future(asyncFct_t fp, void *arg, hclib_ddf_t **ddf_list, struct _phased_t *phased_clause, int property); diff --git a/inc/hcpp-ddf.h b/inc/hcpp-ddf.h index 9bd26aa5..373712fd 100644 --- a/inc/hcpp-ddf.h +++ b/inc/hcpp-ddf.h @@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * NOTE: Terminology * DDF = data-driven future - * DDT = data-driven task (a task that triggers DDF objects) + * DDT = data-driven task (a task that waits on DDF objects) * * Author: Vivek Kumar (vivekk@rice.edu) * Ported from hclib diff --git a/src/hclib.c b/src/hclib.c index 509e5cb9..cd5ab36b 100644 --- a/src/hclib.c +++ b/src/hclib.c @@ -52,14 +52,13 @@ static void future_caller(void *in) { hclib_ddf_t *hclib_async_future(generic_framePtr fp, void *arg, hclib_ddf_t** ddf_list, struct _phased_t * phased_clause, int property) { - future_args_wrapper *wrapper = (future_args_wrapper *)malloc( - sizeof(future_args_wrapper)); + future_args_wrapper *wrapper = malloc(sizeof(future_args_wrapper)); hclib_ddf_init(&wrapper->event); wrapper->fp = fp; wrapper->actual_in = arg; hclib_async(future_caller, wrapper, ddf_list, phased_clause, property); - return (hclib_ddf_t *)wrapper; + return wrapper; } /*** END ASYNC IMPLEMENTATION ***/ diff --git a/src/hcpp-runtime.c b/src/hcpp-runtime.c index b51dbe2c..ac78344a 100644 --- a/src/hcpp-runtime.c +++ b/src/hcpp-runtime.c @@ -112,7 +112,7 @@ static void set_curr_lite_ctx(LiteCtx *ctx) { CURRENT_WS_INTERNAL->curr_ctx = ctx; } -LiteCtx *get_curr_lite_ctx() { +static LiteCtx *get_curr_lite_ctx() { return CURRENT_WS_INTERNAL->curr_ctx; } @@ -548,7 +548,7 @@ static void _hclib_finalize_ctx(LiteCtx *ctx) { assert(0); // Should never return here } -void core_work_loop(void) { +static void core_work_loop(void) { uint64_t wid; do { hc_workerState *ws = CURRENT_WS_INTERNAL; @@ -636,7 +636,7 @@ void teardown() { } #if HCLIB_LITECTX_STRATEGY -void _finish_ctx_resume(void *arg) { +static void _finish_ctx_resume(void *arg) { LiteCtx *currentCtx = get_curr_lite_ctx(); LiteCtx *finishCtx = arg; ctx_swap(currentCtx, finishCtx, __func__); diff --git a/src/inc/hcpp-internal.h b/src/inc/hcpp-internal.h index a397d97a..da253535 100644 --- a/src/inc/hcpp-internal.h +++ b/src/inc/hcpp-internal.h @@ -126,7 +126,4 @@ int iterate_ddt_frontier(ddt_t * ddt); ddt_t * rt_async_task_to_ddt(task_t * async_task); void try_schedule_async(task_t * async_task, int comm_task); -extern void _help_wait(LiteCtx *ctx); -extern LiteCtx *get_curr_lite_ctx(); - #endif /* HCPP_INTERNAL_H_ */ From 2af208e3b240dcbbdaf35c0080d0ea068150d7d0 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Wed, 16 Dec 2015 22:32:38 -0600 Subject: [PATCH 5/6] more fixes for nick's comments --- inc/hclib.h | 8 +++++--- inc/hcpp-async.h | 12 ++++++++++-- src/hclib.c | 12 ++++++------ src/hclib_cpp.cpp | 2 +- test/c/ddf/future0.c | 3 ++- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/inc/hclib.h b/inc/hclib.h index 2651a008..393bd3ed 100644 --- a/inc/hclib.h +++ b/inc/hclib.h @@ -58,7 +58,8 @@ struct _phased_t; * @brief Function prototype executable by an async. * @param[in] arg Arguments to the function */ -typedef void (*asyncFct_t) (void * arg); +typedef void (*asyncFct_t)(void * arg); +typedef void *(*futureFct_t)(void *arg); void hclib_launch(int * argc, char ** argv, asyncFct_t fct_ptr, void * arg); @@ -84,9 +85,10 @@ void hclib_async(asyncFct_t fct_ptr, void * arg, int property); /* - * Spawn an async that automatically puts a DDF on termination. + * Spawn an async that automatically puts a DDF on termination. It is the user's + * responsibility to call hclib_ddf_free on the returned ddf_t. */ -hclib_ddf_t *hclib_async_future(asyncFct_t fp, void *arg, +hclib_ddf_t *hclib_async_future(futureFct_t fp, void *arg, hclib_ddf_t **ddf_list, struct _phased_t *phased_clause, int property); diff --git a/inc/hcpp-async.h b/inc/hcpp-async.h index 24188957..50ab137d 100644 --- a/inc/hcpp-async.h +++ b/inc/hcpp-async.h @@ -171,8 +171,16 @@ inline void asyncComm(T lambda) { template hclib_ddf_t *asyncFuture(T lambda) { hclib_ddf_t *event = hclib_ddf_create(); - auto wrapper = [event, lambda]() { lambda(); hclib_ddf_put(event, NULL); }; - task_t* task = _allocate_async(wrapper, false); + /* + * TODO creating this closure may be inefficient. While the capture list is + * precise, if the user-provided lambda is large then copying it by value + * will also take extra time. + */ + auto wrapper = [event, lambda]() { + lambda(); + hclib_ddf_put(event, NULL); + }; + task_t* task = _allocate_async(wrapper, false); spawn(task); return event; } diff --git a/src/hclib.c b/src/hclib.c index cd5ab36b..7be8a690 100644 --- a/src/hclib.c +++ b/src/hclib.c @@ -39,17 +39,17 @@ void hclib_async(generic_framePtr fp, void *arg, hclib_ddf_t** ddf_list, typedef struct _future_args_wrapper { hclib_ddf_t event; - generic_framePtr fp; + futureFct_t fp; void *actual_in; } future_args_wrapper; static void future_caller(void *in) { - future_args_wrapper *args = (future_args_wrapper *)in; - (args->fp)(args->actual_in); - hclib_ddf_put(&args->event, NULL); + future_args_wrapper *args = in; + void *user_result = (args->fp)(args->actual_in); + hclib_ddf_put(&args->event, user_result); } -hclib_ddf_t *hclib_async_future(generic_framePtr fp, void *arg, +hclib_ddf_t *hclib_async_future(futureFct_t fp, void *arg, hclib_ddf_t** ddf_list, struct _phased_t * phased_clause, int property) { future_args_wrapper *wrapper = malloc(sizeof(future_args_wrapper)); @@ -58,7 +58,7 @@ hclib_ddf_t *hclib_async_future(generic_framePtr fp, void *arg, wrapper->actual_in = arg; hclib_async(future_caller, wrapper, ddf_list, phased_clause, property); - return wrapper; + return (hclib_ddf_t *)wrapper; } /*** END ASYNC IMPLEMENTATION ***/ diff --git a/src/hclib_cpp.cpp b/src/hclib_cpp.cpp index 50a2663f..ec0d2a54 100644 --- a/src/hclib_cpp.cpp +++ b/src/hclib_cpp.cpp @@ -45,5 +45,5 @@ void hclib::get_places(hclib::place_t **pls, hclib::place_type_t type) { } void *hclib::ddf_wait(hclib::ddf_t *ddf) { - hclib_ddf_wait(ddf); + return hclib_ddf_wait(ddf); } diff --git a/test/c/ddf/future0.c b/test/c/ddf/future0.c index 9d720641..7162738c 100644 --- a/test/c/ddf/future0.c +++ b/test/c/ddf/future0.c @@ -11,11 +11,12 @@ #include "hclib.h" -void async_fct(void *arg) { +void *async_fct(void *arg) { int *count_ptr = (int *)arg; printf("Running async with count = %d\n", *count_ptr); *count_ptr = *count_ptr + 1; + return NULL; } void entrypoint(void *arg) { From 25e58a3e9cee13ad9a1e2a2bf9317799d10ae3e7 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Thu, 17 Dec 2015 15:26:30 -0600 Subject: [PATCH 6/6] add future await in --- inc/hcpp-async.h | 17 +++++++++++++++++ test/cpp/ddf/future0.cpp | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/inc/hcpp-async.h b/inc/hcpp-async.h index 50ab137d..d6946733 100644 --- a/inc/hcpp-async.h +++ b/inc/hcpp-async.h @@ -185,6 +185,23 @@ hclib_ddf_t *asyncFuture(T lambda) { return event; } +template +hclib_ddf_t *asyncFutureAwait(hclib_ddf_t **ddf_list, T lambda) { + hclib_ddf_t *event = hclib_ddf_create(); + /* + * TODO creating this closure may be inefficient. While the capture list is + * precise, if the user-provided lambda is large then copying it by value + * will also take extra time. + */ + auto wrapper = [event, lambda]() { + lambda(); + hclib_ddf_put(event, NULL); + }; + task_t* task = _allocate_async(wrapper, true); + spawn_await(task, ddf_list); + return event; +} + inline void finish(std::function lambda) { hclib_start_finish(); lambda(); diff --git a/test/cpp/ddf/future0.cpp b/test/cpp/ddf/future0.cpp index d5f18994..b7036778 100644 --- a/test/cpp/ddf/future0.cpp +++ b/test/cpp/ddf/future0.cpp @@ -28,7 +28,7 @@ int main(int argc, char ** argv) { assert(ddf_list); ddf_list[0] = prev; ddf_list[1] = NULL; - prev = hclib::asyncFuture([=]() { + prev = hclib::asyncFutureAwait(ddf_list, [=]() { printf("Running async with count = %d\n", *count); *count = *count + 1; });