/* thread routine */ void *t_routine(void *arg) { int li, sum; SortedListElement_t *elements = (SortedListElement_t *)arg; // hash and insert elements into a sublist for (int k = 0; k < iter_count; k++) { li = hash_element(&elements[k]) % list_count; //get list index lock_sublist(li); SortedList_insert(&sublist[li], &elements[k]); unlock_sublist(li); } // lock and enumerate all lists sum = 0; for (int k = 0; k < list_count; k++) { lock_sublist(k); sum += SortedList_length(&sublist[k]); unlock_sublist(k); } // hash and remove deleted for (int k = 0; k < iter_count; k++) { li = hash_element(&elements[k]) % list_count; //get list index lock_sublist(li); SortedList_delete(SortedList_lookup(&sublist[li], elements[k].key)); unlock_sublist(li); } return NULL; }
void test_length() { SortedList_t list; SortedListElement_t element[100]; list_init(&list); for (int i = 0;; i++) { TEST_CHECK(SortedList_length(&list) == i); if (i >= 100) break; element_set_randkey(&element[i]); SortedList_insert(&list, &element[i]); } }
void test_corrupt_length() { SortedList_t list; SortedListElement_t element[100]; list_init(&list); for (int i = 0; i < 100; i++) { element_set_randkey(&element[i]); SortedList_insert(&list, &element[i]); } element[99].next = element[99].prev; // TODO: setting to NULL causes segfault TEST_CHECK(SortedList_length(&list) == -1); }
void test_delete() { SortedList_t list; list_init(&list); SortedListElement_t elements[26]; for (int i = 0; i < 26; i++) { char c[] = { (char)(i+97), 0 }; element_set_key(&elements[i], c); SortedList_insert(&list, &elements[i]); } TEST_CHECK(SortedList_delete(&elements[25]) == 0); TEST_CHECK(SortedList_length(&list) == 25); //TEST_CHECK(is_sorted(&list)); SortedListElement_t *e = list.next; while (e != &list) { TEST_CHECK(strcmp(e->key, elements[25].key) != 0); e = e->next; } }
int main(int argc, char** argv){ // for loop counter int i = 0; // c holds return value of getopt_long int c; char* yield = NULL; struct timespec startTime, endTime; long long time_threads_create = 0; struct timespec starttime_threads_create, endtime_threads_create; // Parse options while (1) { int option_index = 0; static struct option long_options[] = { // SUBCOMMAND {"iterations", optional_argument, 0, 'i' }, {"threads", optional_argument, 0, 't' }, {"yield", optional_argument, 0, 'y' }, {"sync", optional_argument, 0, 's'}, {"lists", optional_argument, 0, 'l'}, {0,0,0,0} }; // get the next option c = getopt_long(argc, argv, "", long_options, &option_index); // break when there are no further options to parse if (c == -1) break; switch (c) { //SWITCH STATEMENT case 'i': if(optarg != NULL) iterations = atoi(optarg); break; case 't': if(optarg != NULL) nThreads = atoi(optarg); break; case 'y': if(optarg != NULL) yield= optarg; // 012345 int i = 0; int run = 1; while(run){ switch((int)yield[i]){ case 'i': opt_yield |= INSERT_YIELD; // printf("y=insert\n"); break; case 'd': opt_yield |= DELETE_YIELD; // printf("y=delte\n"); break; case 's': opt_yield |= SEARCH_YIELD; // printf("y=search\n"); break; default: run = 0; } i++; } break; case 's': if(optarg != NULL){ switch((int)optarg[0]){ case 'm': MUTEX = 1; break; case 's': SPIN = 1; break; } } break; case 'l': if(optarg != NULL) nLists = atoi(optarg); // printf("%d\n",nLists ); break; } } // initialize an empty list( with dummy) // list = malloc(sizeof(SortedList_t**)) list = malloc(sizeof(SortedList_t)*nLists); // initialize mutexes if(MUTEX){ pthread_mutex_init(&len_mutex, NULL); mutex = malloc(sizeof(pthread_mutex_t) * nLists); for(i = 0; i != nLists; i++) pthread_mutex_init(&(mutex[i]), NULL); } // initialize spinlocks if(SPIN){ len_spinlock = 0; spinlock = malloc(sizeof(int) * nLists); for(i = 0; i != nLists; i++) spinlock[i] = 0; } for(i = 0; i != nLists; i++){ list[i].key = NULL; list[i].prev = &list[i]; list[i].next = &list[i]; } // SortedList_t l; // list = &l; // list->key = NULL; // create and initializes the required number nElements = nThreads * iterations; elements = malloc(sizeof(SortedListElement_t) * nElements); if(elements == NULL){ fprintf(stderr, "Error in allocating space for elements\n"); } keys= malloc(sizeof(char*) * nElements); if(elements == NULL){ fprintf(stderr, "Error in allocating space for keys\n"); } for(i = 0; i != nElements; i++){ int size = rand() % 15; keys[i] = malloc(sizeof(char) * size); if(keys[i] == NULL){ fprintf(stderr, "Error in allocating space for keys[%d]\n", i); } gen_random(keys[i],size); } for(i = 0 ; i != nElements; i++){ elements[i].key = keys[i]; elements[i].next = NULL; elements[i].prev = NULL; } //create threads pthread_t * thread_array = malloc(sizeof(pthread_t)* nThreads); // start time clock_gettime(CLOCK_MONOTONIC , &startTime); for(i = 0; i < nThreads; i++) { clock_gettime(CLOCK_MONOTONIC , &starttime_threads_create); int *arg = malloc(sizeof(*arg)); *arg = i; // measure the time it takes to create thread int ret = pthread_create(&thread_array[i], NULL, threadfunc, (void *) arg); //to create thread clock_gettime(CLOCK_MONOTONIC , &endtime_threads_create); long long startTime_ = (long long ) starttime_threads_create.tv_sec * pow(10,9) + starttime_threads_create.tv_nsec; long long endTime_ = (long long ) endtime_threads_create.tv_sec * pow(10,9) + endtime_threads_create.tv_nsec; time_threads_create += endTime_ - startTime_; // printf("time_threads = %d\n", time_threads_create); if (ret != 0) { //error handling fprintf(stderr, "Error creating thread %d\n", i); exit(1); } } //wait for all to finish //int pthread_join(pthread_t thread, void **retval); //waits for thread to terminate for(i = 0; i < nThreads; i++) { int ret = pthread_join(thread_array[i], NULL); if (ret != 0) { //error handling fprintf(stderr, "Error joining thread %d\n", i); exit(1); } //need for loop to wait for all //also do error handling } // check th length of the list //int clock_gettime(clocked_t clk_id , struct timespec* tp) clock_gettime(CLOCK_MONOTONIC , &endTime); int finalLength = SortedList_length(list); if( finalLength != 0) { fprintf(stderr, "Error! Final list length is not zero!\n"); exit(1); } // print // get avarage length of a sublist. // int avgLen = nElements / nLists; long num_ops = nThreads * (iterations * 2 + 1) ; printf("%d threads x (%d iterations x (ins + lookup/del) + len) = %d operations\n", nThreads, iterations, num_ops); if(counter != 0){ fprintf(stderr, "ERROR: final count = %d\n", counter); } long long startTimel = (long long ) startTime.tv_sec * pow(10,9) + startTime.tv_nsec; long long endTimel = (long long ) endTime.tv_sec * pow(10,9) + endTime.tv_nsec; long long total_time = endTimel - startTimel; printf("elapsed time: %d\n", total_time); printf("overhead time: %d\n", time_threads_create); // long long avg = (total_time - time_threads_create)/ num_ops; long long avg = (total_time )/ num_ops; printf("per operation: %d ns\n", avg); // printf("EXit with %d\n",exit_status ); // free free(elements); for(i = 0; i != nElements; i++){ free(keys[i]); } free(keys); free(thread_array); free(list); free(spinlock); free(mutex); exit(0); }
void* threadfunc(void* ind){ int index = *((int*) ind); free(ind); int length; int i; // insert each element for(i = 0; i < iterations; ++i) { int j = hash(elements[index*(iterations) + i].key); // printf("j=%d\n", j); if(MUTEX){ int ret = pthread_mutex_lock(&(mutex[j])); SortedList_insert(&list[j], &elements[index*(iterations) + i]); // printf("releasing mutex for insert, mutex=%d\n", mutex); pthread_mutex_unlock(&(mutex[j])); } else if(SPIN){ while(__sync_lock_test_and_set(&(spinlock[j]),1)); SortedList_insert(&list[j], &elements[index*(iterations) + i]); // SortedList_display(list); __sync_lock_release(&(spinlock[j])); }else{ SortedList_insert(&list[j], &elements[index*(iterations) + i]); } } // get length if(MUTEX){ // lock before entering "locking" process pthread_mutex_lock(&len_mutex); for(i = 0; i != nLists; i++) pthread_mutex_lock(&(mutex[i])); // critical section length = SortedList_length(list); for(i = 0; i != nLists; i++) pthread_mutex_unlock(&(mutex[i])); pthread_mutex_unlock(&len_mutex); }else if(SPIN){ // lock before entering "locking" process while(__sync_lock_test_and_set(&len_spinlock,1)); for(i = 0; i != nLists; i++) while(__sync_lock_test_and_set(&(spinlock[i]),1)); length = SortedList_length(list); for(i = 0; i != nLists; i++) __sync_lock_release(&(spinlock[i])); __sync_lock_release(&len_spinlock); }else{ length = SortedList_length(list); } // printf("length = %d\n", length); // look up/ delete for(i = 0; i < iterations; ++i) { int j = hash(elements[index*(iterations) + i].key); SortedListElement_t* target; if(MUTEX){ pthread_mutex_lock(&(mutex[j])); target = SortedList_lookup(&list[j], elements[index*(iterations) + i].key); if(target == NULL){ printf("should never be here.\b"); pthread_mutex_unlock(&(mutex[j])); continue; } SortedList_delete(target); pthread_mutex_unlock(&(mutex[j])); }else if(SPIN){ while(__sync_lock_test_and_set(&(spinlock[j]),1)); target = SortedList_lookup(&list[j], elements[index*iterations + i].key); if(target == NULL){ printf("should never be here.\b"); __sync_lock_release(&(spinlock[j])); continue; } SortedList_delete(target); __sync_lock_release(&(spinlock[j])); }else{ // printf("lookup\n"); // printf("j=%d, key=%s\n", j,elements[index*(iterations) + i].key); target= SortedList_lookup(&list[j], elements[index*iterations + i].key); // printf("\tDONE loopup\n"); if(target == NULL){ printf("should never be here.\b"); continue; } // printf("delete\n"); SortedList_delete(target); // printf("\tDONE delete\n"); } } // SortedList_display(list); // length = SortedList_length(list); }
int main(int argc, char* argv[]){ opt_yield = 0; static struct option longOptions[] = { {"threads", required_argument, NULL, 't'}, {"iterations", required_argument, NULL, 'i'}, {"yield", required_argument, NULL, 'y'}, {"sync", required_argument, NULL, 's'}, {0, 0, 0, 0} }; // Processes the arguments passed in while(1){ int index = 0; int c = getopt_long(argc, argv, "", longOptions, &index); int i; if(c == -1) break; switch(c){ case 't': numThreads = atoi(optarg); // atoi changes a string to a number if possible break; case 'i': iterations = atoi(optarg); // atoi changes a string to a number if possible break; case 's': // for the case of sync, we find the sync_mechanism by looking at the first character sync_mechanism = optarg[0]; break; case 'y': // For the case of yield, the arguments can only be ids. Based on the argument, we set opt_yield accordingly for(i = 0; i < strlen(optarg); i++){ if(optarg[i] == 'i'){ opt_yield |= 0x01; } else if(optarg[i] == 'd'){ opt_yield |= 0x02; } else if(optarg[i] == 's'){ opt_yield |= 0x04; } else{ exit(-1); } } } } // Initializes the linked list. We will be using a circular linked list with a dummy node head = (SortedList_t*) malloc(sizeof(SortedList_t)); head->next = head; head->prev = head; char *key = 0; head->key = key; // Generates random strings of keylen characters int n = numThreads*iterations; char* keylist = (char*) malloc( (keylen + 1) * n * sizeof(char)); int nchars = 1 + 'z' - '0'; // number of characters between 0 and z int counter = 0; for(int i = 0; i < ((keylen + 1) * n); i++){ counter++; if(counter%(keylen + 1) == 0) // on the (keylen+1)th character, keylist[i] = 0; // set as nullbyte else keylist[i] = '0' + rand()%nchars; // random character offset from 0 in ascii } // Generates numThreads*iterations number of nodes SortedListElement_t *nodes = (SortedListElement_t*) malloc( n * sizeof(SortedListElement_t)); for(int i=0; i<n; i++){ nodes[i].key = keylist + i*(keylen + 1); // assigns a string to each node } // Dynamically creates threads based on what we passed into the threads argument pthread_t* tid = (pthread_t*) malloc(sizeof(pthread_t)*numThreads); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_mutex_init(&mutex, NULL); // collect start time struct timespec my_start_time; clock_gettime(CLOCK_MONOTONIC, &my_start_time); // start threads for(int i=0; i < numThreads; i++){ if( pthread_create(&tid[i] , &attr, thread_function, (void*) (nodes+(i*iterations)) ) ){ fprintf(stderr, "Error creating threads"); exit(1); } } pthread_attr_destroy(&attr); // wait for all the threads to finish for(int i=0; i < numThreads; i++){ if( pthread_join(tid[i], NULL) ){ fprintf(stderr, "Error joining threads"); exit(1); } } // collect end time struct timespec my_end_time; clock_gettime(CLOCK_MONOTONIC, &my_end_time); free(keylist); free(nodes); free(tid); // calculates the elapsed time in nanoseconds long long elapsed_time = (my_end_time.tv_sec - my_start_time.tv_sec) * 1000000000; elapsed_time += my_end_time.tv_nsec; elapsed_time -= my_start_time.tv_nsec; // Report data int exit_status = 0; int operations = numThreads * iterations * 2; long long time_per_operation = elapsed_time / operations; fprintf(stdout, "%d threads x %d iterations x (insert + lookup/delete) = %d operations\n", numThreads, iterations, operations); if(SortedList_length(head) != 0){ fprintf(stderr, "List is not empty at the end\n"); exit_status = 1; } fprintf(stdout, "elapsed time: %lld\n", elapsed_time); fprintf(stdout, "per operation: %lld\n", time_per_operation); // Exit exit(exit_status); }
void* thread_function(void* arg){ SortedListElement_t* node = (SortedListElement_t*) arg; // Do the insertion for(int i=0; i<iterations; i++){ switch(sync_mechanism){ case 'n': SortedList_insert(head, node + i); break; case 'm': pthread_mutex_lock(&mutex); SortedList_insert(head, node + i); pthread_mutex_unlock(&mutex); break; case 's': while(__sync_lock_test_and_set(&lock, 1) == 1); SortedList_insert(head, node + i); __sync_lock_release(&lock); default: break; } } // Get the list length for(int i=0; i<iterations; i++){ switch(sync_mechanism){ case 'n': SortedList_length(head); break; case 'm': pthread_mutex_lock(&mutex); SortedList_length(head); pthread_mutex_unlock(&mutex); break; case 's': while(__sync_lock_test_and_set(&lock, 1) == 1); SortedList_length(head); __sync_lock_release(&lock); default: break; } } // Looks up and deletes each of the keys it has previously inserted for(int i=0; i<iterations; i++){ SortedListElement_t* temp; switch(sync_mechanism){ case 'n': temp = SortedList_lookup(head, node[i].key); SortedList_delete(node+i); break; case 'm': pthread_mutex_lock(&mutex); temp = SortedList_lookup(head, node[i].key); SortedList_delete(node+i); pthread_mutex_unlock(&mutex); break; case 's': while(__sync_lock_test_and_set(&lock, 1) == 1); temp = SortedList_lookup(head, node[i].key); SortedList_delete(node+i); __sync_lock_release(&lock); default: break; } } return NULL; }
int main(int argc, char* argv[]) { //iterators long long i; int j; //used to store the input yield string to be parsed and eventually modify the extern yield char *yield; //take parameters for options threads, iterations, yields, syncs opterr = 0; int options; while(1) { static struct option long_options[] = { {"threads", required_argument, 0, 't'}, {"iterations", required_argument, 0, 'i'}, {"yield", required_argument, 0, 'y'}, {"sync", required_argument, 0, 's'}, {"lists", required_argument, 0, 'l'} }; int option_index = 0; options = getopt_long(argc, argv, "", long_options, &option_index); if(options == -1) break; switch(options) { case 0: break; case 't': numthreads = atoi(optarg); break; case 'i': numiterations = atoi(optarg); break; case 'l': numlists = atoi(optarg); break; case 'y': if(optarg) yield = optarg; else { perror("Invalid argument sent to --yield. Valid options are [--yield=ids], where any inclusion of i, d, or s is allowed"); exit(1); } i = 0; int run = 1; while(run) { switch(yield[i]) { case 'i': //printf("i\n"); opt_yield |= INSERT_YIELD; break; case 'd': //printf("d\n"); opt_yield |= DELETE_YIELD; break; case 's': //printf("s\n"); opt_yield |= SEARCH_YIELD; break; default: //printf("what\n"); run = 0; break; } i++; } break; case 's': if(strcmp(optarg, "m") == 0) { which_lock = 'm'; //pthread_mutex_init(&my_mutex, NULL); //in 2C need to do for multiple lists } else if(strcmp(optarg, "s") == 0) which_lock = 's'; else { perror("Invalid argument sent to --sync. Valid options are [--sync=m] and [--sync=c"); exit(1); } break; case '?': perror("Invalid option fed. Valid options are [--threads=<numthreads>], [--iterations=<numiterations>], [--lists=<numlists>], [--yield=<X>]"); perror("where <numthreads>, <numiterations>, <numlists> are integers and X is a string containing 'ids'."); exit(1); default: perror("You should never get here"); exit(1); } } //initialize numlists empty lists heads head = malloc(sizeof(SortedList_t) * numlists); for(i = 0; i != numlists; i++) { head[i].next = &head[i]; head[i].prev = &head[i]; head[i].key = NULL; } //initialize arrays of locks if(which_lock == 'm') { my_mutex = malloc(sizeof(pthread_mutex_t) * numlists); for(i = 0; i != numlists; i++) pthread_mutex_init(&my_mutex[i], NULL); } else if(which_lock == 's') { spinlock = malloc(sizeof(int) * numlists); } else if(which_lock == 0) { //do absolutely nothing; } else { perror("which_lock should be ONLY 'm', 's', or 0. otherwise, something is wrong"); exit(1); } //initialize essentially a static array of characters which the key's values will point to char ASCII33To126[93]; for (i = 0; i != 93; i++) ASCII33To126[i] = i + 33; //create and initialize w/ random keys required number of list elements //this is equal to (number of threads) * (number of iterations) long long numListElements = numthreads * numiterations; //allocate space for each list element structure elements = malloc(numListElements * sizeof(SortedListElement_t)); //allocate space for each pointer to the key for each list element structue keys = malloc(numListElements * sizeof(char*)); for (i = 0; i != numListElements; i++) { //generate each key. we ARBITRARILY use a key length 10 for each keys[i] = malloc(sizeof(char*) * 10); for (j = 0; j != 10; j++) { int character = rand() % 93; keys[i][j] = ASCII33To126[character]; } elements[i].key = keys[i]; elements[i].next = NULL; elements[i].prev = NULL; } //store threads here pthread_t pthreadarray[numthreads]; //collect start time struct timespec my_start_time; clock_gettime(CLOCK_MONOTONIC, &my_start_time); //starts threads for(i = 0; i != numthreads; i++) { //pass i, thread number; each will use this to get which element segment its working w/ int ret = pthread_create(&(pthreadarray[i]), NULL, (void *) &thread_routine, (void *)i); if(ret != 0) { fprintf(stderr, "failed to create thread %i\n", i); exit(1); } } //waits for threads to quit for(i = 0; i != numthreads; i++) { int ret = pthread_join(pthreadarray[i], NULL); } //collect end time struct timespec my_end_time; clock_gettime(CLOCK_MONOTONIC, &my_end_time); //get the final length of the WHOLE LIST (sum of all sublists) and output error if size != 0 int final_listlen = 0; for(i = 0; i != numlists; i++) final_listlen += SortedList_length(&head[i]); if(final_listlen != 0) fprintf(stderr, "ERROR: list length = %i\n", final_listlen); long long numops = numthreads*numiterations*2; printf("%i threads x %i iterations x (insert + lookup/delete) = %i operations\n", numthreads, numiterations, numops); //calculate the elapsed time long long my_elapsed_time_in_ns = (my_end_time.tv_sec - my_start_time.tv_sec) * 1000000000; my_elapsed_time_in_ns += my_end_time.tv_nsec; my_elapsed_time_in_ns -= my_start_time.tv_nsec; //report data printf("elapsed time: %i nanoseconds\n", my_elapsed_time_in_ns); printf("per operation: %g nanoseconds\n\n", (double) ( (long double) my_elapsed_time_in_ns / numops ) ); //exit with proper exit code depending on if there was an error in the whole list thingy if(final_listlen != 0) exit(0); else exit(1); }
void thread_routine(void * arg) { long long threadID = (long long) arg; //printf("%i\n", threadID); int k; //insert if(which_lock == 'm') { for (k = 0; k != numiterations; k++) { long long index = (threadID * numiterations) + k; int sublistindex = getSubListIndex(&elements[index]); pthread_mutex_lock(&my_mutex[sublistindex]); SortedList_insert(&head[sublistindex], &elements[index]); pthread_mutex_unlock(&my_mutex[sublistindex]); } } else if(which_lock == 's') { for (k = 0; k != numiterations; k++) { long long index = (threadID * numiterations) + k; int sublistindex = getSubListIndex(&elements[index]); while(__sync_lock_test_and_set(&spinlock[sublistindex], 1)); SortedList_insert(&head[sublistindex], &elements[index]); __sync_lock_release(&spinlock[sublistindex]); } } else if(which_lock == 0) { //insert set of pre-allocated elements into shared list for (k = 0; k != numiterations; k++) { long long index = (threadID * numiterations) + k; int sublistindex = getSubListIndex(&elements[index]); SortedList_insert(&head[sublistindex], &elements[index]); } } else { perror("shouldn't get here"); exit(1); } int listlen = 0; //get the sum of the lengths of all sublists = the length of the ENTiRE list at THIS moment if(which_lock == 'm') { for(k = 0; k != numlists; k++) { pthread_mutex_lock(&my_mutex[k]); listlen += SortedList_length(&head[k]); pthread_mutex_unlock(&my_mutex[k]); } } else if(which_lock == 's') { for(k = 0; k != numlists; k++) { while(__sync_lock_test_and_set(&spinlock[k], 1)); listlen += SortedList_length(&head[k]); __sync_lock_release(&spinlock[k]); } } else if(which_lock == 0) { //get list length for(k = 0; k != numlists; k++) listlen += SortedList_length(&head[k]); } else { perror("shouldn't get here"); exit(1); } //lookup + delete if(which_lock == 'm') { for(k = 0; k != numiterations; k++) { long long index = (threadID*numiterations) + k; int sublistindex = getSubListIndex(&elements[index]); pthread_mutex_lock(&my_mutex[sublistindex]); //looks up SortedListElement_t* node = SortedList_lookup(&head[sublistindex], keys[index]); //deletes int ret = SortedList_delete(node); pthread_mutex_unlock(&my_mutex[sublistindex]); } } else if(which_lock == 's') { for(k = 0; k != numiterations; k++) { SortedListElement_t* node; long long index = (threadID*numiterations) + k; int sublistindex = getSubListIndex(&elements[index]); while(__sync_lock_test_and_set(&spinlock[sublistindex], 1)); //looks up node = SortedList_lookup(&head[sublistindex], keys[index]); //deletes int ret = SortedList_delete(node); __sync_lock_release(&spinlock[sublistindex]); } } else if(which_lock == 0) { //looks up and deletes each of the prior keys entered for(k = 0; k != numiterations; k++) { long long index = (threadID*numiterations) + k; int sublistindex = getSubListIndex(&elements[index]); //looks up SortedListElement_t* node = SortedList_lookup(&head[sublistindex], keys[index]); //deletes int ret = SortedList_delete(node); } } else { perror("shouldn't get here"); exit(1); } pthread_exit(NULL); }
void *bthread(void *void_ptr) { struct thread_info ptr = *((struct thread_info*)void_ptr); size_t i = (ptr.thread_number)*(ptr.itr); while (i < (ptr.thread_number + 1)*(ptr.itr)) { if (sync_flag == '_') { SortedList_insert(ptr.head, &(ptr.sortedarray[i])); } else if (sync_flag == 'm') { pthread_mutex_lock(&mutex); SortedList_insert(ptr.head, &(ptr.sortedarray[i])); pthread_mutex_unlock(&mutex); } else if (sync_flag == 's') { while (__sync_lock_test_and_set(&locker, 1) == 1); SortedList_insert(ptr.head, &(ptr.sortedarray[i])); __sync_lock_release(&locker); } i++; } if (sync_flag == '_') { if (SortedList_length(ptr.head) < 0) exit(1); } else if (sync_flag == 'm') { pthread_mutex_lock(&mutex); if (SortedList_length(ptr.head) < 0) exit(1); pthread_mutex_unlock(&mutex); } else if (sync_flag == 's') { while (__sync_lock_test_and_set(&locker, 1) == 1); if (SortedList_length(ptr.head) < 0) exit(1); __sync_lock_release(&locker); } size_t j = (ptr.thread_number)*(ptr.itr); while (j < (ptr.thread_number + 1)*(ptr.itr)) { if (sync_flag == '_') { if (SortedList_lookup(ptr.head, ptr.sortedarray[j].key) == 0) exit(2); if (SortedList_delete(&(ptr.sortedarray[j])) == 1) exit(2); } else if (sync_flag == 'm') { pthread_mutex_lock(&mutex); if (SortedList_lookup(ptr.head, ptr.sortedarray[j].key) == 0) exit(2); if (SortedList_delete(&(ptr.sortedarray[j])) == 1) exit(2); pthread_mutex_unlock(&mutex); } else if (sync_flag == 's') { while (__sync_lock_test_and_set(&locker, 1) == 1); if (SortedList_lookup(ptr.head, ptr.sortedarray[j].key) == 0) exit(2); if (SortedList_delete(&(ptr.sortedarray[j])) == 1) exit(2); __sync_lock_release(&locker); } j++; } return NULL; }
int main(int argc, char *argv[]) { static struct option long_options[] = { { "threads", required_argument, 0, 't' }, { "iterations", required_argument, 0, 'i' }, { "yield", required_argument, 0, 'y' }, { "sync", required_argument, 0, 's' }, { 0, 0, 0, 0 } }; char opt; unsigned int thread_count = 1; unsigned int iteration_count = 1; while ((opt = getopt_long(argc, argv, "y::s:t:i:", long_options, NULL))) { if (opt == -1) break; if (opt == 't') { if (optarg) thread_count = strtol(optarg, NULL, 10); } else if (opt == 'i') { if (optarg) iteration_count = strtol(optarg, NULL, 10); } else if (opt == 'y') { opt_yield = 0x00; for (size_t i = 0; i < strlen(optarg); i++) { if (optarg[i] == 'i') { opt_yield = 0x01 | opt_yield; } else if (optarg[i] == 'd') { opt_yield = 0x02 | opt_yield; } else if (optarg[i] == 'l') { opt_yield = 0x04 | opt_yield; } else { fprintf(stderr, "ERROR: incorrect yield usage. Correct usage: --yield=(i/l/d) \n"); exit(1); } } } else if (opt == 's') { if (optarg) { if (*optarg == 'm') { pthread_mutex_init(&mutex, NULL); sync_flag = 'm'; } else if (*optarg == 's') { sync_flag = 's'; } else if (*optarg == 'c') { sync_flag = 'c'; } else { fprintf(stderr, "ERROR: incorrect sync usage. Correct usage: --sync (m/s/c) \n"); exit(1); } } else { fprintf(stderr, "ERROR: incorrect sync usage. Correct usage: --sync (m/s/c) \n"); exit(1); } } else { fprintf(stderr, "ERROR: incorrect usage. Correct usage: ./lab2_list --threads=(num) --iterations=(num) --yield=(i/l/d) --sync=(m/s/c) \n"); exit(1); } } SortedList_t *head = (SortedList_t*)malloc(sizeof(SortedList_t)); SortedList_t temp = { head, head, NULL }; memcpy(head, &temp, sizeof(SortedList_t)); SortedListElement_t *sortedarray = (SortedListElement_t*)malloc(sizeof(SortedListElement_t)*(thread_count*iteration_count)); srand(time(NULL)); long long t = 0; while (t < thread_count*iteration_count) { char *temp_key = (char*)malloc(sizeof(char)); *temp_key = (char)(rand() % 256); SortedListElement_t temp2 = { NULL, NULL, temp_key }; memcpy(&sortedarray[t], &temp2, sizeof(SortedListElement_t)); t++; } struct thread_info *threadi = calloc(thread_count, sizeof(struct thread_info)); if (threadi == NULL) { fprintf(stderr, "ERROR: memory allocation failed. \n"); exit(2); } char *yieldo; size_t threadn = 0; yieldo = optf(); struct timespec start_time; clock_gettime(CLOCK_REALTIME, &start_time); while (threadn < thread_count) { threadi[threadn].thread_number = threadn; threadi[threadn].head = head; threadi[threadn].sortedarray = sortedarray; threadi[threadn].itr = iteration_count; int generate_res = pthread_create(&(threadi[threadn].thread_id), NULL, &bthread, (void*)(&threadi[threadn])); if (generate_res != 0) fprintf(stderr, "ERROR: thread creation failed. \n"); threadn++; } threadn = 0; while (threadn < thread_count) { if (pthread_join(threadi[threadn].thread_id, NULL)) { fprintf(stderr, "ERROR: thread join failed. \n"); exit(2); } threadn++; } struct timespec end_time; clock_gettime(CLOCK_REALTIME, &end_time); if (SortedList_length(head) != 0) exit(2); long long total_time = 1000000000 * (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec - start_time.tv_nsec); char* bstr = syncf(); fprintf(stdout, "list-%s-%s,%d,%d,1,%d,%lld,%d\n", yieldo, bstr, thread_count, iteration_count, 3*thread_count*iteration_count, total_time, (int)(total_time / (3.0*thread_count*iteration_count))); free(threadi); exit(0); }
void* thread_func(void* argc) { int i; //insert //printf("%d\n", *(int*)argc); for (i = *(int*)argc; i < operations; i += num_thread) { if (sync_s == 'm') { pthread_mutex_lock(&lock); SortedList_insert(&list[hash_key(element[i].key)], &element[i]); pthread_mutex_unlock(&lock); } else if (sync_s=='s') { while (__sync_lock_test_and_set(&locker, 1)); SortedList_insert(&list[hash_key(element[i].key)], &element[i]); __sync_lock_release(&locker); } else { SortedList_insert(&list[hash_key(element[i].key)], &element[i]); } } int b; //get the length if (sync_s=='m') { pthread_mutex_lock(&lock); for (b=0; b<num_list; b++) { SortedList_length(&list[b]); //printf("%d\n",SortedList_length(&list[b]) ); } pthread_mutex_unlock(&lock); } else if (sync_s=='s') { while (__sync_lock_test_and_set(&locker, 1)); for (b=0; b<num_list; b++) { SortedList_length(&list[b]); } __sync_lock_release(&locker); } else { for (b=0; b<num_list; b++) { SortedList_length(&list[b]); } } //lookup and delete. SortedListElement_t* node_deleted; for ( i = *(int *)argc; i < operations; i += num_thread) { if (sync_s=='m') { pthread_mutex_lock(&lock); node_deleted = SortedList_lookup(&list[hash_key(element[i].key)], element[i].key); SortedList_delete(node_deleted); pthread_mutex_unlock(&lock); } else if (sync_s=='s') { while (__sync_lock_test_and_set(&locker, 1)); node_deleted = SortedList_lookup(&list[hash_key(element[i].key)], element[i].key); SortedList_delete(node_deleted); __sync_lock_release(&locker); } else { node_deleted = SortedList_lookup(&list[hash_key(element[i].key)], element[i].key); SortedList_delete(node_deleted); } } }
int main(int argc, char *argv[]) { int i, j; /* get the options */ while (1) { static struct option long_options[] = { //set value {"threads", required_argument, 0, 't'}, {"yield", required_argument, 0, 'y'}, {"iterations", required_argument, 0, 'i'}, {"sync", required_argument, 0, 's'}, {"lists", required_argument, 0, 'l'}, {0, 0, 0, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; char arg = getopt_long (argc, argv, "tis", long_options, &option_index); /* Detect the end of the options. */ if (arg == -1) break; switch (arg) { case 0: break; case 't': num_thread = atoi(optarg); break; case 'i': num_iteration = atoi(optarg); break; case 's': sync_s = optarg[0]; break; case 'l': num_list = atoi(optarg); break; case 'y': temperal = optarg; int i=0; for (i=0; temperal[i]!= '\0'; i++) { if (temperal[i]=='i') { opt_yield+=INSERT_YIELD; } else if (temperal[i]=='d') { opt_yield+=DELETE_YIELD; } else if (temperal[i]=='s') { opt_yield+=SEARCH_YIELD; } else { fprintf(stderr, "invalid option!\n"); } } break; //default: //return 0; } } //initialize the list headers list = (SortedList_t *) malloc (num_list*sizeof(SortedList_t)); int h; for (h=0; h<num_list; h++) { //list[h] = {&list[h], &list[h], NULL}; list[h].prev = &list[h]; list[h].next = &list[h]; list[h].key = NULL; } //initialize all the node needed operations = num_thread * num_iteration; element = (SortedListElement_t *)malloc(operations*sizeof(SortedListElement_t)); //generate key for each node for (i = 0; i < operations; i++) { char* temp = (char*) malloc (5*sizeof(char)); temp[0]=65+rand()%60; temp[1]=65+rand()%60; temp[2]=65+rand()%60; temp[3]=65+rand()%60; temp[4]=65+rand()%60; element[i].key = temp; // element[i].key = (char*) malloc (5*sizeof(char)); // element[i].key[0] = 65+rand()%60; // element[i].key[1] = 65+rand()%60; // element[i].key[2] = 65+rand()%60; // element[i].key[3] = 65+rand()%60; // element[i].key[4] = 65+rand()%60; } pthread_t *tids = (pthread_t *)malloc(num_thread*sizeof(pthread_t)); struct timespec requestStart, requestEnd; clock_gettime(CLOCK_MONOTONIC, &requestStart); //an integer array to hold ids int *thread_id = (int *)malloc(num_thread*sizeof(int)); for ( i = 0; i < num_thread; i++) thread_id[i] = i; int k; for ( k = 0; k < num_thread; k++) pthread_create(&tids[k], NULL, thread_func, &thread_id[k] ); for ( j = 0; j < num_thread; j++) pthread_join(tids[j], NULL); clock_gettime(CLOCK_MONOTONIC, &requestEnd); int elapsed_time = diff(requestStart, requestEnd).tv_nsec; //print discription printf("%ld threads x %ld iterations x (insert + lookup/delete) = %ld operations\n", num_thread, num_iteration, operations*2); printf("elapsed time: %dns\n", elapsed_time); printf("per operation: %ldns\n", elapsed_time/operations/2); int q; int sum_length=0; for (q=0; q<num_list; q++) { sum_length+=SortedList_length(&list[q]); } if (sum_length!=0) fprintf(stderr,"ERROR: final count = %lld\n", sum_length); //printf("%d\n", elapsed_time/operations/2); exit(0); }