/** * @brief Receives a count, updates it and sends it back * @param main_channel The channel from the main thread * @return 0 if successful */ void * child_pong(lwt_chan_t main_channel){ printf("Starting child function 2\n"); //create the channel lwt_chan_t child_2_channel = lwt_chan(0); //send it to parent lwt_snd_chan(main_channel, child_2_channel); //receive child 1 channel lwt_chan_t child_1_channel = lwt_rcv_chan(child_2_channel); int count = (int)lwt_rcv(child_2_channel); while(count < 100){ printf("CHILD 2 COUNT: %d\n", count); //update count count++; printf("SENDING COUNT TO CHILD 1\n"); lwt_snd(child_1_channel, (int)count); if(count >= 100){ break; } printf("RECEVING COUNT FROM CHILD 1\n"); count = (int)lwt_rcv(child_2_channel); } lwt_chan_deref(main_channel); lwt_chan_deref(child_1_channel); lwt_chan_deref(child_2_channel); printf("CHILD 2 COUNT: %d\n", count); 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* grp_wait_rcver(void* param, lwt_chan_t c) { lwt_chan_t cc = lwt_chan(10); lwt_snd_chan((lwt_chan_t)param, cc); lwt_chan_t cc2 = lwt_rcv_chan(cc); lwt_cgrp_t cg = lwt_cgrp(); int i=0; for(i=0; i < ITER; i++) { lwt_chan_t cci = lwt_chan(3); assert(lwt_cgrp_add(cg, cci, LWT_CHAN_RCV) == 0); printf("in_main: thread %d: sending channel %d\n", current_tid, i); lwt_snd_chan(cc2, cci); printf("in_main: thread %d: channel %d sent\n", current_tid, i); } while(i>0) { printf("in_main: thread %d: group waiting\n", current_tid); lwt_chan_t cci = lwt_cgrp_wait(cg, LWT_CHAN_RCV); printf("in_main: thread %d: cci rcved, start rcv data\n", current_tid); i = (int)lwt_rcv(cci); printf("in_main: thread %d: i rcved: %d\n", current_tid, i); } return NULL; }
/** * @brief Ping channel test * @param main_channel The channel from the main thread * @return 0 if successful * Sends count out to many siblings; tests that they receive and update it properly */ void * child_ping(lwt_chan_t main_channel){ printf("Starting child ping channel\n"); //create the channel lwt_chan_t child_1_channel = lwt_chan(0); //send it to parent lwt_snd_chan(main_channel, child_1_channel); //receive children channels lwt_chan_t * children = (lwt_chan_t *)malloc(sizeof(lwt_chan_t) * ITER); int count = 1; int index; for(index = 0; index < ITER; ++index){ children[index] = lwt_rcv_chan(child_1_channel); } while(count < 100){ printf("PING COUNT: %d\n", count); //send count for(index = 0; index < ITER; ++index){ lwt_snd(children[index], (void *)count); } printf("PONG COUNT\n"); //receive count count = (int)lwt_rcv(child_1_channel); for(index = 1; index < ITER; ++index){ assert(count == (int)lwt_rcv(child_1_channel)); } if(count >= 100){ break; } //update count count++; } lwt_chan_deref(main_channel); for(index = 0; index < ITER; ++index){ lwt_chan_deref(children[index]); } free(children); lwt_chan_deref(child_1_channel); printf("CHILD 1 COUNT: %d\n", count); return 0; }
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_chan(lwt_chan_t to) { lwt_chan_t from; int i; from = lwt_chan(0); lwt_snd_chan(to, from); assert(from->snd_cnt); for (i = 0 ; i < ITER ; i++) { lwt_snd(to, (void*)1); assert(2 == (int)lwt_rcv(from)); } lwt_chan_deref(from); return NULL; }
void multiple_channels_test_v3(){ 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, LWT_NOJOIN); } 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_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 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* kthd_rcv_print(void* data, lwt_chan_t rcv_c) { printf("in kthd: data: %d and channel 0x%08x rcvd!\n", (int)data, (unsigned int)rcv_c); lwt_chan_t cc = lwt_chan(0); lwt_chan_t main_c = lwt_rcv_chan(rcv_c); lwt_snd_chan(main_c, cc); /* void* pkg = lwt_rcv(cc); printf("in kthd: data %d rcvd!\n", (int)pkg); pkg = lwt_rcv(cc); printf("in kthd: data %d rcvd!\n", (int)pkg); pkg = lwt_rcv(cc); printf("in kthd: data %d rcvd!\n", (int)pkg); pkg = lwt_rcv(cc); printf("in kthd: data %d rcvd!\n", (int)pkg); pkg = lwt_rcv(cc); printf("in kthd: data %d rcvd!\n", (int)pkg); */ lwt_cgrp_t cg = lwt_cgrp(); lwt_cgrp_add(cg, cc, LWT_CHAN_RCV); lwt_chan_t actived; printf("====start wait====\n"); while((actived = lwt_cgrp_wait(cg, LWT_CHAN_RCV)) != NULL) { assert(actived == cc); void* pkg = lwt_rcv(actived); printf("in kthd: data %d rcvd!\n", (int)pkg); } printf("====end wait====\n"); return NULL; }
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_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); }
/** * @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; }