int test_speed_create_join() { int i=0; unsigned long long start, end; lwt_t tid1, tid2, tid3; tid1 = lwt_create(fn, NULL, 0, 0); lwt_join(tid1); IS_RESET(); rdtscll(start); for(i=0 ; i < ITER; i++) { tid1 = lwt_create(fn, NULL, 0, 0); lwt_join(tid1); } rdtscll(end); IS_RESET(); printf("performance of fork/join: --> %lld\n", (end-start)/ITER); for(i=0 ; i < ITER; i++) { tid1 = lwt_create(fn, NULL, 0, 0); tid2 = lwt_create(fn, NULL, 0, 0); tid3 = lwt_create(fn, NULL, 0, 0); lwt_join(tid3); lwt_join(tid1); lwt_join(tid2); } IS_RESET(); return 0; }
void test_perf(void) { lwt_t chld1, chld2; int i; unsigned long long start, end; /* Performance tests */ rdtscll(start); for (i = 0 ; i < ITER ; i++) { lwt_chan_t c = lwt_chan(0); chld1 = lwt_create(fn_null, NULL, 0, c); lwt_join(chld1); } rdtscll(end); printf("[PERF] %lld <- fork/join\n", (end-start)/ITER); IS_RESET(); lwt_chan_t c1 = lwt_chan(0); chld1 = lwt_create(fn_bounce, (void*)1, 0, c1); lwt_chan_t c2 = lwt_chan(0); chld2 = lwt_create(fn_bounce, NULL, 0, c2); lwt_join(chld1); lwt_join(chld2); IS_RESET(); }
void test_crt_join_sched(void) { lwt_t chld1, chld2; printf("[TEST] thread creation/join/scheduling\n"); /* functional tests: scheduling */ lwt_yield(LWT_NULL); lwt_chan_t c1 = lwt_chan(0); chld1 = lwt_create(fn_sequence, (void*)1, 0, c1); lwt_chan_t c2 = lwt_chan(0); chld2 = lwt_create(fn_sequence, (void*)2, 0, c2); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: join */ lwt_chan_t c3 = lwt_chan(0); chld1 = lwt_create(fn_null, NULL, 0, c3); lwt_join(chld1); IS_RESET(); lwt_chan_t c4 = lwt_chan(0); chld1 = lwt_create(fn_null, NULL, 0, c4); lwt_yield(LWT_NULL); lwt_join(chld1); IS_RESET(); lwt_chan_t c5 = lwt_chan(0); chld1 = lwt_create(fn_nested_joins, NULL, 0, c5); lwt_join(chld1); IS_RESET(); /* functional tests: join only from parents */ lwt_chan_t c6 = lwt_chan(0); chld1 = lwt_create(fn_identity, (void*)0x37337, 0, c6); lwt_chan_t c7 = lwt_chan(0); chld2 = lwt_create(fn_join, chld1, 0, c7); lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: passing data between threads */ lwt_chan_t c8 = lwt_chan(0); chld1 = lwt_create(fn_identity, (void*)0x37337, 0, c8); assert((void*)0x37337 == lwt_join(chld1)); IS_RESET(); /* functional tests: directed yield */ lwt_chan_t c9 = lwt_chan(0); chld1 = lwt_create(fn_null, NULL, 0, c9); lwt_yield(chld1); assert(lwt_info(LWT_INFO_NTHD_ZOMBIES) == 1); lwt_join(chld1); IS_RESET(); }
void test_speed_yield() { lwt_t tid1, tid2; tid1 = lwt_create(fn_bounce, (void*)1, 0, 0); tid2 = lwt_create(fn_bounce, NULL, 0, 0); lwt_yield(LWT_NULL); lwt_join(tid1); lwt_join(tid2); lwt_yield(LWT_NULL); IS_RESET(); }
int test_grp_wait_with_buffer() { lwt_chan_t main_c = lwt_chan(1); lwt_t id1 = lwt_create(grp_wait_snder, (void*)main_c, 0, 0); lwt_chan_t snd_c = lwt_rcv_chan(main_c); lwt_t id2 = lwt_create(grp_wait_rcver, (void*)main_c, 0, 0); lwt_chan_t rcv_c = lwt_rcv_chan(main_c); lwt_snd_chan(rcv_c, snd_c); lwt_join(id1); lwt_join(id2); return 0; }
void test_perf_channels(int chsz) { lwt_chan_t from, to; lwt_t t; int i; unsigned long long start, end; //assert(LWT_RUNNING == lwt_current()->state); from = lwt_chan(chsz); assert(from); t = lwt_create_chan(fn_chan, from, 0); to = lwt_rcv_chan(from); assert(to->snd_cnt); rdtscll(start); for (i = 0 ; i < ITER ; i++) { assert(1 == (int)lwt_rcv(from)); lwt_snd(to, (void*)2); } lwt_chan_deref(to); rdtscll(end); printf("[PERF] %5lld <- snd+rcv (buffer size %d)\n", (end-start)/(ITER*2), chsz); lwt_join(t); }
void test_multisend(int chsz) { lwt_chan_t c; lwt_t t1, t2; int i, ret[ITER*2], sum = 0, maxcnt = 0; struct multisend_arg args[2]; printf("[TEST] multisend (channel buffer size %d)\n", chsz); c = lwt_chan(chsz); assert(c); for (i = 0 ; i < 2 ; i++) { args[i].c = c; args[i].snd_val = i+1; lwt_chan_grant(c); } t1 = lwt_create(fn_snder, &args[0], 0, c); t2 = lwt_create(fn_snder, &args[1], 0, c); for (i = 0 ; i < ITER*2 ; i++) { /*if (i % 5 == 0) lwt_yield(LWT_NULL);*/ ret[i] = (int)lwt_rcv(c); if (sndrcv_cnt > maxcnt) maxcnt = sndrcv_cnt; sndrcv_cnt--; } lwt_join(t1); lwt_join(t2); for (i = 0 ; i < ITER*2 ; i++) { sum += ret[i]; assert(ret[i] == 1 || ret[i] == 2); } assert(sum == (ITER * 1) + (ITER*2)); /* * This is important: Asynchronous means that the buffer * should really fill up here as the senders never block until * the buffer is full. Thus the difference in the number of * sends and the number of receives should vary by the size of * the buffer. If your implementation doesn't do this, it is * doubtful you are really doing asynchronous communication. */ assert(maxcnt >= chsz); return; }
void * fn_join(void *d) { lwt_t t = (lwt_t)d; void *r; r = lwt_join(d); assert(r != (void*)0x37337); }
void test_crt_join_sched(void) { lwt_t chld1, chld2; /* functional tests: scheduling */ lwt_yield(LWT_NULL); chld1 = lwt_create(fn_sequence, (void*)1); chld2 = lwt_create(fn_sequence, (void*)2); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: join */ chld1 = lwt_create(fn_null, NULL); lwt_join(chld1); IS_RESET(); chld1 = lwt_create(fn_null, NULL); lwt_yield(LWT_NULL); lwt_join(chld1); IS_RESET(); chld1 = lwt_create(fn_nested_joins, NULL); lwt_join(chld1); IS_RESET(); /* functional tests: join only from parents */ chld1 = lwt_create(fn_identity, (void*)0x37337); chld2 = lwt_create(fn_join, chld1); lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: passing data between threads */ chld1 = lwt_create(fn_identity, (void*)0x37337); assert((void*)0x37337 == lwt_join(chld1)); IS_RESET(); /* functional tests: directed yield */ chld1 = lwt_create(fn_null, NULL); lwt_yield(chld1); assert(lwt_info(LWT_INFO_NTHD_ZOMBIES) == 1); lwt_join(chld1); IS_RESET(); }
void * fn_join(void *d) { lwt_t t = (lwt_t)d; void *r; r = lwt_join(d); //TODO change back assert(r == (void*)0x37337); }
/** * @brief Runs the ping/pong test */ void ping_pong_test(){ printf("Starting channels test\n"); //create channel lwt_chan_t main_channel = lwt_chan(0); //create child threads lwt_t ping_lwt = lwt_create_chan(child_ping, main_channel, 0); lwt_t * pong_lwts = (lwt_t *)malloc(sizeof(lwt_t) * ITER); int index; for(index = 0; index < ITER; ++index){ pong_lwts[index] = lwt_create_chan(child_pong, main_channel, 0); } //receive channels lwt_chan_t ping_channel = lwt_rcv_chan(main_channel); lwt_chan_t * pong_channels = (lwt_chan_t *)malloc(sizeof(lwt_chan_t) * ITER); for(index = 0; index < ITER; ++index){ pong_channels[index] = lwt_rcv_chan(main_channel); } //send channels for(index = 0; index < ITER; ++index){ lwt_snd_chan(pong_channels[index], ping_channel); } for(index = 0; index < ITER; ++index){ lwt_snd_chan(ping_channel, pong_channels[index]); } //we're done with the channels lwt_chan_deref(ping_channel); for(index = 0; index < ITER; ++index){ lwt_chan_deref(pong_channels[index]); } lwt_chan_deref(main_channel); free(pong_channels); //join threads lwt_join(ping_lwt); for(index = 0; index < ITER; ++index){ lwt_join(pong_lwts[index]); } free(pong_lwts); }
void test_function_basic() { lwt_t id; IS_RESET(); id = lwt_create(fn_nested_create, 0, 0, 0); lwt_yield(LWT_NULL); printf("join in parent\n"); lwt_join(id); lwt_yield(LWT_NULL); IS_RESET(); }
void test_grpwait(int chsz, int grpsz) { lwt_chan_t cs[grpsz]; lwt_t ts[grpsz]; int i; lwt_cgrp_t g; printf("[TEST] group wait (channel buffer size %d, grpsz %d)\n", chsz, grpsz); g = lwt_cgrp(); assert(g); for (i = 0 ; i < grpsz ; i++) { cs[i] = lwt_chan(chsz); assert(cs[i]); lwt_chan_grant(cs[i]); lwt_chan_t c = lwt_chan(0); ts[i] = lwt_create(fn_grpwait, cs[i], 0, c); lwt_chan_mark_set(cs[i], (void*)lwt_id(ts[i])); lwt_cgrp_add(g, cs[i], LWT_CHAN_RCV); } assert(lwt_cgrp_free(g) == -1); /** * Q: why don't we iterate through all of the data here? * * A: We need to fix 1) cevt_wait to be level triggered, or 2) * provide a function to detect if there is data available on * a channel. Either of these would allows us to iterate on a * channel while there is more data pending. */ for (i = 0 ; i < ((ITER * grpsz)-(grpsz*chsz)) ; i++) { lwt_chan_t c; int r; lwt_chan_dir_t direction; c = lwt_cgrp_wait(g, &direction); assert(c); assert(direction == LWT_CHAN_RCV); r = (int)lwt_rcv(c); assert(r == (int)lwt_chan_mark_get(c)); } for (i = 0 ; i < grpsz ; i++) { lwt_cgrp_rem(g, cs[i]); lwt_join(ts[i]); lwt_chan_deref(cs[i]); } assert(!lwt_cgrp_free(g)); return; }
/** * @brief Runs the merge sort test * Tests being able to create multiple child channels and joining them properly */ void merge_sort_test(){ struct msort_args * args = (struct msort_args *)malloc(sizeof(struct msort_args)); args->data = (int *)malloc(sizeof(int) * MERGE_SZ); args->swap = (int *)malloc(sizeof(int) * MERGE_SZ); args->begin_index = 0; args->end_index = MERGE_SZ; //prep data int index; srand(time(NULL)); printf("Data is: ["); for(index = 0; index < MERGE_SZ; ++index){ args->data[index] = rand(); printf(" %d", args->data[index]); } printf("]\n"); //create channel lwt_chan_t main_channel = lwt_chan(0); //create child worker lwt_t child = lwt_create_chan(msort, main_channel, 0); //receive child channel lwt_chan_t child_channel = lwt_rcv_chan(main_channel); //send args printf("SEND TO CHILDREN\n"); lwt_snd(child_channel, args); printf("SEND COMPLETE\n"); //receive args assert(lwt_rcv(main_channel)); //join child lwt_join(child); //dereference channel printf("child channel\n"); lwt_chan_deref(child_channel); printf("main channel\n"); lwt_chan_deref(main_channel); //validate args int prev = args->data[0]; printf("Sorted data: [ %d", prev); for(index = 1; index < MERGE_SZ; ++index){ assert(args->data[index] >= prev); prev = args->data[index]; printf(" %d", prev); } printf("]\n"); //free data free(args->data); free(args->swap); free(args); }
void * fn_nested_joins(void *d) { lwt_t chld; if (d) { lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); assert(lwt_info(LWT_INFO_NTHD_RUNNABLE) == 1); lwt_die(NULL); } chld = lwt_create(fn_nested_joins, (void*)1); lwt_join(chld); }
void test_multisend(void) { lwt_chan_t c; lwt_t t1, t2; int i, ret[4], sum = 0; struct multisend_arg args[2]; c = lwt_chan(0); assert(c); for (i = 0 ; i < 2 ; i++) { args[i].c = c; args[i].snd_val = i+1; } t1 = lwt_create(fn_snder, &args[0]); //print_sq(&args[0].c); t2 = lwt_create(fn_snder, &args[1]); for (i = 0 ; i < 4 ; i++) { //printf("before receive.\n"); ret[i] = (int)lwt_rcv(c); } lwt_join(t1); lwt_join(t2); for (i = 0 ; i < 4 ; i++) { sum += ret[i]; assert(ret[i] == 1 || ret[i] == 2); } assert(sum == 6); return; }
void test_perf(void) { lwt_t chld1, chld2; int i; unsigned long long start, end; /* Performance tests */ rdtscll(start); for (i = 0 ; i < ITER ; i++) { chld1 = lwt_create(fn_null, NULL); lwt_join(chld1); } rdtscll(end); printf("Overhead for fork/join is %lld\n", (end-start)/ITER); IS_RESET(); chld1 = lwt_create(fn_bounce, (void*)1); chld2 = lwt_create(fn_bounce, NULL); lwt_join(chld1); lwt_join(chld2); IS_RESET(); }
void* fn_nested_create(void* data, lwt_chan_t c) { int param = (int)data; lwt_t id; if(param< 5) { printf("create: %d\n", param); id = lwt_create(fn_nested_create, (void*)(param+1), 0, 0); lwt_yield(id); printf("join: %d\n", param); lwt_join(id); } lwt_yield(LWT_NULL); return NULL; }
void multiple_channels_test_v2(){ lwt_chan_t main_channel = lwt_chan(ITER); lwt_t * threads = (lwt_t *)malloc(sizeof(lwt_t) * ITER); int index; for(index = 0; index < ITER; ++index){ threads[index] = lwt_create_chan(child_multiple_channels, main_channel, 0); } for(index = 0; index < ITER; ++index){ lwt_join(threads[index]); } int count = 0; for(index = 0; index < ITER; ++index){ printf("CURRENT INDEX: %d\n", index); count += (int)lwt_rcv(main_channel); } lwt_chan_deref(main_channel); free(threads); assert(count == 3240); printf("COUNT: %d\n", count); }
void test_perf_async_steam(int chsz) { lwt_chan_t from; lwt_t t; int i; unsigned long long start, end; async_sz = chsz; assert(RUNNABLE == lwt_current()->state); from = lwt_chan(chsz); assert(from); lwt_chan_grant(from); lwt_chan_t cfix = lwt_chan(0); t = lwt_create(fn_async_steam, from, 0, cfix); assert(lwt_info(LWT_INFO_NTHD_RUNNABLE) == 2); rdtscll(start); for (i = 0 ; i < ITER ; i++) assert(i+1 == (int)lwt_rcv(from)); rdtscll(end); printf("[PERF] %lld <- asynchronous snd->rcv (buffer size %d)\n", (end-start)/(ITER*2), chsz); lwt_join(t); }
void test_perf_channels(void) { lwt_chan_t from, to; lwt_t t; int i; unsigned long long start, end; assert(_TCB_ACTIVE == lwt_current()->state); from = lwt_chan(0); assert(from); t = lwt_create(fn_chan, from); to = lwt_rcv_chan(from); rdtscll(start); for (i = 0 ; i < ITER ; i++) { assert(1 == (int)lwt_rcv(from)); lwt_snd(to, (void*)2); } lwt_chan_deref(to); rdtscll(end); printf("Overhead for snd/rcv is %lld\n", (end-start)/(ITER*2)); lwt_join(t); }
/* #define IS_RESET() \ assert( lwt_info(LWT_INFO_NTHD_RUNNABLE) == 1 && \ lwt_info(LWT_INFO_NTHD_ZOMBIES) == 0 && \ lwt_info(LWT_INFO_NTHD_BLOCKED) == 0) */ int main(void) { lwt_t chld1, chld2; int i; unsigned long long start, end; /* Performance tests */ rdtscll(start); for (i = 0 ; i < ITER ; i++) { chld1 = lwt_create(fn_null, NULL); lwt_join(chld1); } rdtscll(end); printf("Overhead for fork/join is %lld\n", (end-start)/ITER); //IS_RESET(); chld1 = lwt_create(fn_bounce, NULL); chld2 = lwt_create(fn_bounce, NULL); lwt_join(chld1); lwt_join(chld2); //IS_RESET(); /* functional tests: scheduling */ lwt_yield(LWT_NULL); chld1 = lwt_create(fn_sequence, (void*)1); chld2 = lwt_create(fn_sequence, (void*)2); lwt_join(chld2); lwt_join(chld1); //IS_RESET(); /* functional tests: join */ chld1 = lwt_create(fn_null, NULL); lwt_join(chld1); //IS_RESET(); chld1 = lwt_create(fn_null, NULL); lwt_yield(LWT_NULL); lwt_join(chld1); //IS_RESET(); chld1 = lwt_create(fn_nested_joins, NULL); lwt_join(chld1); //IS_RESET(); /* functional tests: join only from parents */ chld1 = lwt_create(fn_identity, (void*)0x37337); chld2 = lwt_create(fn_join, chld1); lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); lwt_join(chld2); lwt_join(chld1); //IS_RESET(); /* functional tests: passing data between threads */ chld1 = lwt_create(fn_identity, (void*)0x37337); //TODO assert((void*)0x37337 == lwt_join(chld1)); //IS_RESET(); /* functional tests: directed yield */ chld1 = lwt_create(fn_null, NULL); lwt_yield(chld1); //assert(lwt_info(LWT_INFO_NTHD_ZOMBIES) == 1); lwt_join(chld1); //IS_RESET(); //TODO assert(thd_cnt == ITER+12); }
/** * @brief Merge sort in parallel * @param main_channel The channel from the main thread * @return 0 if successful * @note Adapted from wikipedia: http://en.wikipedia.org/wiki/Merge_sort#Parallel_merge_sort) */ void * msort(lwt_chan_t main_channel){ //create channel lwt_chan_t my_channel = lwt_chan(0); //send channel back lwt_snd_chan(main_channel, my_channel); //receive args struct msort_args * args = lwt_rcv(my_channel); if(args->end_index - args->begin_index < 2){ //send channels lwt_snd(main_channel, args); //dereference channels lwt_chan_deref(my_channel); lwt_chan_deref(main_channel); return 0; } int middle_index = (args->begin_index + args->end_index)/2; struct msort_args * l_args = (struct msort_args *)malloc(sizeof(struct msort_args)); l_args->data = args->data; l_args->swap = args->swap; l_args->begin_index = args->begin_index; l_args->end_index = middle_index; struct msort_args * r_args = (struct msort_args *)malloc(sizeof(struct msort_args)); r_args->data = args->data; r_args->swap = args->swap; r_args->begin_index = middle_index; r_args->end_index = args->end_index; //create threads lwt_t l_lwt = lwt_create_chan(msort, my_channel, 0); lwt_t r_lwt = lwt_create_chan(msort, my_channel, 0); //receive child channels lwt_chan_t l_chan = lwt_rcv_chan(my_channel); lwt_chan_t r_chan = lwt_rcv_chan(my_channel); //send args lwt_snd(l_chan, l_args); lwt_snd(r_chan, r_args); //receive new args assert(lwt_rcv(my_channel)); assert(lwt_rcv(my_channel)); //join threads assert(lwt_join(l_lwt) == 0); assert(lwt_join(r_lwt) == 0); //dereference channels lwt_chan_deref(l_chan); lwt_chan_deref(r_chan); printf("DEREF MY CHILD CHANNEL: %d\n", (int)my_channel); lwt_chan_deref(my_channel); //free args free(l_args); free(r_args); //merge int index; int l_head = args->begin_index; int r_head = middle_index; for(index = args->begin_index; index < args->end_index; ++index){ if(l_head < middle_index && (r_head >= args->end_index || args->data[l_head] <= args->data[r_head])){ args->swap[index] = args->data[l_head]; l_head++; } else{ args->swap[index] = args->data[r_head]; r_head++; } } //copy swap into data for(index = args->begin_index; index < args->end_index; ++index){ args->data[index] = args->swap[index]; } //send updated args back lwt_snd(main_channel, args); //dereference main channel lwt_chan_deref(main_channel); return 0; }