void *test(void *data) { fprintf(stderr, "Starting test\n"); //get the per-thread data thread_data_t *d = (thread_data_t *)data; //place the thread on the apropriate cpu set_cpu(the_cores[d->id]); int op_count = 10000; ssalloc_init(); bst_init_local(d->id); /* Wait on barrier */ barrier_cross(d->barrier); int i; bool_t added; for ( i = 1; i <= op_count; i++){ added = bst_insert(i, root, d->id); // fprintf(stderr, "[%d] Added %d? %d\n", d->id, i, added==TRUE); if (added == TRUE) { d->num_insert++; } } // printf("Root right node: %d", root->right->key); for ( i = 1; i <= op_count; i++){ node_t* found = bst_find(i, root, d->id); // printf("Contains %d? %d\n", i, found==FOUND); if (found != NULL) { d->num_search ++; } } for ( i = 1; i <= op_count; i++){ bool_t removed = bst_delete(i, root, d->id); // printf("Removed %d? %d\n", i, removed==TRUE); if (removed == TRUE) { d->num_remove ++; } } // for ( i = 1; i < 10; i++){ // bool_t found = bst_contains(i); // printf("Contains %d? %d\n", i, found==FOUND); // } return NULL; }
void *test(void *data) { int rand_max; thread_data_t *d = (thread_data_t *)data; unsigned short seed[3]; seeds = seed_rand(); //#ifdef __sparc__ phys_id = the_cores[d->id]; cluster_id = get_cluster(phys_id); //#else // phys_id = d->id; //#endif /* Initialize seed (use rand48 as rand is poor) */ seed[0] = (unsigned short)rand_r(&d->seed); seed[1] = (unsigned short)rand_r(&d->seed); seed[2] = (unsigned short)rand_r(&d->seed); rand_max = d->bank->size - 1; /* local initialization of locks */ local_th_data[d->id] = init_lock_array_local(phys_id, d->bank->size, the_locks); /* Wait on barrier */ barrier_cross(d->barrier); while (stop == 0) { uint32_t nb = (uint32_t) (my_random(&(seeds[0]),&(seeds[1]),&(seeds[2])) % 100); uint32_t acc = (uint32_t) my_random(&(seeds[0]),&(seeds[1]),&(seeds[2])) & rand_max; account_t* accp = &d->bank->accounts[acc]; if (nb < d->deposit_perc) { deposit(accp, 1, d->id); d->nb_deposit++; } else if (nb < d->withdraw_perc) { withdraw(accp, 1, d->id); d->nb_withdraw++; } else /* nb < balance_perc */ { check(accp, d->id); d->nb_balance++; } } /* Free locks */ //free_local(local_th_data[d->id], d->bank->size); return NULL; }
//threads test void *test_thread(void* data){ thread_data_t * my_data = (thread_data_t *) data; int task_id = my_data->thread_id; int round; for(round = 0; round < ROUND ;round++){ if(round%num_thread == task_id){ (my_data->sc->counter)++; } #ifdef USE_SenseBarrier barrier_cross(my_data->barrier,my_data); #elif defined(USE_TreeBarrier) TreeBarrier_cross(my_data->barrier,my_data); #elif defined(USE_StaticTreeBarrier) StaticTreeBarrier_cross(my_data->barrier,my_data); #endif if((my_data->sc->counter) != round){ printf("Error\n"); } #ifdef USE_SenseBarrier barrier_cross(my_data->barrier,my_data); #elif defined(USE_TreeBarrier) TreeBarrier_cross(my_data->barrier,my_data); #elif defined(USE_StaticTreeBarrier) StaticTreeBarrier_cross(my_data->barrier,my_data); #endif } printf("thread %0d over\n",task_id); pthread_exit(NULL); }
void *test(void *data) { int rand_max; thread_data_t *d = (thread_data_t *)data; uint64_t res; phys_id= the_cores[d->id]; set_cpu(phys_id); seeds = seed_rand(); rand_max = num_entries - 1; /* Init of local data if necessary */ /* Wait on barrier */ barrier_cross(d->barrier); int entry; while (stop == 0) { if (num_entries==1) { entry=0; } else { entry =(int) my_random(&(seeds[0]),&(seeds[1]),&(seeds[2])) & rand_max; } // entry = (int)(erand48(seed) * rand_max) + rand_min; #ifdef TEST_CAS do { res = CAS_U8(&(the_data[entry].data),0,1); } while(res!=0); #elif defined(TEST_TAS) do { res = TAS_U8(&(the_data[entry].data)); } while (res!=0); #elif defined(TEST_FAI) FAI_U8(&(the_data[entry].data)); #else perror("No test primitive specified"); #endif MEM_BARRIER; the_data[entry].data = 0; d->num_operations++; if (op_pause>0) { cpause(op_pause); } } /* Free any local data if necessary */ return NULL; }
void *test_maintenance(void *data) { #ifdef TINY10B int i; free_list_item **t_list_items; #endif maintenance_thread_data_t *d = (maintenance_thread_data_t *)data; #ifdef TINY10B t_list_items = (free_list_item **)malloc(d->nb_threads * sizeof(free_list_item *)); for(i = 0; i < d->nb_threads; i++) { t_list_items[i] = d->set->t_free_list[i]; } #endif /* Create transaction */ TM_THREAD_ENTER(); /* Wait on barrier */ barrier_cross(d->barrier); /* Is the first op an update? */ //unext = (rand_range_re(&d->seed, 100) - 1 < d->update); #ifdef ICC while (stop == 0) { #else while (AO_load_full(&stop) == 0) { #endif /* ICC */ #ifdef TINY10B do_maintenance_thread(d->set, d->id, d->nb_maint); #endif #ifdef ICC } #else } #endif /* ICC */ /* Free transaction */ TM_THREAD_EXIT(); return NULL; }
void *test(void *data) { int unext, last = -1; val_t val = 0; int result; int id; ulong *tloc; #ifdef BIAS_RANGE val_t increase; #endif thread_data_t *d = (thread_data_t *)data; id = d->id; tloc = d->set->nb_committed; #ifdef BIAS_RANGE increase = d->range; #endif /* Create transaction */ TM_THREAD_ENTER(); /* Wait on barrier */ barrier_cross(d->barrier); /* Is the first op an update? */ unext = (rand_range_re(&d->seed, 100) - 1 < d->update); #ifdef ICC while (stop == 0) { #else while (AO_load_full(&stop) == 0) { #endif /* ICC */ if (unext) { // update if (last < 0) { // add val = rand_range_re(&d->seed, d->range); #ifdef BIAS_RANGE if(rand_range_re(&d->seed, 1000) < 50) { increase += rand_range_re(&d->seed, 10); if(increase > d->range * 20) { increase = d->range; } val = increase; } #endif if ((result = avl_add(d->set, val, TRANSACTIONAL, id)) > 0) { d->nb_added++; if(result > 1) { d->nb_modifications++; } last = val; } d->nb_trans++; tloc[id]++; d->nb_add++; } else { // remove if (d->alternate) { // alternate mode (default) #ifdef TINY10B if ((result = avl_remove(d->set, last, TRANSACTIONAL, id)) > 0) { #else if ((result = avl_remove(d->set, last, TRANSACTIONAL, 0)) > 0) { #endif d->nb_removed++; #ifdef REMOVE_LATER finish_removal(d->set, id); #endif if(result > 1) { d->nb_modifications++; } } last = -1; } else { /* Random computation only in non-alternated cases */ val = rand_range_re(&d->seed, d->range); /* Remove one random value */ #ifdef BIAS_RANGE if(rand_range_re(&d->seed, 1000) < 300) { //val = d->range + rand_range_re(&d->seed, increase - d->range); val = increase - rand_range_re(&d->seed, 10); } #endif #ifdef TINY10B if ((result = avl_remove(d->set, val, TRANSACTIONAL, id)) > 0) { #else if ((result = avl_remove(d->set, val, TRANSACTIONAL, 0)) > 0) { #endif d->nb_removed++; #ifdef REMOVE_LATER finish_removal(d->set, id); #endif if(result > 1) { d->nb_modifications++; } /* Repeat until successful, to avoid size variations */ last = -1; } } d->nb_trans++; tloc[id]++; d->nb_remove++; } } else { // read if (d->alternate) { if (d->update == 0) { if (last < 0) { val = d->first; last = val; } else { // last >= 0 val = rand_range_re(&d->seed, d->range); last = -1; } } else { // update != 0 if (last < 0) { val = rand_range_re(&d->seed, d->range); //last = val; } else { val = last; } } } else val = rand_range_re(&d->seed, d->range); #ifdef BIAS_RANGE if(rand_range_re(&d->seed, 1000) < 100) { val = increase; } #endif if (avl_contains(d->set, val, TRANSACTIONAL, id)) d->nb_found++; d->nb_trans++; tloc[id]++; d->nb_contains++; } /* Is the next op an update? */ if (d->effective) { // a failed remove/add is a read-only tx unext = ((100 * (d->nb_added + d->nb_removed)) < (d->update * (d->nb_add + d->nb_remove + d->nb_contains))); } else { // remove/add (even failed) is considered as an update unext = (rand_range_re(&d->seed, 100) - 1 < d->update); } #ifdef ICC } #else } #endif /* ICC */ /* Free transaction */ TM_THREAD_EXIT(); return NULL; } void *test_maintenance(void *data) { #ifdef TINY10B int i; free_list_item **t_list_items; #endif maintenance_thread_data_t *d = (maintenance_thread_data_t *)data; #ifdef TINY10B t_list_items = (free_list_item **)malloc(d->nb_threads * sizeof(free_list_item *)); for(i = 0; i < d->nb_threads; i++) { t_list_items[i] = d->set->t_free_list[i]; } #endif /* Create transaction */ TM_THREAD_ENTER(); /* Wait on barrier */ barrier_cross(d->barrier); /* Is the first op an update? */ //unext = (rand_range_re(&d->seed, 100) - 1 < d->update); #ifdef ICC while (stop == 0) { #else while (AO_load_full(&stop) == 0) { #endif /* ICC */ #ifdef TINY10B do_maintenance_thread(d->set, d->id, d->nb_maint); #endif #ifdef ICC } #else } #endif /* ICC */ /* Free transaction */ TM_THREAD_EXIT(); return NULL; } void catcher(int sig) { printf("CAUGHT SIGNAL %d\n", sig); }
int main(int argc, char **argv) { struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"duration", required_argument, NULL, 'd'}, {"initial-size", required_argument, NULL, 'i'}, {"thread-num", required_argument, NULL, 't'}, {"range", required_argument, NULL, 'r'}, {"seed", required_argument, NULL, 'S'}, {"update-rate", required_argument, NULL, 'u'}, {"bias-range", required_argument, NULL, 'b'}, {"bias-offset", required_argument, NULL, 'u'}, {"elasticity", required_argument, NULL, 'x'}, {NULL, 0, NULL, 0} }; intset_t *set; int i, c, size; val_t last = 0; val_t val = 0; unsigned long reads, effreads, updates, effupds, aborts, aborts_locked_read, aborts_locked_write, aborts_validate_read, aborts_validate_write, aborts_validate_commit, aborts_invalid_memory, aborts_double_write, max_retries, failures_because_contention; thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; int duration = DEFAULT_DURATION; int initial = DEFAULT_INITIAL; int nb_threads = DEFAULT_NB_THREADS; long range = DEFAULT_RANGE; long bias_range = DEFAULT_BIAS_RANGE; long bias_offset = DEFAULT_BIAS_OFFSET; int bias_enabled = 0; int seed = DEFAULT_SEED; int update = DEFAULT_UPDATE; int unit_tx = DEFAULT_ELASTICITY; int alternate = DEFAULT_ALTERNATE; int effective = DEFAULT_EFFECTIVE; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "hAf:d:i:t:r:S:u:b:B:x:", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: /* Flag is automatically set */ break; case 'h': printf("intset -- STM stress test " "(linked list)\n" "\n" "Usage:\n" " intset [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -A, --alternate (default="XSTR(DEFAULT_ALTERNATE)")\n" " Consecutive insert/remove target the same value\n" " -f, --effective <int>\n" " update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -i, --initial-size <int>\n" " Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n" " -t, --thread-num <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" " -r, --range <int>\n" " Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n" " -S, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" " -u, --update-rate <int>\n" " Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n" " -b, --bias-range <int>\n" " If used, updates will take place in range [B, B+b)\n" " -B, --bias-offset <int>\n" " If used, updates will take place in range [B, B+b)\n" " -x, --elasticity (default=4)\n" " Use elastic transactions\n" " 0 = non-protected,\n" " 1 = normal transaction,\n" " 2 = read elastic-tx,\n" " 3 = read/add elastic-tx,\n" " 4 = read/add/rem elastic-tx,\n" " 5 = all recursive elastic-tx,\n" " 6 = harris lock-free\n" ); exit(0); case 'A': alternate = 1; break; case 'f': effective = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'i': initial = atoi(optarg); break; case 't': nb_threads = atoi(optarg); break; case 'r': range = atol(optarg); break; case 'S': seed = atoi(optarg); break; case 'u': update = atoi(optarg); break; case 'b': bias_range = atol(optarg); break; case 'B': bias_offset = atol(optarg); break; case 'x': unit_tx = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(initial >= 0); assert(nb_threads > 0); assert(range > 0 && range >= initial); assert(update >= 0 && update <= 100); if (bias_range != DEFAULT_BIAS_RANGE || bias_offset != DEFAULT_BIAS_OFFSET) { bias_enabled = 1; assert(bias_range >= 0); assert(bias_offset > 0); } printf("Bench type : " ALGONAME "\n"); printf("Duration : %d\n", duration); printf("Initial size : %d\n", initial); printf("Nb threads : %d\n", nb_threads); printf("Value range : %ld\n", range); if (bias_enabled) { printf("Biased range: [%ld, %ld)\n", bias_offset, bias_offset+bias_range); } printf("Seed : %d\n", seed); printf("Update rate : %d\n", update); printf("Elasticity : %d\n", unit_tx); printf("Alternate : %d\n", alternate); printf("Effective : %d\n", effective); printf("Type sizes : int=%d/long=%d/ptr=%d/word=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(uintptr_t)); printf("Node size : %d\n", (int)sizeof(node_t)); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(0)); else srand(seed); set = set_new(); stop = 0; /* Populate set */ printf("Adding %d entries to set\n", initial); i = 0; while (i < initial) { val = rand_range(range); if (set_insert(set, val)) { last = val; i++; } } size = set_size(set); printf("Set size : %d\n", size); /* Access set from all threads */ barrier_init(&barrier, nb_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < nb_threads; i++) { printf("Creating thread %d\n", i); data[i].first = last; data[i].bias_enabled = bias_enabled; data[i].bias_range = bias_range; data[i].bias_offset = bias_offset; data[i].range = range; data[i].update = update; data[i].unit_tx = unit_tx; data[i].alternate = alternate; data[i].effective = effective; data[i].nb_add = 0; data[i].nb_added = 0; data[i].nb_remove = 0; data[i].nb_removed = 0; data[i].nb_contains = 0; data[i].nb_found = 0; data[i].nb_aborts = 0; data[i].nb_aborts_locked_read = 0; data[i].nb_aborts_locked_write = 0; data[i].nb_aborts_validate_read = 0; data[i].nb_aborts_validate_write = 0; data[i].nb_aborts_validate_commit = 0; data[i].nb_aborts_invalid_memory = 0; data[i].nb_aborts_double_write = 0; data[i].max_retries = 0; data[i].seed = rand(); data[i].set = set; data[i].barrier = &barrier; data[i].failures_because_contention = 0; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); /* Start threads */ barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } /* #ifdef ICC stop = 1; #else AO_store_full(&stop, 1); #endif // ICC */ atomic_store(&stop, 1); gettimeofday(&end, NULL); printf("STOPPING...\n"); /* Wait for thread completion */ for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); aborts = 0; aborts_locked_read = 0; aborts_locked_write = 0; aborts_validate_read = 0; aborts_validate_write = 0; aborts_validate_commit = 0; aborts_invalid_memory = 0; aborts_double_write = 0; failures_because_contention = 0; reads = 0; effreads = 0; updates = 0; effupds = 0; max_retries = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #add : %lu\n", data[i].nb_add); printf(" #added : %lu\n", data[i].nb_added); printf(" #remove : %lu\n", data[i].nb_remove); printf(" #removed : %lu\n", data[i].nb_removed); printf(" #contains : %lu\n", data[i].nb_contains); printf(" #found : %lu\n", data[i].nb_found); printf(" #aborts : %lu\n", data[i].nb_aborts); printf(" #lock-r : %lu\n", data[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", data[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", data[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", data[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", data[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", data[i].nb_aborts_invalid_memory); printf(" #inv-mem : %lu\n", data[i].nb_aborts_double_write); printf(" #failures : %lu\n", data[i].failures_because_contention); printf(" Max retries : %lu\n", data[i].max_retries); aborts += data[i].nb_aborts; aborts_locked_read += data[i].nb_aborts_locked_read; aborts_locked_write += data[i].nb_aborts_locked_write; aborts_validate_read += data[i].nb_aborts_validate_read; aborts_validate_write += data[i].nb_aborts_validate_write; aborts_validate_commit += data[i].nb_aborts_validate_commit; aborts_invalid_memory += data[i].nb_aborts_invalid_memory; aborts_double_write += data[i].nb_aborts_double_write; failures_because_contention += data[i].failures_because_contention; reads += data[i].nb_contains; effreads += data[i].nb_contains + (data[i].nb_add - data[i].nb_added) + (data[i].nb_remove - data[i].nb_removed); updates += (data[i].nb_add + data[i].nb_remove); effupds += data[i].nb_removed + data[i].nb_added; size += data[i].nb_added - data[i].nb_removed; if (max_retries < data[i].max_retries) max_retries = data[i].max_retries; } printf("Set size : %d (expected: %d)\n", set_size(set), size); if (set_size(set) != size) { printf("ERROR: Set size did not match expected.\n"); } printf("Duration : %d (ms)\n", duration); printf("#txs : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration); printf("#read txs : "); if (effective) { printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration); printf(" #contains : %lu (%f / s)\n", reads, reads * 1000.0 / duration); } else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration); printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads)); printf("#update txs : "); if (effective) { printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration); printf(" #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / duration); } else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration); printf("#aborts : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration); printf(" #lock-r : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration); printf(" #lock-w : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration); printf(" #val-r : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration); printf(" #val-w : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration); printf(" #val-c : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration); printf(" #inv-mem : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration); printf(" #dup-w : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration); printf(" #failures : %lu\n", failures_because_contention); printf("Max retries : %lu\n", max_retries); /* Delete set */ set_delete(set); free(threads); free(data); return 0; }
void *test(void *data) { fprintf(stderr, "Starting test\n"); //get the per-thread data thread_data_t *d = (thread_data_t *)data; //place the thread on the apropriate cpu set_cpu(d->id); int op_count = 10000; ssalloc_init(); /* Wait on barrier */ barrier_cross(d->barrier); int i; bst_value_t* val = (bst_value_t*)malloc(sizeof(bst_value_t)); bst_value_t* added; for ( i = 1; i <= op_count; i++){ *val = d->id*op_count+i; // bst_value_t val = d->id*op_count+i; // fprintf(stderr, "[%d] before add\n", pthread_self()); added = bst_put(i, val, root); // fprintf(stderr, "[%d] Added %d\n", pthread_self(), i); // fprintf(stderr, "[%d] Added %d? %d\n", d->id, i, added==TRUE); if (added == NULL) { d->num_insert++; FAI_U8(&v[i]); } } // printf("Root right node: %d", root->right->key); for (i = 1; i <= op_count; i++){ bool_t found = (bst_get(i, root) != NULL); // printf("Contains %d? %d\n", i, found==FOUND); if (found) { d->num_search ++; } } // fprintf(stderr, "After insertions, found %d\n", d->num_search); // d->num_search = 0; for ( i = 1; i <= op_count; i++){ bool_t removed = (bst_remove(i, root) != NULL); // printf("Removed %d? %d\n", i, removed==TRUE); if (removed == TRUE) { d->num_remove ++; FAI_U8(&v[i]); } } // for ( i = 1; i <= op_count; i++){ // bool_t found = (bst_get(i) != NULL); // // printf("Contains %d? %d\n", i, found==FOUND); // if (found) { // d->num_search ++; // } // } // fprintf(stderr, "After deletions, found %d\n", d->num_search); return NULL; }
void* sssp(void *data) { thread_data_t *d = (thread_data_t *)data; /* Create transaction */ set_cpu(the_cores[d->id]); /* Wait on barrier */ ssalloc_init(); PF_CORRECTION; seeds = seed_rand(); #ifdef PIN int id = d->id; // int cpu = 40*(id/40) + 4*(id%10) + (id%40)/10; int cpu = 4*(id%20) + id/20; // printf("Pinning %d to %d\n",id,cpu); pin(pthread_self(), cpu); // pin(pthread_self(), id); #endif #ifdef PAPI if (PAPI_OK != PAPI_start_counters(g_events, G_EVENT_COUNT)) { printf("Problem starting counters 1."); } #endif barrier_cross(d->barrier); // Begin SSSP int fail = 0; // int radius = 0; while (1) { val_t node; slkey_t dist_node; // print_skiplist(d->set); while (1) { if (d->sl) { if (spray_delete_min_key(d->set, &dist_node, &node, d)) break; // keep trying until get a node } else if (d->pq) { if (lotan_shavit_delete_min_key(d->set, &dist_node, &node, d)) break; } else if (d->lin) { node = (val_t) deletemin_key(d->linden_set, &dist_node, d); break; } else { printf("error: no queue selected\n"); exit(1); // TODO: grace } if (dist_node == -1) { // flag that list is empty break; } dist_node = 0; } if (dist_node == -1) { // list is empty; TODO make sure threads don't quit early fail++; if (fail > 20*d->nb_threads) { // TODO: really need a better break condition... break; } continue; } fail = 0; if (dist_node != nodes[node].dist) continue; // dead node nodes[node].times_processed++; int i; for (i = 0;i < nodes[node].deg;i++) { int v = nodes[node].adj[i]; int w = nodes[node].weights[i]; slkey_t dist_v = nodes[v].dist; // printf("v=%d dist_v=%d\n", v, dist_v); if (dist_v == -1 || dist_node + w < dist_v) { // found better path to v // printf("attempting cas...\n"); // printf("nodes[v].dist=%d dist_v=%d dist_node=%d\n", nodes[v].dist, dist_v, dist_node); int res = ATOMIC_CAS_MB(&nodes[v].dist, dist_v, dist_node+w); // printf("%d nodes[%d].dist=%d\n", res, v, nodes[v].dist); if (res) { if (d->pq || d->sl) { sl_add_val(d->set, dist_node+w, v, TRANSACTIONAL); // add to queue only if CAS is successful } else if (d->lin) { insert(d->linden_set, dist_node+w, v); } d->nb_add++; // if (dist_node+1 > radius) { // radius = dist_node+1; // printf("radius %d\n", radius); // } } } } } // End SSSP #ifdef PAPI if (PAPI_OK != PAPI_read_counters(g_values[d->id], G_EVENT_COUNT)) { printf("Problem reading counters 2."); } #endif PF_PRINT; return NULL; }
void* test(void *data) { int unext, last = -1; val_t val = 0; pval_t pval = 0; thread_data_t *d = (thread_data_t *)data; /* Create transaction */ TM_THREAD_ENTER(d->id); set_cpu(the_cores[d->id]); /* Wait on barrier */ ssalloc_init(); PF_CORRECTION; seeds = seed_rand(); #ifdef PIN int id = d->id; int cpu = 40*(id/40) + 4*(id%10) + (id%40)/10; // printf("Pinning %d to %d\n",id,cpu); pin(pthread_self(), cpu); // pin(pthread_self(), id); #endif #ifdef PAPI if (PAPI_OK != PAPI_start_counters(g_events, G_EVENT_COUNT)) { printf("Problem starting counters 1."); } #endif barrier_cross(d->barrier); /* Is the first op an update? */ unext = (rand_range_re(&d->seed, 100) - 1 < d->update); #ifdef DISTRIBUTION_EXPERIMENT while (1) #else while (*running) #endif { if (d->es) { // event simulator experiment if (d->lin) { if (!empty(d->linden_set)) { d->nb_remove++; pval_t pval = deletemin(d->linden_set, d); d->nb_removed++; // printf("%d %d\n", pval, deps[pval][0]); int i = 0; val_t dep; while ((dep = deps[pval][i]) != -1 && i < MAX_DEPS) { d->nb_add++; if (insert(d->linden_set, dep, dep)) { d->nb_added++; } i++; } } } else { if (d->set->head->next[0]->next[0] != NULL) {// set not empty d->nb_remove++; if (d->sl) { // spray list if (spray_delete_min(d->set, &val, d)) { d->nb_removed++; } else { continue; } } else if (d->pq) { // lotan_shavit pq if (lotan_shavit_delete_min(d->set, &val, d)) { d->nb_removed++; // continue; // TODO: maybe try remove this to simulate task handling (dependency checks still occur) } else { continue; } } // struct timespec ten_usec; // ten_usec.tv_sec = 0; // ten_usec.tv_nsec = 10000; // nanosleep(&ten_usec, NULL); // dependency handling int i = 0; val_t dep; while ((dep = deps[val][i]) != -1 && i < MAX_DEPS) { if (!sl_contains(d->set, dep, TRANSACTIONAL)) { // dependent has been removed, need to add it again if (sl_add(d->set, dep, TRANSACTIONAL)) { // check if insert actually succeeded (otherwise someone else did it first) d->nb_added++; } d->nb_add++; } i++; } } } } else { // not event simulator if (unext) { // update if (last < 0) { // add val = rand_range_re(&d->seed, d->range); if (d->lin) { pval = val; insert(d->linden_set, pval, pval); d->nb_added++; last = pval; } else { // not linden if (sl_add(d->set, val, TRANSACTIONAL)) { d->nb_added++; last = val; } } d->nb_add++; } else { // remove if (d->pq) { if (lotan_shavit_delete_min(d->set, &val, d)) { d->nb_removed++; if (d->first_remove == -1) { d->first_remove = val; } } last = -1; } else if (d->sl) { if (spray_delete_min(d->set, &val, d)) { d->nb_removed++; if (d->first_remove == -1) { d->first_remove = val; } last = -1; } } else if (d->lin) { if ((pval = deletemin(d->linden_set, d))) { d->nb_removed++; if (d->first_remove == -1) { d->first_remove = pval; } last = -1; } } else if (d->alternate) { // alternate mode (default) if (sl_remove(d->set, last, TRANSACTIONAL)) { d->nb_removed++; if (d->first_remove == -1) { d->first_remove = val; } } last = -1; } else { /* Random computation only in non-alternated cases */ val = rand_range_re(&d->seed, d->range); /* Remove one random value */ if (sl_remove_succ(d->set, val, TRANSACTIONAL)) { d->nb_removed++; if (d->first_remove == -1) { d->first_remove = val; } /* Repeat until successful, to avoid size variations */ last = -1; } } d->nb_remove++; } } else { // read if (d->alternate) { if (d->update == 0) { if (last < 0) { val = d->first; last = val; } else { // last >= 0 val = rand_range_re(&d->seed, d->range); last = -1; } } else { // update != 0 if (last < 0) { val = rand_range_re(&d->seed, d->range); //last = val; } else { val = last; } } } else val = rand_range_re(&d->seed, d->range); PF_START(2); if (sl_contains(d->set, val, TRANSACTIONAL)) d->nb_found++; PF_STOP(2); d->nb_contains++; } /* Is the next op an update? */ if (d->effective) { // a failed remove/add is a read-only tx unext = ((100 * (d->nb_added + d->nb_removed)) < (d->update * (d->nb_add + d->nb_remove + d->nb_contains))); } else { // remove/add (even failed) is considered as an update unext = (rand_range_re(&d->seed, 100) - 1 < d->update); } } #ifdef DISTRIBUTION_EXPERIMENT if (d->first_remove != -1) { break; //only one run } #endif } #ifdef PAPI if (PAPI_OK != PAPI_read_counters(g_values[d->id], G_EVENT_COUNT)) { printf("Problem reading counters 2."); } #endif /* Free transaction */ TM_THREAD_EXIT(); PF_PRINT; return NULL; }
void *test(void *data) { DDPRINT("starting test\n",NULL); //get the per-thread data thread_data_t *d = (thread_data_t *)data; //scale percentages of the various operations to the range 0..255 //this saves us a floating point operation during the benchmark //e.g instead of random()%100 to determine the next operation we will do, we can simply do random()&256 //this saves time on some platfroms uint32_t read_thresh = 256 * finds / 100; //uint32_t write_thresh = 256 * (finds + inserts) / 100; //place the thread on the apropriate cpu set_cpu(d->id); //initialize the custom memeory allocator for this thread (we do not use malloc due to concurrency bottleneck issues) ssalloc_init(); // ssalloc_align(); bst_init_local(d->id); //for fine-grain latency measurements, we need to get the lenght of a getticks() function call, which is also counted //by default when we do getticks(); //code... getticks(); PF_START and PF_STOP use this when fine grain measurements are enabled PF_CORRECTION; uint32_t rand_max; //seed the custom random number generator seeds = seed_rand(); rand_max = max_key; uint32_t op; skey_t key; int i; int last = -1; DDPRINT("staring initial insert\n",NULL); DDPRINT("number of inserts: %u up to %u\n",d->num_add,rand_max); //before starting the test, we insert a number of elements in the data structure //we do this at each thread to avoid the situation where the entire data structure //resides in the same memory node // int num_elem = 0; // if (num_threads == 1){ // num_elem = max_key/2; // } else{ // num_elem = max_key/4; // } // pthread_mutex_lock(d->init_lock); // fprintf(stderr, "Starting critical section %d\n", d->id); for (i=0;i<max_key/4;++i) { key = my_random(&seeds[0],&seeds[1],&seeds[2]) & rand_max; DDPRINT("key is %u\n",key); //we make sure the insert was effective (as opposed to just updating an existing entry) if (d->id < 2) { if (bst_add(key,root, d->id)!=TRUE) { i--; } } } // fprintf(stderr, "Exiting critical section %d\n", d->id); // pthread_mutex_unlock(d->init_lock); DDPRINT("added initial data\n",NULL); bool_t res; /* Init of local data if necessary */ ticks t1,t2; /* Wait on barrier */ // fprintf(stderr, "Waiting on barrier; thread %d\n", d->id); barrier_cross(d->barrier); //start the test while (*running) { //generate a key (node that rand_max is expected to be a power of 2) key = my_random(&seeds[0],&seeds[1],&seeds[2]) & rand_max; //generate the operation op = my_random(&seeds[0],&seeds[1],&seeds[2]) & 0xff; if (op < read_thresh) { //do a find operation //PF_START and PF_STOP can be used to do latency measurements of the operation //to enable them, DO_TIMINGS must be defined at compile time, otherwise they do nothing //PF_START(2); bst_contains(key,root, d->id); //PF_STOP(2); } else if (last == -1) { //do a write operation if (bst_add(key,root, d->id)) { d->num_insert++; last=1; } } else { //do a delete operation if (bst_remove(key,root, d->id)) { d->num_remove++; last=-1; } } d->num_operations++; //memory barrier to ensure no unwanted reporderings are happening //MEM_BARRIER; } //summary of the fine grain measurements if enabled PF_PRINT; return NULL; }
int main(int argc, char **argv) { struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"alternate", no_argument, NULL, 'A'}, {"effective", required_argument, NULL, 'f'}, {"duration", required_argument, NULL, 'd'}, {"initial-size", required_argument, NULL, 'i'}, {"num-threads", required_argument, NULL, 'n'}, {"range", required_argument, NULL, 'r'}, {"seed", required_argument, NULL, 's'}, {"update-rate", required_argument, NULL, 'u'}, {"move-rate", required_argument, NULL, 'm'}, {"snapshot-rate", required_argument, NULL, 'a'}, {"elasticity", required_argument, NULL, 'x'}, {NULL, 0, NULL, 0} }; ht_intset_t *set; int i, c, size; val_t last = 0; val_t val = 0; unsigned long reads, effreads, updates, effupds, moves, snapshots, aborts, aborts_locked_read, aborts_locked_write, aborts_validate_read, aborts_validate_write, aborts_validate_commit, aborts_invalid_memory, aborts_double_write, max_retries, failures_because_contention; thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; int duration = DEFAULT_DURATION; int initial = DEFAULT_INITIAL; int nb_threads = DEFAULT_NB_THREADS; long range = DEFAULT_RANGE; int seed = DEFAULT_SEED; int update = DEFAULT_UPDATE; int load_factor = DEFAULT_LOAD; int move = DEFAULT_MOVE; int snapshot = DEFAULT_SNAPSHOT; int unit_tx = DEFAULT_ELASTICITY; int alternate = DEFAULT_ALTERNATE; int effective = DEFAULT_EFFECTIVE; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "hAf:d:i:n:r:s:u:m:a:l:x:", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: // Flag is automatically set break; case 'h': printf("intset -- STM stress test " "(hash table)\n" "\n" "Usage:\n" " intset [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -A, --Alternate\n" " Consecutive insert/remove target the same value\n" " -f, --effective <int>\n" " update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -i, --initial-size <int>\n" " Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" " -r, --range <int>\n" " Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n" " -s, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" " -u, --update-rate <int>\n" " Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n" " -m , --move-rate <int>\n" " Percentage of move transactions (default=" XSTR(DEFAULT_MOVE) ")\n" " -a , --snapshot-rate <int>\n" " Percentage of snapshot transactions (default=" XSTR(DEFAULT_SNAPSHOT) ")\n" " -l , --load-factor <int>\n" " Ratio of keys over buckets (default=" XSTR(DEFAULT_LOAD) ")\n" " -x, --elasticity (default=4)\n" " Use elastic transactions\n" " 0 = non-protected,\n" " 1 = normal transaction,\n" " 2 = read elastic-tx,\n" " 3 = read/add elastic-tx,\n" " 4 = read/add/rem elastic-tx,\n" " 5 = elastic-tx w/ optimized move.\n" ); exit(0); case 'A': alternate = 1; break; case 'f': effective = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'i': initial = atoi(optarg); break; case 'n': nb_threads = atoi(optarg); break; case 'r': range = atol(optarg); break; case 's': seed = atoi(optarg); break; case 'u': update = atoi(optarg); break; case 'm': move = atoi(optarg); break; case 'a': snapshot = atoi(optarg); break; case 'l': load_factor = atoi(optarg); break; case 'x': unit_tx = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(initial >= 0); assert(nb_threads > 0); assert(range > 0 && range >= initial); assert(update >= 0 && update <= 100); assert(move >= 0 && move <= update); assert(snapshot >= 0 && snapshot <= (100-update)); assert(initial < MAXHTLENGTH); assert(initial >= load_factor); printf("Set type : hash table\n"); printf("Duration : %d\n", duration); printf("Initial size : %d\n", initial); printf("Nb threads : %d\n", nb_threads); printf("Value range : %ld\n", range); printf("Seed : %d\n", seed); printf("Update rate : %d\n", update); printf("Load factor : %d\n", load_factor); printf("Move rate : %d\n", move); printf("Snapshot rate: %d\n", snapshot); printf("Elasticity : %d\n", unit_tx); printf("Alternate : %d\n", alternate); printf("Effective : %d\n", effective); printf("Type sizes : int=%d/long=%d/ptr=%d/word=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(uintptr_t)); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(0)); else srand(seed); //maxhtlength = (unsigned int) initial / load_factor; set = ht_new(); stop = 0; // Init STM printf("Initializing STM\n"); TM_STARTUP(); // Populate set printf("Adding %d entries to set\n", initial); i = 0; maxhtlength = (int) (initial / load_factor); while (i < initial) { val = rand_range(range); if (ht_add(set, val, 0)) { last = val; i++; } } size = ht_size(set); printf("Set size : %d\n", size); printf("Bucket amount: %d\n", maxhtlength); printf("Load : %d\n", load_factor); // Access set from all threads barrier_init(&barrier, nb_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < nb_threads; i++) { printf("Creating thread %d\n", i); data[i].first = last; data[i].range = range; data[i].update = update; data[i].load_factor = load_factor; data[i].move = move; data[i].snapshot = snapshot; data[i].unit_tx = unit_tx; data[i].alternate = alternate; data[i].effective = effective; data[i].nb_add = 0; data[i].nb_added = 0; data[i].nb_remove = 0; data[i].nb_removed = 0; data[i].nb_move = 0; data[i].nb_moved = 0; data[i].nb_snapshot = 0; data[i].nb_snapshoted = 0; data[i].nb_contains = 0; data[i].nb_found = 0; data[i].nb_aborts = 0; data[i].nb_aborts_locked_read = 0; data[i].nb_aborts_locked_write = 0; data[i].nb_aborts_validate_read = 0; data[i].nb_aborts_validate_write = 0; data[i].nb_aborts_validate_commit = 0; data[i].nb_aborts_invalid_memory = 0; data[i].nb_aborts_double_write = 0; data[i].max_retries = 0; data[i].seed = rand(); data[i].set = set; data[i].barrier = &barrier; data[i].failures_because_contention = 0; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); // Start threads barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } AO_store_full(&stop, 1); gettimeofday(&end, NULL); printf("STOPPING...\n"); // Wait for thread completion for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); aborts = 0; aborts_locked_read = 0; aborts_locked_write = 0; aborts_validate_read = 0; aborts_validate_write = 0; aborts_validate_commit = 0; aborts_invalid_memory = 0; aborts_double_write = 0; failures_because_contention = 0; reads = 0; effreads = 0; updates = 0; effupds = 0; moves = 0; snapshots = 0; max_retries = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #add : %lu\n", data[i].nb_add); printf(" #added : %lu\n", data[i].nb_added); printf(" #remove : %lu\n", data[i].nb_remove); printf(" #removed : %lu\n", data[i].nb_removed); printf(" #contains : %lu\n", data[i].nb_contains); printf(" #found : %lu\n", data[i].nb_found); printf(" #move : %lu\n", data[i].nb_move); printf(" #moved : %lu\n", data[i].nb_moved); printf(" #snapshot : %lu\n", data[i].nb_snapshot); printf(" #snapshoted : %lu\n", data[i].nb_snapshoted); printf(" #aborts : %lu\n", data[i].nb_aborts); printf(" #lock-r : %lu\n", data[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", data[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", data[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", data[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", data[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", data[i].nb_aborts_invalid_memory); printf(" #dup-w : %lu\n", data[i].nb_aborts_double_write); printf(" #failures : %lu\n", data[i].failures_because_contention); printf(" Max retries : %lu\n", data[i].max_retries); aborts += data[i].nb_aborts; aborts_locked_read += data[i].nb_aborts_locked_read; aborts_locked_write += data[i].nb_aborts_locked_write; aborts_validate_read += data[i].nb_aborts_validate_read; aborts_validate_write += data[i].nb_aborts_validate_write; aborts_validate_commit += data[i].nb_aborts_validate_commit; aborts_invalid_memory += data[i].nb_aborts_invalid_memory; aborts_double_write += data[i].nb_aborts_double_write; failures_because_contention += data[i].failures_because_contention; reads += (data[i].nb_contains + data[i].nb_snapshot); effreads += data[i].nb_contains + (data[i].nb_add - data[i].nb_added) + (data[i].nb_remove - data[i].nb_removed) + (data[i].nb_move - data[i].nb_moved) + data[i].nb_snapshoted; updates += (data[i].nb_add + data[i].nb_remove + data[i].nb_move); effupds += data[i].nb_removed + data[i].nb_added + data[i].nb_moved; moves += data[i].nb_move; snapshots += data[i].nb_snapshot; size += data[i].nb_added - data[i].nb_removed; if (max_retries < data[i].max_retries) max_retries = data[i].max_retries; } printf("Set size : %d (expected: %d)\n", ht_size(set), size); printf("Duration : %d (ms)\n", duration); printf("#txs : %lu (%f / s)\n", reads + updates + moves + snapshots, (reads + updates + moves + snapshots) * 1000.0 / duration); printf("#read txs : "); if (effective) { printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration); printf(" #cont/snpsht: %lu (%f / s)\n", reads, reads * 1000.0 / duration); } else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration); printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads)); printf("#update txs : "); if (effective) { printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration); printf(" #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / duration); } else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration); printf("#move txs : %lu (%f / s)\n", moves, moves * 1000.0 / duration); printf("#snapshot txs : %lu (%f / s)\n", snapshots, snapshots * 1000.0 / duration); printf("#aborts : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration); printf(" #lock-r : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration); printf(" #lock-w : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration); printf(" #val-r : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration); printf(" #val-w : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration); printf(" #val-c : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration); printf(" #inv-mem : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration); printf(" #dup-w : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration); printf(" #failures : %lu\n", failures_because_contention); printf("Max retries : %lu\n", max_retries); // Delete set ht_delete(set); // Cleanup STM TM_SHUTDOWN(); free(threads); free(data); return 0; }
int main(int argc, char **argv) { struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"duration", required_argument, NULL, 'd'}, {"initial-size", required_argument, NULL, 'i'}, {"thread-num", required_argument, NULL, 't'}, {"range", required_argument, NULL, 'r'}, {"seed", required_argument, NULL, 'S'}, {"update-rate", required_argument, NULL, 'u'}, {"elasticity", required_argument, NULL, 'x'}, {NULL, 0, NULL, 0} }; avl_intset_t *set; int i, j, c, size, tree_size; val_t last = 0; val_t val = 0; unsigned long reads, effreads, updates, effupds, aborts, aborts_locked_read, aborts_locked_write, aborts_validate_read, aborts_validate_write, aborts_validate_commit, aborts_invalid_memory, aborts_double_write, max_retries, failures_because_contention; thread_data_t *data; maintenance_thread_data_t *maintenance_data; pthread_t *threads; pthread_t *maintenance_threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; int duration = DEFAULT_DURATION; int initial = DEFAULT_INITIAL; int nb_threads = DEFAULT_NB_THREADS; int nb_maintenance_threads = DEFAULT_NB_MAINTENANCE_THREADS; long range = DEFAULT_RANGE; int seed = DEFAULT_SEED; int update = DEFAULT_UPDATE; int unit_tx = DEFAULT_ELASTICITY; int alternate = DEFAULT_ALTERNATE; int effective = DEFAULT_EFFECTIVE; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "hAf:d:i:t:r:S:u:x:" , long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: break; case 'h': printf("intset -- STM stress test " "(avltree)\n" "\n" "Usage:\n" " intset [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -A, --Alternate\n" " Consecutive insert/remove target the same value\n" " -f, --effective <int>\n" " update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -i, --initial-size <int>\n" " Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n" " -t, --thread-num <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" " -r, --range <int>\n" " Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n" " -S, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" " -u, --update-rate <int>\n" " Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n" " -x, --elasticity (default=4)\n" " Use elastic transactions\n" " 0 = non-protected,\n" " 1 = normal transaction,\n" " 2 = read elastic-tx,\n" " 3 = read/add elastic-tx,\n" " 4 = read/add/rem elastic-tx,\n" " 5 = fraser lock-free\n" ); exit(0); case 'A': alternate = 1; break; case 'f': effective = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'i': initial = atoi(optarg); break; case 't': nb_threads = atoi(optarg); break; case 'r': range = atol(optarg); break; case 'S': seed = atoi(optarg); break; case 'u': update = atoi(optarg); break; case 'x': unit_tx = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(initial >= 0); assert(nb_threads > 0); assert(range > 0 && range >= initial); assert(update >= 0 && update <= 100); printf("Set type : avltree\n"); printf("Duration : %d\n", duration); printf("Initial size : %u\n", initial); printf("Nb threads : %d\n", nb_threads); printf("Nb mt threads: %d\n", nb_maintenance_threads); printf("Value range : %ld\n", range); printf("Seed : %d\n", seed); printf("Update rate : %d\n", update); printf("Elasticity : %d\n", unit_tx); printf("Alternate : %d\n", alternate); printf("Efffective : %d\n", effective); printf("Type sizes : int=%d/long=%d/ptr=%d/word=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(uintptr_t)); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if ((maintenance_data = (maintenance_thread_data_t *)malloc(nb_maintenance_threads * sizeof(maintenance_thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((maintenance_threads = (pthread_t *)malloc(nb_maintenance_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(0)); else srand(seed); //levelmax = floor_log_2((unsigned int) initial); //set = avl_set_new(); set = avl_set_new_alloc(0, nb_threads); //set->stop = &stop; //#endif stop = 0; global_seed = rand(); #ifdef TLS rng_seed = &global_seed; #else /* ! TLS */ if (pthread_key_create(&rng_seed_key, NULL) != 0) { fprintf(stderr, "Error creating thread local\n"); exit(1); } pthread_setspecific(rng_seed_key, &global_seed); #endif /* ! TLS */ // Init STM printf("Initializing STM\n"); TM_STARTUP(); // Populate set printf("Adding %d entries to set\n", initial); i = 0; while (i < initial) { val = rand_range_re(&global_seed, range); //printf("Adding %d\n", val); if (avl_add(set, val, 0, 0) > 0) { //printf("Added %d\n", val); //print_avltree(set); last = val; i++; } } size = avl_set_size(set); tree_size = avl_tree_size(set); printf("Set size : %d\n", size); printf("Tree size : %d\n", tree_size); //printf("Level max : %d\n", levelmax); // Access set from all threads barrier_init(&barrier, nb_threads + nb_maintenance_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < nb_threads; i++) { printf("Creating thread %d\n", i); data[i].id = i; data[i].first = last; data[i].range = range; data[i].update = update; data[i].unit_tx = unit_tx; data[i].alternate = alternate; data[i].effective = effective; data[i].nb_modifications = 0; data[i].nb_add = 0; data[i].nb_added = 0; data[i].nb_remove = 0; data[i].nb_removed = 0; data[i].nb_contains = 0; data[i].nb_found = 0; data[i].nb_aborts = 0; data[i].nb_aborts_locked_read = 0; data[i].nb_aborts_locked_write = 0; data[i].nb_aborts_validate_read = 0; data[i].nb_aborts_validate_write = 0; data[i].nb_aborts_validate_commit = 0; data[i].nb_aborts_invalid_memory = 0; data[i].nb_aborts_double_write = 0; data[i].max_retries = 0; data[i].seed = rand(); data[i].set = set; data[i].barrier = &barrier; data[i].failures_because_contention = 0; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } for (i = 0; i < nb_maintenance_threads; i++) { maintenance_data[i].nb_maint = nb_maintenance_threads; maintenance_data[i].id = i; maintenance_data[i].nb_removed = 0; maintenance_data[i].nb_rotated = 0; maintenance_data[i].nb_suc_rotated = 0; maintenance_data[i].nb_propagated = 0; maintenance_data[i].nb_suc_propagated = 0; maintenance_data[i].nb_aborts = 0; maintenance_data[i].nb_aborts_locked_read = 0; maintenance_data[i].nb_aborts_locked_write = 0; maintenance_data[i].nb_aborts_validate_read = 0; maintenance_data[i].nb_aborts_validate_write = 0; maintenance_data[i].nb_aborts_validate_commit = 0; maintenance_data[i].nb_aborts_invalid_memory = 0; maintenance_data[i].nb_aborts_double_write = 0; maintenance_data[i].max_retries = 0; maintenance_data[i].t_data = data; maintenance_data[i].nb_threads = nb_threads; maintenance_data[i].set = set; maintenance_data[i].barrier = &barrier; if ((maintenance_data[i].t_nb_trans = (unsigned long *)malloc(nb_threads * sizeof(unsigned long))) == NULL) { perror("malloc"); exit(1); } for(j = 0; j < nb_threads; j++) { maintenance_data[i].t_nb_trans[j] = 0; } if ((maintenance_data[i].t_nb_trans_old = (unsigned long *)malloc(nb_threads * sizeof(unsigned long))) == NULL) { perror("malloc"); exit(1); } for(j = 0; j < nb_threads; j++) { maintenance_data[i].t_nb_trans_old[j] = 0; } printf("Creating maintenance thread %d\n", i); if (pthread_create(&maintenance_threads[i], &attr, test_maintenance, (void *)(&maintenance_data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); // Catch some signals if (signal(SIGHUP, catcher) == SIG_ERR || //signal(SIGINT, catcher) == SIG_ERR || signal(SIGTERM, catcher) == SIG_ERR) { perror("signal"); exit(1); } // Start threads barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } #ifdef ICC stop = 1; #else AO_store_full(&stop, 1); #endif /* ICC */ gettimeofday(&end, NULL); printf("STOPPING...\n"); // Wait for thread completion for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } // Wait for maintenance thread completion for (i = 0; i < nb_maintenance_threads; i++) { if (pthread_join(maintenance_threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for maintenance thread completion\n"); exit(1); } } duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); aborts = 0; aborts_locked_read = 0; aborts_locked_write = 0; aborts_validate_read = 0; aborts_validate_write = 0; aborts_validate_commit = 0; aborts_invalid_memory = 0; aborts_double_write = 0; failures_because_contention = 0; reads = 0; effreads = 0; updates = 0; effupds = 0; max_retries = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #add : %lu\n", data[i].nb_add); printf(" #added : %lu\n", data[i].nb_added); printf(" #remove : %lu\n", data[i].nb_remove); printf(" #removed : %lu\n", data[i].nb_removed); printf(" #contains : %lu\n", data[i].nb_contains); printf(" #found : %lu\n", data[i].nb_found); printf(" #aborts : %lu\n", data[i].nb_aborts); printf(" #lock-r : %lu\n", data[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", data[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", data[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", data[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", data[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", data[i].nb_aborts_invalid_memory); printf(" #dup-w : %lu\n", data[i].nb_aborts_double_write); printf(" #failures : %lu\n", data[i].failures_because_contention); printf(" Max retries : %lu\n", data[i].max_retries); printf(" #set read trans reads: %lu\n", data[i].set_read_reads); printf(" #set write trans reads: %lu\n", data[i].set_write_reads); printf(" #set write trans writes: %lu\n", data[i].set_write_writes); printf(" #set trans reads: %lu\n", data[i].set_reads); printf(" #set trans writes: %lu\n", data[i].set_writes); printf(" set max reads: %lu\n", data[i].set_max_reads); printf(" set max writes: %lu\n", data[i].set_max_writes); printf(" #read trans reads: %lu\n", data[i].read_reads); printf(" #write trans reads: %lu\n", data[i].write_reads); printf(" #write trans writes: %lu\n", data[i].write_writes); printf(" #trans reads: %lu\n", data[i].reads); printf(" #trans writes: %lu\n", data[i].writes); printf(" max reads: %lu\n", data[i].max_reads); printf(" max writes: %lu\n", data[i].max_writes); aborts += data[i].nb_aborts; aborts_locked_read += data[i].nb_aborts_locked_read; aborts_locked_write += data[i].nb_aborts_locked_write; aborts_validate_read += data[i].nb_aborts_validate_read; aborts_validate_write += data[i].nb_aborts_validate_write; aborts_validate_commit += data[i].nb_aborts_validate_commit; aborts_invalid_memory += data[i].nb_aborts_invalid_memory; aborts_double_write += data[i].nb_aborts_double_write; failures_because_contention += data[i].failures_because_contention; reads += data[i].nb_contains; effreads += data[i].nb_contains + (data[i].nb_add - data[i].nb_added) + (data[i].nb_remove - data[i].nb_removed); updates += (data[i].nb_add + data[i].nb_remove); effupds += data[i].nb_removed + data[i].nb_added; size += data[i].nb_added - data[i].nb_removed; if (max_retries < data[i].max_retries) max_retries = data[i].max_retries; } for (i = 0; i < nb_maintenance_threads; i++) { printf("Maintenance thread %d\n", i); printf(" #removed %lu\n", set->nb_removed); printf(" #rotated %lu\n", set->nb_rotated); printf(" #rotated sucs %lu\n", set->nb_suc_rotated); printf(" #propogated %lu\n", set->nb_propogated); printf(" #propogated sucs %lu\n", set->nb_suc_propogated); printf(" #aborts : %lu\n", maintenance_data[i].nb_aborts); printf(" #lock-r : %lu\n", maintenance_data[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", maintenance_data[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", maintenance_data[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", maintenance_data[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", maintenance_data[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", maintenance_data[i].nb_aborts_invalid_memory); printf(" #dup-w : %lu\n", maintenance_data[i].nb_aborts_double_write); //printf(" #failures : %lu\n", maintenance_data[i].failures_because_contention); printf(" Max retries : %lu\n", maintenance_data[i].max_retries); } printf("Set size : %d (expected: %d)\n", avl_set_size(set), size); printf("Tree size : %d\n", avl_tree_size(set)); printf("Duration : %d (ms)\n", duration); printf("#txs : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration); printf("#read txs : "); if (effective) { printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration); printf(" #contains : %lu (%f / s)\n", reads, reads * 1000.0 / duration); } else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration); printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads)); printf("#update txs : "); if (effective) { printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration); printf(" #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / duration); } else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration); printf("#aborts : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration); printf(" #lock-r : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration); printf(" #lock-w : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration); printf(" #val-r : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration); printf(" #val-w : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration); printf(" #val-c : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration); printf(" #inv-mem : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration); printf(" #dup-w : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration); printf(" #failures : %lu\n", failures_because_contention); printf("Max retries : %lu\n", max_retries); //print_avltree(set); // Delete set avl_set_delete(set); // Cleanup STM TM_SHUTDOWN(); #ifndef TLS pthread_key_delete(rng_seed_key); #endif /* ! TLS */ free(threads); free(data); free(maintenance_threads); free(maintenance_data); return 0; }
int main(int argc, char **argv) { struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"do-not-alternate", no_argument, NULL, 'a'}, #ifndef TM_COMPILER {"contention-manager", required_argument, NULL, 'c'}, #endif /* ! TM_COMPILER */ {"duration", required_argument, NULL, 'd'}, {"initial-size", required_argument, NULL, 'i'}, {"num-threads", required_argument, NULL, 'n'}, {"range", required_argument, NULL, 'r'}, {"seed", required_argument, NULL, 's'}, {"update-rate", required_argument, NULL, 'u'}, #ifdef USE_LINKEDLIST {"unit-tx", no_argument, NULL, 'x'}, #endif /* LINKEDLIST */ {NULL, 0, NULL, 0} }; intset_t *set; int i, c, val, size, ret; unsigned long reads, updates; #ifndef TM_COMPILER char *s; unsigned long aborts, aborts_1, aborts_2, aborts_locked_read, aborts_locked_write, aborts_validate_read, aborts_validate_write, aborts_validate_commit, aborts_invalid_memory, aborts_killed, locked_reads_ok, locked_reads_failed, max_retries; stm_ab_stats_t ab_stats; #endif /* ! TM_COMPILER */ thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; int duration = DEFAULT_DURATION; int initial = DEFAULT_INITIAL; int nb_threads = DEFAULT_NB_THREADS; int range = DEFAULT_RANGE; int seed = DEFAULT_SEED; int update = DEFAULT_UPDATE; int alternate = 1; #ifndef TM_COMPILER char *cm = NULL; #endif /* ! TM_COMPILER */ #ifdef USE_LINKEDLIST int unit_tx = 0; #endif /* LINKEDLIST */ sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "ha" #ifndef TM_COMPILER "c:" #endif /* ! TM_COMPILER */ "d:i:n:r:s:u:" #ifdef USE_LINKEDLIST "x" #endif /* LINKEDLIST */ , long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: /* Flag is automatically set */ break; case 'h': printf("intset -- STM stress test " #if defined(USE_LINKEDLIST) "(linked list)\n" #elif defined(USE_RBTREE) "(red-black tree)\n" #elif defined(USE_SKIPLIST) "(skip list)\n" #elif defined(USE_HASHSET) "(hash set)\n" #endif /* defined(USE_HASHSET) */ "\n" "Usage:\n" " intset [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -a, --do-not-alternate\n" " Do not alternate insertions and removals\n" #ifndef TM_COMPILER " -c, --contention-manager <string>\n" " Contention manager for resolving conflicts (default=suicide)\n" #endif /* ! TM_COMPILER */ " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -i, --initial-size <int>\n" " Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" " -r, --range <int>\n" " Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n" " -s, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" " -u, --update-rate <int>\n" " Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n" #ifdef USE_LINKEDLIST " -x, --unit-tx\n" " Use unit transactions\n" #endif /* LINKEDLIST */ ); exit(0); case 'a': alternate = 0; break; #ifndef TM_COMPILER case 'c': cm = optarg; break; #endif /* ! TM_COMPILER */ case 'd': duration = atoi(optarg); break; case 'i': initial = atoi(optarg); break; case 'n': nb_threads = atoi(optarg); break; case 'r': range = atoi(optarg); break; case 's': seed = atoi(optarg); break; case 'u': update = atoi(optarg); break; #ifdef USE_LINKEDLIST case 'x': unit_tx++; break; #endif /* LINKEDLIST */ case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(initial >= 0); assert(nb_threads > 0); assert(range > 0 && range >= initial); assert(update >= 0 && update <= 100); #if defined(USE_LINKEDLIST) printf("Set type : linked list\n"); #elif defined(USE_RBTREE) printf("Set type : red-black tree\n"); #elif defined(USE_SKIPLIST) printf("Set type : skip list\n"); #elif defined(USE_HASHSET) printf("Set type : hash set\n"); #endif /* defined(USE_HASHSET) */ #ifndef TM_COMPILER printf("CM : %s\n", (cm == NULL ? "DEFAULT" : cm)); #endif /* ! TM_COMPILER */ printf("Duration : %d\n", duration); printf("Initial size : %d\n", initial); printf("Nb threads : %d\n", nb_threads); printf("Value range : %d\n", range); printf("Seed : %d\n", seed); printf("Update rate : %d\n", update); printf("Alternate : %d\n", alternate); #ifdef USE_LINKEDLIST printf("Unit tx : %d\n", unit_tx); #endif /* LINKEDLIST */ printf("Type sizes : int=%d/long=%d/ptr=%d/word=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(size_t)); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(NULL)); else srand(seed); set = set_new(INIT_SET_PARAMETERS); stop = 0; /* Thread-local seed for main thread */ rand_init(main_seed); /* Init STM */ printf("Initializing STM\n"); TM_INIT; #ifndef TM_COMPILER if (stm_get_parameter("compile_flags", &s)) printf("STM flags : %s\n", s); if (cm != NULL) { if (stm_set_parameter("cm_policy", cm) == 0) printf("WARNING: cannot set contention manager \"%s\"\n", cm); } #endif /* ! TM_COMPILER */ if (alternate == 0 && range != initial * 2) printf("WARNING: range is not twice the initial set size\n"); /* Populate set */ printf("Adding %d entries to set\n", initial); i = 0; while (i < initial) { val = rand_range(range, main_seed) + 1; if (set_add(set, val, 0)) i++; } size = set_size(set); printf("Set size : %d\n", size); /* Access set from all threads */ barrier_init(&barrier, nb_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < nb_threads; i++) { printf("Creating thread %d\n", i); data[i].range = range; data[i].update = update; data[i].alternate = alternate; #ifdef USE_LINKEDLIST data[i].unit_tx = unit_tx; #endif /* LINKEDLIST */ data[i].nb_add = 0; data[i].nb_remove = 0; data[i].nb_contains = 0; data[i].nb_found = 0; #ifndef TM_COMPILER data[i].nb_aborts = 0; data[i].nb_aborts_1 = 0; data[i].nb_aborts_2 = 0; data[i].nb_aborts_locked_read = 0; data[i].nb_aborts_locked_write = 0; data[i].nb_aborts_validate_read = 0; data[i].nb_aborts_validate_write = 0; data[i].nb_aborts_validate_commit = 0; data[i].nb_aborts_invalid_memory = 0; data[i].nb_aborts_killed = 0; data[i].locked_reads_ok = 0; data[i].locked_reads_failed = 0; data[i].max_retries = 0; #endif /* ! TM_COMPILER */ data[i].diff = 0; rand_init(data[i].seed); data[i].set = set; data[i].barrier = &barrier; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); /* Start threads */ barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } stop = 1; gettimeofday(&end, NULL); printf("STOPPING...\n"); /* Wait for thread completion */ for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); #ifndef TM_COMPILER aborts = 0; aborts_1 = 0; aborts_2 = 0; aborts_locked_read = 0; aborts_locked_write = 0; aborts_validate_read = 0; aborts_validate_write = 0; aborts_validate_commit = 0; aborts_invalid_memory = 0; aborts_killed = 0; locked_reads_ok = 0; locked_reads_failed = 0; max_retries = 0; #endif /* ! TM_COMPILER */ reads = 0; updates = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #add : %lu\n", data[i].nb_add); printf(" #remove : %lu\n", data[i].nb_remove); printf(" #contains : %lu\n", data[i].nb_contains); printf(" #found : %lu\n", data[i].nb_found); #ifndef TM_COMPILER printf(" #aborts : %lu\n", data[i].nb_aborts); printf(" #lock-r : %lu\n", data[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", data[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", data[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", data[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", data[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", data[i].nb_aborts_invalid_memory); printf(" #killed : %lu\n", data[i].nb_aborts_killed); printf(" #aborts>=1 : %lu\n", data[i].nb_aborts_1); printf(" #aborts>=2 : %lu\n", data[i].nb_aborts_2); printf(" #lr-ok : %lu\n", data[i].locked_reads_ok); printf(" #lr-failed : %lu\n", data[i].locked_reads_failed); printf(" Max retries : %lu\n", data[i].max_retries); aborts += data[i].nb_aborts; aborts_1 += data[i].nb_aborts_1; aborts_2 += data[i].nb_aborts_2; aborts_locked_read += data[i].nb_aborts_locked_read; aborts_locked_write += data[i].nb_aborts_locked_write; aborts_validate_read += data[i].nb_aborts_validate_read; aborts_validate_write += data[i].nb_aborts_validate_write; aborts_validate_commit += data[i].nb_aborts_validate_commit; aborts_invalid_memory += data[i].nb_aborts_invalid_memory; aborts_killed += data[i].nb_aborts_killed; locked_reads_ok += data[i].locked_reads_ok; locked_reads_failed += data[i].locked_reads_failed; if (max_retries < data[i].max_retries) max_retries = data[i].max_retries; #endif /* ! TM_COMPILER */ reads += data[i].nb_contains; updates += (data[i].nb_add + data[i].nb_remove); size += data[i].diff; } printf("Set size : %d (expected: %d)\n", set_size(set), size); ret = (set_size(set) != size); printf("Duration : %d (ms)\n", duration); printf("#txs : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration); printf("#read txs : %lu (%f / s)\n", reads, reads * 1000.0 / duration); printf("#update txs : %lu (%f / s)\n", updates, updates * 1000.0 / duration); #ifndef TM_COMPILER printf("#aborts : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration); printf(" #lock-r : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration); printf(" #lock-w : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration); printf(" #val-r : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration); printf(" #val-w : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration); printf(" #val-c : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration); printf(" #inv-mem : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration); printf(" #killed : %lu (%f / s)\n", aborts_killed, aborts_killed * 1000.0 / duration); printf("#aborts>=1 : %lu (%f / s)\n", aborts_1, aborts_1 * 1000.0 / duration); printf("#aborts>=2 : %lu (%f / s)\n", aborts_2, aborts_2 * 1000.0 / duration); printf("#lr-ok : %lu (%f / s)\n", locked_reads_ok, locked_reads_ok * 1000.0 / duration); printf("#lr-failed : %lu (%f / s)\n", locked_reads_failed, locked_reads_failed * 1000.0 / duration); printf("Max retries : %lu\n", max_retries); for (i = 0; stm_get_ab_stats(i, &ab_stats) != 0; i++) { printf("Atomic block : %d\n", i); printf(" #samples : %lu\n", ab_stats.samples); printf(" Mean : %f\n", ab_stats.mean); printf(" Variance : %f\n", ab_stats.variance); printf(" Min : %f\n", ab_stats.min); printf(" Max : %f\n", ab_stats.max); printf(" 50th perc. : %f\n", ab_stats.percentile_50); printf(" 90th perc. : %f\n", ab_stats.percentile_90); printf(" 95th perc. : %f\n", ab_stats.percentile_95); } #endif /* ! TM_COMPILER */ /* Delete set */ set_delete(set); /* Cleanup STM */ TM_EXIT; free(threads); free(data); return ret; }
static void *test(void *data) { int op, val, last = -1; thread_data_t *d = (thread_data_t *)data; /* Create transaction */ TM_INIT_THREAD; /* Wait on barrier */ barrier_cross(d->barrier); while (stop == 0) { op = rand_range(100, d->seed); if (op < d->update) { if (d->alternate) { /* Alternate insertions and removals */ if (last < 0) { /* Add random value */ val = rand_range(d->range, d->seed) + 1; if (set_add(d->set, val, d)) { d->diff++; last = val; } d->nb_add++; } else { /* Remove last value */ if (set_remove(d->set, last, d)) d->diff--; d->nb_remove++; last = -1; } } else { /* Randomly perform insertions and removals */ val = rand_range(d->range, d->seed) + 1; if ((op & 0x01) == 0) { /* Add random value */ if (set_add(d->set, val, d)) d->diff++; d->nb_add++; } else { /* Remove random value */ if (set_remove(d->set, val, d)) d->diff--; d->nb_remove++; } } } else { /* Look for random value */ val = rand_range(d->range, d->seed) + 1; if (set_contains(d->set, val, d)) d->nb_found++; d->nb_contains++; } } #ifndef TM_COMPILER stm_get_stats("nb_aborts", &d->nb_aborts); stm_get_stats("nb_aborts_1", &d->nb_aborts_1); stm_get_stats("nb_aborts_2", &d->nb_aborts_2); stm_get_stats("nb_aborts_locked_read", &d->nb_aborts_locked_read); stm_get_stats("nb_aborts_locked_write", &d->nb_aborts_locked_write); stm_get_stats("nb_aborts_validate_read", &d->nb_aborts_validate_read); stm_get_stats("nb_aborts_validate_write", &d->nb_aborts_validate_write); stm_get_stats("nb_aborts_validate_commit", &d->nb_aborts_validate_commit); stm_get_stats("nb_aborts_invalid_memory", &d->nb_aborts_invalid_memory); stm_get_stats("nb_aborts_killed", &d->nb_aborts_killed); stm_get_stats("locked_reads_ok", &d->locked_reads_ok); stm_get_stats("locked_reads_failed", &d->locked_reads_failed); stm_get_stats("max_retries", &d->max_retries); #endif /* ! TM_COMPILER */ /* Free transaction */ TM_EXIT_THREAD; return NULL; }
void *test2(void *data) { int val, newval, last, flag = 1; int id; ulong *tloc; thread_data_t *d = (thread_data_t *)data; id = d->id; tloc = d->set->nb_committed; /* Create transaction */ TM_THREAD_ENTER(); /* Wait on barrier */ barrier_cross(d->barrier); last = 0; // to avoid warning while (stop == 0) { val = rand_range_re(&d->seed, 100) - 1; /* added for HashTables */ if (val < d->update) { if (val >= d->move) { /* update without move */ if (flag) { /* Add random value */ val = (rand_r(&d->seed) % d->range) + 1; if (avl_add(d->set, val, TRANSACTIONAL, id)) { d->nb_added++; last = val; flag = 0; } d->nb_trans++; tloc[id]++; d->nb_add++; } else { if (d->alternate) { /* Remove last value */ if (avl_remove(d->set, last, TRANSACTIONAL, id)) d->nb_removed++; d->nb_trans++; tloc[id]++; d->nb_remove++; flag = 1; } else { /* Random computation only in non-alternated cases */ newval = rand_range_re(&d->seed, d->range); if (avl_remove(d->set, newval, TRANSACTIONAL, id)) { d->nb_removed++; /* Repeat until successful, to avoid size variations */ flag = 1; } d->nb_trans++; tloc[id]++; d->nb_remove++; } } } else { /* move */ val = rand_range_re(&d->seed, d->range); if (avl_move(d->set, last, val, TRANSACTIONAL, id)) { d->nb_moved++; last = val; } d->nb_trans++; tloc[id]++; d->nb_move++; } } else { if (val >= d->update + d->snapshot) { /* read-only without snapshot */ /* Look for random value */ val = rand_range_re(&d->seed, d->range); if (avl_contains(d->set, val, TRANSACTIONAL, id)) d->nb_found++; d->nb_trans++; tloc[id]++; d->nb_contains++; } else { /* snapshot */ if (avl_snapshot(d->set, TRANSACTIONAL, id)) d->nb_snapshoted++; d->nb_trans++; tloc[id]++; d->nb_snapshot++; } } } /* Free transaction */ TM_THREAD_EXIT(); return NULL; }
void *test_throughput(void *data) { thread_data_t *d = (thread_data_t *)data; #ifndef NO_SET_CPU int phys_id = the_cores[d->id]; set_cpu(phys_id); #endif int rand_max; #if defined(TEST_CTR) data_type old_data; data_type new_data; #endif volatile uint64_t res; seeds = seed_rand(); rand_max = num_entries - 1; barrier_cross(d->barrier); int entry=0; while (stop == 0) { if (num_entries>1) { entry =(int) my_random(&(seeds[0]),&(seeds[1]),&(seeds[2])) & rand_max; } #ifdef TEST_CAS if ((d->num_operations)&1) { res = CAS_U8(&(the_data[entry].data),1,0); } else { res = CAS_U8(&(the_data[entry].data),0,1); } #elif defined(TEST_SWAP) # ifdef __sparc__ if ((d->num_operations)&1) { res = SWAP_U32(&(the_data[entry].data),0); } else { res = SWAP_U32(&(the_data[entry].data),1); } # else if ((d->num_operations)&1) { res = SWAP_U8(&(the_data[entry].data),0); } else { res = SWAP_U8(&(the_data[entry].data),1); } # endif #elif defined(TEST_CTR) do { old_data=the_data[entry].data; new_data=old_data+1; } while (CAS_U8(&(the_data[entry].data),old_data,new_data)!=old_data); #elif defined(TEST_TAS) res = TAS_U8(&(the_data[entry].data)); if (res==0) { the_data[entry].data = 0; } #elif defined(TEST_FAI) FAI_U8(&(the_data[entry].data)); #else perror("No test primitive specified"); #endif d->num_operations++; if (op_pause>0) { cpause(op_pause); } } /* avoid warning of unused var*/ if (res == 12345654) { printf("%d", (int) res); } return NULL; }
void *test_latency(void *data) { thread_data_t *d = (thread_data_t *)data; #ifndef NO_SET_CPU int phys_id = the_cores[d->id]; set_cpu(phys_id); #endif int rand_max; #if defined(TEST_CTR) data_type old_data; data_type new_data; #endif volatile uint64_t res; seeds = seed_rand(); rand_max = num_entries - 1; unsigned long do_not_measure=0; int entry=0; ticks t1 = 0, t2 = 0; barrier_cross(d->barrier); while (stop == 0) { if (num_entries>1) { entry =(int) my_random(&(seeds[0]),&(seeds[1]),&(seeds[2])) & rand_max; } do_not_measure=(d->num_operations) & 0x1f; #ifdef TEST_CAS if ((d->num_operations)&1) { res = CAS_U8(&(the_data[entry].data),1,0); } else { if (!do_not_measure) { t1=getticks(); # ifdef __tile__ MEM_BARRIER; # endif res = CAS_U8(&(the_data[entry].data),0,1); # ifdef __tile__ MEM_BARRIER; # endif t2=getticks(); } else { res = CAS_U8(&(the_data[entry].data),0,1); } } #elif defined(TEST_SWAP) if ((d->num_operations)&1) { res = SWAP_U8(&(the_data[entry].data),0); } else { if (do_not_measure) { res = SWAP_U8(&(the_data[entry].data),1); } else { t1=getticks(); # ifdef __tile__ MEM_BARRIER; # endif res = SWAP_U8(&(the_data[entry].data),1); # ifdef __tile__ MEM_BARRIER; # endif t2=getticks(); } } #elif defined(TEST_CTR) if (do_not_measure) { do { old_data=the_data[entry].data; new_data=old_data+1; } while (CAS_U8(&(the_data[entry].data),old_data,new_data)!=old_data); } else { t1=getticks(); # ifdef __tile__ MEM_BARRIER; # endif do { old_data=the_data[entry].data; new_data=old_data+1; } while (CAS_U8(&(the_data[entry].data),old_data,new_data)!=old_data); # ifdef __tile__ MEM_BARRIER; # endif t2=getticks(); } #elif defined(TEST_TAS) if (do_not_measure) { res = TAS_U8(&(the_data[entry].data)); } else { t1=getticks(); # ifdef __tile__ MEM_BARRIER; # endif res = TAS_U8(&(the_data[entry].data)); # ifdef __tile__ MEM_BARRIER; # endif t2=getticks(); } if (res==0) { the_data[entry].data = 0; } #elif defined(TEST_FAI) if (do_not_measure) { FAI_U8(&(the_data[entry].data)); } else { t1=getticks(); # ifdef __tile__ MEM_BARRIER; # endif FAI_U8(&(the_data[entry].data)); # ifdef __tile__ MEM_BARRIER; # endif t2=getticks(); } #else perror("No test primitive specified"); #endif if (!do_not_measure) { d->num_measured++; d->total_time+=t2-t1-correction; } d->num_operations++; if (op_pause>0) { cpause(op_pause); } } /* avoid warning of unused var*/ if (res == 12345654) { printf("%d", (int) res); } return NULL; }
void *test(void *data) { int val2, numtx, r, last = -1; val_t val = 0; int unext, mnext, cnext; thread_data_t *d = (thread_data_t *)data; /* Create transaction */ TM_THREAD_ENTER(); /* Wait on barrier */ barrier_cross(d->barrier); /* Is the first op an update, a move? */ r = rand_range_re(&d->seed, 100) - 1; unext = (r < d->update); mnext = (r < d->move); cnext = (r >= d->update + d->snapshot); #ifdef ICC while (stop == 0) { #else while (AO_load_full(&stop) == 0) { #endif /* ICC */ if (unext) { // update if (mnext) { // move if (last == -1) val = rand_range_re(&d->seed, d->range); val2 = rand_range_re(&d->seed, d->range); if (ht_move(d->set, val, val2, TRANSACTIONAL)) { d->nb_moved++; last = val2; } d->nb_move++; } else if (last < 0) { // add val = rand_range_re(&d->seed, d->range); if (ht_add(d->set, val, TRANSACTIONAL)) { d->nb_added++; last = val; } d->nb_add++; } else { // remove if (d->alternate) { // alternate mode if (ht_remove(d->set, last, TRANSACTIONAL)) { d->nb_removed++; last = -1; } } else { /* Random computation only in non-alternated cases */ val = rand_range_re(&d->seed, d->range); /* Remove one random value */ if (ht_remove(d->set, val, TRANSACTIONAL)) { d->nb_removed++; /* Repeat until successful, to avoid size variations */ last = -1; } } d->nb_remove++; } } else { // reads if (cnext) { // contains (no snapshot) if (d->alternate) { if (d->update == 0) { if (last < 0) { val = d->first; last = val; } else { // last >= 0 val = rand_range_re(&d->seed, d->range); last = -1; } } else { // update != 0 if (last < 0) { val = rand_range_re(&d->seed, d->range); //last = val; } else { val = last; } } } else val = rand_range_re(&d->seed, d->range); if (ht_contains(d->set, val, TRANSACTIONAL)) d->nb_found++; d->nb_contains++; } else { // snapshot if (ht_snapshot(d->set, TRANSACTIONAL)) d->nb_snapshoted++; d->nb_snapshot++; } } /* Is the next op an update, a move, a contains? */ if (d->effective) { // a failed remove/add is a read-only tx numtx = d->nb_contains + d->nb_add + d->nb_remove + d->nb_move + d->nb_snapshot; unext = ((100.0 * (d->nb_added + d->nb_removed + d->nb_moved)) < (d->update * numtx)); mnext = ((100.0 * d->nb_moved) < (d->move * numtx)); cnext = !((100.0 * d->nb_snapshoted) < (d->snapshot * numtx)); } else { // remove/add (even failed) is considered as an update r = rand_range_re(&d->seed, 100) - 1; unext = (r < d->update); mnext = (r < d->move); cnext = (r >= d->update + d->snapshot); } #ifdef ICC } #else } #endif /* ICC */ /* Free transaction */ TM_THREAD_EXIT(); return NULL; }
int main(int argc, char **argv) { set_cpu(the_cores[0]); struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"accounts", required_argument, NULL, 'a'}, {"duration", required_argument, NULL, 'd'}, {"num-threads", required_argument, NULL, 'n'}, {"check", required_argument, NULL, 'c'}, {"deposit_perc", required_argument, NULL, 'e'}, {"servers", required_argument, NULL, 's'}, {"withdraws", required_argument, NULL, 'w'}, {NULL, 0, NULL, 0} }; bank_t *bank; int i, c; unsigned long reads, writes, updates; thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; int nb_threads = DEFAULT_NUM_THREADS; int duration = DEFAULT_DURATION; int nb_accounts = DEFAULT_NB_ACCOUNTS; int balance_perc = DEFAULT_BALANCE_PERC; int deposit_perc = DEFAULT_DEPOSIT_PERC; int seed = DEFAULT_SEED; int withdraw_perc = DEFAULT_WITHDRAW_PERC; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "ha:c:d:n:r:e:s:w:W:j", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: /* Flag is automatically set */ break; case 'h': printf("bank -- lock stress test\n" "\n" "Usage:\n" " bank [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -a, --accounts <int>\n" " Number of accounts in the bank (default=" XSTR(DEFAULT_NB_ACCOUNTS) ")\n" " -d, --duraiton <int>\n" " Duration of the test in ms (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NUM_THREADS) ")\n" " -c, --check <int>\n" " Percentage of check balance transactions (default=" XSTR(DEFAULT_BALANCE_PERC) ")\n" " -e, --deposit_perc <int>\n" " Percentage of deposit transactions (default=" XSTR(DEFAULT_DEPOSIT_PERC) ")\n" " -w, --withdraws <int>\n" " Percentage of withdraw_perc transactions (default=" XSTR(DEFAULT_WITHDRAW_PERC) ")\n" ); exit(0); case 'a': nb_accounts = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'n': nb_threads = atoi(optarg); break; case 'c': balance_perc = atoi(optarg); break; case 'e': deposit_perc = atoi(optarg); break; case 'w': withdraw_perc = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(nb_accounts >= 2); assert(nb_threads > 0); assert(balance_perc >= 0 && withdraw_perc >= 0 && deposit_perc >= 0 && deposit_perc + balance_perc + withdraw_perc <= 100); nb_accounts = pow2roundup(nb_accounts); uint32_t missing = 100 - (deposit_perc + balance_perc + withdraw_perc); if (missing > 0) { balance_perc += missing; } printf("Nb accounts : %d\n", nb_accounts); printf("Num ops : %d\n", duration); printf("Nb threads : %d\n", nb_threads); printf("Check balance : %d\n", balance_perc); printf("Deposit : %d\n", deposit_perc); printf("Withdraws : %d\n", withdraw_perc); withdraw_perc += deposit_perc; balance_perc += withdraw_perc; timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(NULL)); else srand(seed); bank = (bank_t *)malloc(sizeof(bank_t)); bank->accounts = (account_t *)malloc(nb_accounts * sizeof(account_t)); bank->size = nb_accounts; for (i = 0; i < bank->size; i++) { bank->accounts[i].number = i; bank->accounts[i].balance = 0; } gl.lock_data = 0; local_th_data = (local_data *)malloc(nb_threads*sizeof(local_data)); stop = 0; /* Init locks */ printf("Initializing locks\n"); the_locks = init_lock_array_global(nb_accounts, nb_threads); /* Access set from all threads */ barrier_init(&barrier, nb_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < nb_threads; i++) { printf("Creating thread %d\n", i); data[i].id = i; data[i].nb_threads = nb_threads; data[i].nb_balance = 0; data[i].nb_deposit = 0; data[i].nb_withdraw = 0; data[i].balance_perc = balance_perc; data[i].deposit_perc = deposit_perc; data[i].withdraw_perc = withdraw_perc; data[i].seed = rand(); data[i].bank = bank; data[i].barrier = &barrier; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); /* Catch some signals */ if (signal(SIGHUP, catcher) == SIG_ERR || signal(SIGINT, catcher) == SIG_ERR || signal(SIGTERM, catcher) == SIG_ERR) { perror("signal"); exit(1); } /* Start threads */ barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } stop = 1; gettimeofday(&end, NULL); printf("STOPPING...\n"); /* Wait for thread completion */ for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); reads = 0; writes = 0; updates = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #balance : %lu\n", data[i].nb_balance); printf(" #withdraw : %lu\n", data[i].nb_withdraw); printf(" #deposit : %lu\n", data[i].nb_deposit); updates += data[i].nb_withdraw; reads += data[i].nb_balance; writes += data[i].nb_deposit; } /* printf("Bank total : %d (expected: 0)\n", total(bank, 0)); */ printf("Duration : %d (ms)\n", duration); printf("#read txs : %lu ( %f / s)\n", reads, reads * 1000.0 / duration); printf("#write txs : %lu ( %f / s)\n", writes, writes * 1000.0 / duration); printf("#update txs : %lu ( %f / s)\n", updates, updates * 1000.0 / duration); printf("#txs : %lu ( %f / s)\n", reads + writes + updates, (reads + writes + updates) * 1000.0 / duration); /* Delete bank and accounts */ free(bank->accounts); free(bank); /* Cleanup locks */ //free_global(the_locks, nb_accounts); //free(threads); //free(data); return 0; }
void *test(void *data) { int unext, last = -1; val_t val = 0; thread_data_t *d = (thread_data_t *)data; /* Wait on barrier */ barrier_cross(d->barrier); /* Is the first op an update? */ unext = (rand_range_re(&d->seed, 100) - 1 < d->update); while (stop == 0) { if (unext) { // update if (last < 0) { // add val = rand_range_re(&d->seed, d->range); if (set_add_l(d->set, val, TRANSACTIONAL)) { d->nb_added++; last = val; } d->nb_add++; } else { // remove if (d->alternate) { // alternate mode if (set_remove_l(d->set, last, TRANSACTIONAL)) { d->nb_removed++; } last = -1; } else { val = rand_range_re(&d->seed, d->range); if (set_remove_l(d->set, val, TRANSACTIONAL)) { d->nb_removed++; last = -1; } } d->nb_remove++; } } else { // read if (d->alternate) { if (d->update == 0) { if (last < 0) { val = d->first; last = val; } else { // last >= 0 val = rand_range_re(&d->seed, d->range); last = -1; } } else { // update != 0 if (last < 0) { val = rand_range_re(&d->seed, d->range); //last = val; } else { val = last; } } } else val = rand_range_re(&d->seed, d->range); if (set_contains_l(d->set, val, TRANSACTIONAL)) d->nb_found++; d->nb_contains++; } /* Is the next op an update? */ if (d->effective) { // a failed remove/add is a read-only tx unext = ((100 * (d->nb_added + d->nb_removed)) < (d->update * (d->nb_add + d->nb_remove + d->nb_contains))); } else { // remove/add (even failed) is considered an update unext = (rand_range_re(&d->seed, 100) - 1 < d->update); } } return NULL; }
int main(int argc, char **argv) { struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"duration", required_argument, NULL, 'd'}, {"initial-size", required_argument, NULL, 'i'}, {"thread-num", required_argument, NULL, 't'}, {"range", required_argument, NULL, 'r'}, {"seed", required_argument, NULL, 'S'}, {"update-rate", required_argument, NULL, 'u'}, {"unit-tx", required_argument, NULL, 'x'}, {NULL, 0, NULL, 0} }; intset_l_t *set; int i, c, size; val_t last = 0; val_t val = 0; unsigned long reads, effreads, updates, effupds, aborts, aborts_locked_read, aborts_locked_write, aborts_validate_read, aborts_validate_write, aborts_validate_commit, aborts_invalid_memory, max_retries; thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; int duration = DEFAULT_DURATION; int initial = DEFAULT_INITIAL; int nb_threads = DEFAULT_NB_THREADS; long range = DEFAULT_RANGE; int seed = DEFAULT_SEED; int update = DEFAULT_UPDATE; int unit_tx = DEFAULT_LOCKTYPE; int alternate = DEFAULT_ALTERNATE; int effective = DEFAULT_EFFECTIVE; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "hAf:d:i:t:r:S:u:x:", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: /* Flag is automatically set */ break; case 'h': printf("intset -- STM stress test " "(linked list)\n" "\n" "Usage:\n" " intset [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -A, --alternate (default="XSTR(DEFAULT_ALTERNATE)")\n" " Consecutive insert/remove target the same value\n" " -f, --effective <int>\n" " update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -i, --initial-size <int>\n" " Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n" " -t, --thread-num <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" " -r, --range <int>\n" " Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n" " -S, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" " -u, --update-rate <int>\n" " Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n" " -x, --lock-based algorithm (default=1)\n" " Use lock-based algorithm\n" " 1 = lock-coupling,\n" " 2 = lazy algorithm\n" ); exit(0); case 'A': alternate = 1; break; case 'f': effective = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'i': initial = atoi(optarg); break; case 't': nb_threads = atoi(optarg); break; case 'r': range = atol(optarg); break; case 'S': seed = atoi(optarg); break; case 'u': update = atoi(optarg); break; case 'x': printf("The parameter x is not valid for this benchmark.\n"); exit(0); case 'a': printf("The parameter a is not valid for this benchmark.\n"); exit(0); case 's': printf("The parameter s is not valid for this benchmark.\n"); exit(0); case '?': printf("Use -h or --help for help.\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(initial >= 0); assert(nb_threads > 0); assert(range > 0 && range >= initial); assert(update >= 0 && update <= 100); printf("Set type : lazy linked list\n"); printf("Length : %d\n", duration); printf("Initial size : %d\n", initial); printf("Thread num : %d\n", nb_threads); printf("Value range : %ld\n", range); printf("Seed : %d\n", seed); printf("Update rate : %d\n", update); printf("Lock alg : %d\n", unit_tx); printf("Alternate : %d\n", alternate); printf("Effective : %d\n", effective); printf("Type sizes : int=%d/long=%d/ptr=%d/word=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(uintptr_t)); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(0)); else srand(seed); set = set_new_l(); stop = 0; /* Init STM */ printf("Initializing STM\n"); /* Populate set */ printf("Adding %d entries to set\n", initial); i = 0; while (i < initial) { val = (rand() % range) + 1; if (set_add_l(set, val, 0)) { last = val; i++; } } size = set_size_l(set); printf("Set size : %d\n", size); /* Access set from all threads */ barrier_init(&barrier, nb_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < nb_threads; i++) { printf("Creating thread %d\n", i); data[i].first = last; data[i].range = range; data[i].update = update; data[i].alternate = alternate; data[i].unit_tx = unit_tx; data[i].alternate = alternate; data[i].effective = effective; data[i].nb_add = 0; data[i].nb_added = 0; data[i].nb_remove = 0; data[i].nb_removed = 0; data[i].nb_contains = 0; data[i].nb_found = 0; data[i].nb_aborts = 0; data[i].nb_aborts_locked_read = 0; data[i].nb_aborts_locked_write = 0; data[i].nb_aborts_validate_read = 0; data[i].nb_aborts_validate_write = 0; data[i].nb_aborts_validate_commit = 0; data[i].nb_aborts_invalid_memory = 0; data[i].max_retries = 0; data[i].seed = rand(); data[i].set = set; data[i].barrier = &barrier; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); /* Start threads */ barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } AO_store_full(&stop, 1); gettimeofday(&end, NULL); printf("STOPPING...\n"); /* Wait for thread completion */ for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); aborts = 0; aborts_locked_read = 0; aborts_locked_write = 0; aborts_validate_read = 0; aborts_validate_write = 0; aborts_validate_commit = 0; aborts_invalid_memory = 0; reads = 0; effreads = 0; updates = 0; effupds = 0; max_retries = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #add : %lu\n", data[i].nb_add); printf(" #added : %lu\n", data[i].nb_added); printf(" #remove : %lu\n", data[i].nb_remove); printf(" #removed : %lu\n", data[i].nb_removed); printf(" #contains : %lu\n", data[i].nb_contains); printf(" #found : %lu\n", data[i].nb_found); printf(" #aborts : %lu\n", data[i].nb_aborts); printf(" #lock-r : %lu\n", data[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", data[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", data[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", data[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", data[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", data[i].nb_aborts_invalid_memory); printf(" Max retries : %lu\n", data[i].max_retries); aborts += data[i].nb_aborts; aborts_locked_read += data[i].nb_aborts_locked_read; aborts_locked_write += data[i].nb_aborts_locked_write; aborts_validate_read += data[i].nb_aborts_validate_read; aborts_validate_write += data[i].nb_aborts_validate_write; aborts_validate_commit += data[i].nb_aborts_validate_commit; aborts_invalid_memory += data[i].nb_aborts_invalid_memory; reads += data[i].nb_contains; effreads += data[i].nb_contains + (data[i].nb_add - data[i].nb_added) + (data[i].nb_remove - data[i].nb_removed); updates += (data[i].nb_add + data[i].nb_remove); effupds += data[i].nb_removed + data[i].nb_added; //size += data[i].diff; size += data[i].nb_added - data[i].nb_removed; if (max_retries < data[i].max_retries) max_retries = data[i].max_retries; } printf("Set size : %d (expected: %d)\n", set_size_l(set), size); printf("Duration : %d (ms)\n", duration); printf("#txs : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration); printf("#read txs : "); if (effective) { printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration); printf(" #contains : %lu (%f / s)\n", reads, reads * 1000.0 / duration); } else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration); printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads)); printf("#update txs : "); if (effective) { printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration); printf(" #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / duration); } else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration); printf("#aborts : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration); printf(" #lock-r : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration); printf(" #lock-w : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration); printf(" #val-r : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration); printf(" #val-w : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration); printf(" #val-c : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration); printf(" #inv-mem : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration); printf("Max retries : %lu\n", max_retries); /* Delete set */ set_delete_l(set); free(threads); free(data); return 0; }
int main(int argc, char* const argv[]) { //place thread on the first cpu set_cpu(0); //initialize the custom memory allocator ssalloc_init(); pthread_t *threads; pthread_attr_t attr; barrier_t barrier; pthread_mutex_t init_lock; struct timeval start, end; struct timespec timeout; thread_data_t *data; sigset_t block_set; //initially, set parameters to their default values num_threads = DEFAULT_NUM_THREADS; seed=DEFAULT_SEED; max_key=DEFAULT_RANGE; updates=DEFAULT_UPDATES; finds=DEFAULT_READS; //inserts=DEFAULT_INSERTS; //removes=DEFAULT_REMOVES; duration=DEFAULT_DURATION; //now read the parameters in case the user provided values for them //we use getopt, the same skeleton may be used for other bechmarks, //though the particular parameters may be different struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"duration", required_argument, NULL, 'd'}, {"range", required_argument, NULL, 'r'}, {"initial", required_argument, NULL, 'i'}, {"num-threads", required_argument, NULL, 'n'}, {"updates", required_argument, NULL, 'u'}, {"seed", required_argument, NULL, 's'}, {NULL, 0, NULL, 0} }; int i,c; //actually get the parameters form the command-line while(1) { i = 0; c = getopt_long(argc, argv, "hd:n:l:u:i:r:s", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: /* Flag is automatically set */ break; case 'h': printf("lock stress test\n" "\n" "Usage:\n" " stress_test [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -u, --updates <int>\n" " Percentage of update operations (default=" XSTR(DEFAULT_UPDATES) ")\n" " -r, --range <int>\n" " Key range (default=" XSTR(DEFAULT_RANGE) ")\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NUM_THREADS) ")\n" " -s, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" ); exit(0); case 'd': duration = atoi(optarg); break; case 'u': updates = atoi(optarg); finds = 100 - updates; break; case 'r': max_key = atoi(optarg); break; case 'i': break; case 'l': break; case 'n': num_threads = atoi(optarg); break; case 's': seed = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } max_key--; //we round the max key up to the nearest power of 2, which makes our random key generation more efficient max_key = pow2roundup(max_key)-1; //initialization of the tree root = bst_initialize(num_threads); //initialize the data which will be passed to the threads if ((data = (thread_data_t *)malloc(num_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(num_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(NULL)); else srand(seed); //flag signaling the threads until when to run *running = 1; //global barrier initialization (used to start the threads at the same time) barrier_init(&barrier, num_threads + 1); pthread_mutex_init(&init_lock, NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; //set the data for each thread and create the threads for (i = 0; i < num_threads; i++) { data[i].id = i; data[i].num_operations = 0; data[i].total_time=0; data[i].num_insert=0; data[i].num_remove=0; data[i].num_search=0; data[i].num_add = max_key/(2 * num_threads); if (i< ((max_key/2)%num_threads)) data[i].num_add++; data[i].seed = rand(); data[i].barrier = &barrier; data[i].init_lock = &init_lock; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); /* Catch some signals */ if (signal(SIGHUP, catcher) == SIG_ERR || signal(SIGINT, catcher) == SIG_ERR || signal(SIGTERM, catcher) == SIG_ERR) { perror("signal"); exit(1); } // seeds = seed_rand(); // skey_t key; // for (i=0;i<max_key/2;++i) { // key = my_random(&seeds[0],&seeds[1],&seeds[2]) & max_key; // //we make sure the insert was effective (as opposed to just updating an existing entry) // if (bst_add(key, root, 0)!=TRUE) { // i--; // } // } // bst_print(root); /* Start threads */ barrier_cross(&barrier); gettimeofday(&start, NULL); if (duration > 0) { //sleep for the duration of the experiment nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } //signal the threads to stop *running = 0; gettimeofday(&end, NULL); /* Wait for thread completion */ for (i = 0; i < num_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } DDPRINT("threads finshed\n",NULL); //compute the exact duration of the experiment duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); //bst_print(root); unsigned long operations = 0; ticks total_ticks = 0; long reported_total = 1; //the tree contains two initial dummy nodes, INF1 and INF2 //report some experiment statistics for (i = 0; i < num_threads; i++) { printf("Thread %d\n", i); printf(" #operations : %lu\n", data[i].num_operations); printf(" #inserts : %lu\n", data[i].num_insert); printf(" #removes : %lu\n", data[i].num_remove); operations += data[i].num_operations; total_ticks += data[i].total_time; reported_total = reported_total + data[i].num_add + data[i].num_insert - data[i].num_remove; } printf("Duration : %d (ms)\n", duration); printf("#txs : %lu (%f / s)\n", operations, operations * 1000.0 / duration); //printf("Operation latency %lu\n", total_ticks / operations); //make sure the tree is correct printf("Expected size: %ld Actual size: %lu\n",reported_total,bst_size(root)); free(threads); free(data); return 0; }
void* test(void* thread) { size_t num_retry_cas1 = 0, num_retry_cas2 = 0, num_retry_cas3 = 0 , num_retry_cas4 = 0, num_retry_cas5 = 0; thread_data_t* td = (thread_data_t*) thread; uint8_t ID = td->id; phys_id = the_cores[ID % (NUMBER_OF_SOCKETS * CORES_PER_SOCKET)]; set_cpu(phys_id); ssmem_allocator_t* alloc = (ssmem_allocator_t*) memalign(CACHE_LINE_SIZE, sizeof(ssmem_allocator_t)); assert(alloc != NULL); ssmem_alloc_init(alloc, SSMEM_DEFAULT_MEM_SIZE, ID); ssmem_gc_thread_init(alloc, ID); PF_INIT(3, SSPFD_NUM_ENTRIES, ID); #if defined(COMPUTE_LATENCY) volatile ticks my_putting_succ = 0; volatile ticks my_putting_fail = 0; volatile ticks my_getting_succ = 0; volatile ticks my_getting_fail = 0; volatile ticks my_removing_succ = 0; volatile ticks my_removing_fail = 0; #endif uint64_t my_putting_count = 0; uint64_t my_getting_count = 0; uint64_t my_removing_count = 0; uint64_t my_putting_count_succ = 0; uint64_t my_getting_count_succ = 0; uint64_t my_removing_count_succ = 0; #if defined(COMPUTE_LATENCY) && PFD_TYPE == 0 volatile ticks start_acq, end_acq; volatile ticks correction = getticks_correction_calc(); #endif seeds = seed_rand(); MEM_BARRIER; barrier_cross(&barrier); barrier_cross(&barrier_global); size_t obj_size_bytes = obj_size * sizeof(size_t); volatile size_t* dat = (size_t*) malloc(obj_size_bytes); assert(dat != NULL); size_t* obj = NULL; while (stop == 0) { size_t rand = (my_random(&(seeds[0]), &(seeds[1]), &(seeds[2]))); size_t k = (rand & 1) + 2; rand &= 1023; /* search baby! */ int i; for (i = 0; i < KEY_BUCKT; i++) { volatile uintptr_t v = val[i]; if (snap->map[i] == MAP_VALID && key[i] == k) { if (val[i] == v) { if (GET_VAL(v) != k) { printf("[%02d] :get: key != val for %zu\n", ID, k); } break; } } } if (rand > 513) { my_putting_count++; if (obj != NULL) { ssmem_free(alloc, (void*) obj); } obj = ssmem_alloc(alloc, 8); *obj = k; int empty_index = -2; clht_snapshot_t s; retry: s.snapshot = snap->snapshot; int i; for (i = 0; i < KEY_BUCKT; i++) { volatile uintptr_t v = val[i]; if (snap->map[i] == MAP_VALID && key[i] == k) { if (val[i] == v) { if (empty_index > 0) { snap->map[empty_index] = MAP_INVLD; } goto end; } } } clht_snapshot_all_t s1; if (empty_index < 0) { empty_index = snap_get_empty_index(s.snapshot); if (empty_index < 0) { num_retry_cas1++; goto end; } s1 = snap_set_map(s.snapshot, empty_index, MAP_INSRT); if (CAS_U64(&snap->snapshot, s.snapshot, s1) != s.snapshot) { empty_index = -2; num_retry_cas2++; goto retry; } val[empty_index] = (uintptr_t) obj; key[empty_index] = k; } else { s1 = snap_set_map(s.snapshot, empty_index, MAP_INSRT); } clht_snapshot_all_t s2 = snap_set_map_and_inc_version(s1, empty_index, MAP_VALID); if (CAS_U64(&snap->snapshot, s1, s2) != s1) { num_retry_cas3++; /* key[empty_index] = 0; */ /* val[empty_index] = 0; */ goto retry; } obj = NULL; my_putting_count_succ++; end: ; } else { my_removing_count++; clht_snapshot_t s; retry_rem: s.snapshot = snap->snapshot; volatile uintptr_t v; int i, removed = 0; for (i = 0; i < KEY_BUCKT && !removed; i++) { if (key[i] == k && s.map[i] == MAP_VALID) { v = val[i]; clht_snapshot_all_t s1 = snap_set_map(s.snapshot, i, MAP_INVLD); if (CAS_U64(&snap->snapshot, s.snapshot, s1) == s.snapshot) { /* snap->map[i] = MAP_INVLD; */ removed = 1; } else { num_retry_cas4++; goto retry_rem; } } } if (removed) { ssmem_free(alloc, (void*) v); my_removing_count_succ++; } } } free((void*) dat); #if defined(DEBUG) if (put_num_restarts | put_num_failed_expand | put_num_failed_on_new) { /* printf("put_num_restarts = %3u / put_num_failed_expand = %3u / put_num_failed_on_new = %3u \n", */ /* put_num_restarts, put_num_failed_expand, put_num_failed_on_new); */ } #endif if (ID < 2) { printf("#retry-stats-thread-%d: #cas1: %-8zu / #cas2: %-8zu /" "#cas3: %-8zu / #cas4: %-8zu / #cas5: %-8zu\n", ID, num_retry_cas1, num_retry_cas2, num_retry_cas3, num_retry_cas4, num_retry_cas5); } /* printf("gets: %-10llu / succ: %llu\n", num_get, num_get_succ); */ /* printf("rems: %-10llu / succ: %llu\n", num_rem, num_rem_succ); */ barrier_cross(&barrier); #if defined(COMPUTE_LATENCY) putting_succ[ID] += my_putting_succ; putting_fail[ID] += my_putting_fail; getting_succ[ID] += my_getting_succ; getting_fail[ID] += my_getting_fail; removing_succ[ID] += my_removing_succ; removing_fail[ID] += my_removing_fail; #endif putting_count[ID] += my_putting_count; getting_count[ID] += my_getting_count; removing_count[ID]+= my_removing_count; putting_count_succ[ID] += my_putting_count_succ; getting_count_succ[ID] += my_getting_count_succ; removing_count_succ[ID]+= my_removing_count_succ; #if (PFD_TYPE == 1) && defined(COMPUTE_LATENCY) if (ID == 0) { printf("get ----------------------------------------------------\n"); SSPFDPN(0, SSPFD_NUM_ENTRIES, print_vals_num); printf("put ----------------------------------------------------\n"); SSPFDPN(1, SSPFD_NUM_ENTRIES, print_vals_num); printf("rem ----------------------------------------------------\n"); SSPFDPN(2, SSPFD_NUM_ENTRIES, print_vals_num); } #endif /* SSPFDTERM(); */ pthread_exit(NULL); }
int main(int argc, char **argv) { set_cpu(the_cores[0]); ssalloc_init(); seeds = seed_rand(); #ifdef PAPI if (PAPI_VER_CURRENT != PAPI_library_init(PAPI_VER_CURRENT)) { printf("PAPI_library_init error.\n"); return 0; } else { printf("PAPI_library_init success.\n"); } if (PAPI_OK != PAPI_query_event(PAPI_L1_DCM)) { printf("Cannot count PAPI_L1_DCM."); } printf("PAPI_query_event: PAPI_L1_DCM OK.\n"); if (PAPI_OK != PAPI_query_event(PAPI_L2_DCM)) { printf("Cannot count PAPI_L2_DCM."); } printf("PAPI_query_event: PAPI_L2_DCM OK.\n"); #endif struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"duration", required_argument, NULL, 'd'}, {"priority-queue", required_argument, NULL, 'p'}, {"linden", required_argument, NULL, 'L'}, {"spray-list", required_argument, NULL, 'l'}, {"event-simulator", required_argument, NULL, 'e'}, {"initial-size", required_argument, NULL, 'i'}, {"num-threads", required_argument, NULL, 'n'}, {"range", required_argument, NULL, 'r'}, {"seed", required_argument, NULL, 's'}, {"update-rate", required_argument, NULL, 'u'}, {"elasticity", required_argument, NULL, 'x'}, {"nothing", required_argument, NULL, 'l'}, {NULL, 0, NULL, 0} }; sl_intset_t *set; pq_t *linden_set; int i, c, size; val_t last = 0; val_t val = 0; pval_t pval = 0; unsigned long reads, effreads, updates, collisions, effupds, aborts, aborts_locked_read, aborts_locked_write, aborts_validate_read, aborts_validate_write, aborts_validate_commit, add, added, remove, removed, aborts_invalid_memory, aborts_double_write, max_retries, failures_because_contention, depdist; thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; int duration = DEFAULT_DURATION; int initial = DEFAULT_INITIAL; int nb_threads = DEFAULT_NB_THREADS; long range = DEFAULT_RANGE; int seed = DEFAULT_SEED; int seed2 = DEFAULT_SEED; int update = DEFAULT_UPDATE; int unit_tx = DEFAULT_ELASTICITY; int alternate = DEFAULT_ALTERNATE; int pq = DEFAULT_PQ; int sl = DEFAULT_SL; int es = DEFAULT_ES; int lin = DEFAULT_LIN; int effective = DEFAULT_EFFECTIVE; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "hAplLe:f:d:i:n:r:s:u:x:l:", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: break; case 'h': printf("intset -- STM stress test " "(skip list)\n" "\n" "Usage:\n" " intset [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -A, --Alternate\n" " Consecutive insert/remove target the same value\n" " -l, --spray-list\n" " Remove via delete_min operations using a spray list\n" " -p, --priority-queue\n" " Remove via delete_min operations using a skip list\n" " -e, --event-simulator\n" " Descrete event simulator experiment, parameter = dependency distance\n" " -L, --linden\n" " Use Linden's priority queue\n" " -f, --effective <int>\n" " update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -i, --initial-size <int>\n" " Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" " -r, --range <int>\n" " Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n" " -s, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" " -u, --update-rate <int>\n" " Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n" " -x, --elasticity (default=4)\n" " Use elastic transactions\n" " 0 = non-protected,\n" " 1 = normal transaction,\n" " 2 = read elastic-tx,\n" " 3 = read/add elastic-tx,\n" " 4 = read/add/rem elastic-tx,\n" " 5 = fraser lock-free\n" ); exit(0); case 'A': alternate = 1; break; case 'l': sl = 1; break; case 'p': pq = 1; break; case 'e': es = 1; depdist = atoi(optarg); break; case 'L': lin = 1; break; case 'f': effective = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'i': initial = atoi(optarg); break; case 'n': nb_threads = atoi(optarg); break; case 'r': range = atol(optarg); break; case 's': seed = atoi(optarg); break; case 'u': update = atoi(optarg); break; case 'x': unit_tx = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(initial >= 0); assert(nb_threads > 0); assert(range > 0); assert(update >= 0 && update <= 100); // if (range < initial) // { range = 100000000; // } printf("Set type : skip list\n"); printf("Duration : %d\n", duration); printf("Initial size : %u\n", initial); printf("Nb threads : %d\n", nb_threads); printf("Value range : %ld\n", range); printf("Seed : %d\n", seed); printf("Update rate : %d\n", update); printf("Elasticity : %d\n", unit_tx); printf("Alternate : %d\n", alternate); printf("Priority Q : %d\n", pq); printf("Spray List : %d\n", sl); printf("Linden : %d\n", lin); printf("Efffective : %d\n", effective); printf("Type sizes : int=%d/long=%d/ptr=%d/word=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(uintptr_t)); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(0)); else srand(seed); *levelmax = floor_log_2((unsigned int) initial); set = sl_set_new(); /* stop = 0; */ *running = 1; // Init STM printf("Initializing STM\n"); TM_STARTUP(); // Populate set printf("Adding %d entries to set\n", initial); i = 0; if (lin) { int offset = 32; // not sure what this does _init_gc_subsystem(); linden_set = pq_init(offset); } if (es) { // event simulator has event ids 1..m // no timeout in ES, finishes when list is empty // timeout.tv_sec = 0; // timeout.tv_nsec = 0; if ((nb_deps = (int *)malloc(initial * sizeof(int))) == NULL) { perror("malloc"); exit(1); } if ((deps = (val_t **)malloc(initial * sizeof(val_t*))) == NULL) { perror("malloc"); exit(1); } while (i < initial) { if ((deps[i] = (val_t*)malloc(MAX_DEPS * sizeof(val_t))) == NULL) { perror("malloc"); exit(1); } int num_deps = 0; nb_deps[i] = 0; if (lin) { insert(linden_set, i, i); } else { sl_add(set, (val_t)i, 0); } while (i < initial-1 && num_deps < MAX_DEPS && rand_range_re(NULL, 3) % 2) { // Add geometrically distributed # of deps TODO: parametrize '2' val_t dep = ((val_t)i)+1; int dep_var = sqrt(depdist); dep += depdist + rand_range_re(NULL,2*dep_var) - dep_var; if (dep >= initial) dep = initial-1; // while (dep < initial-1 && rand_range_re(NULL, 11) % 10) { // dep should be i+GEO(10) TODO: parametrize '10' // dep++; // } deps[i][num_deps] = dep; num_deps++; } nb_deps[i] = num_deps; if (num_deps < MAX_DEPS) { deps[i][num_deps] = -1; // marks last dep } i++; } } else if (lin) { while (i < initial) { #ifdef DISTRIBUTION_EXPERIMENT pval = i; #else pval = rand_range_re(NULL, range); #endif insert(linden_set, pval, pval); last = pval; i++; } } else { while (i < initial) { #ifdef DISTRIBUTION_EXPERIMENT val = i; #else val = rand_range_re(NULL, range); #endif if (sl_add(set, val, 0)) { last = val; i++; } } } #ifdef PRINT_LIST print_skiplist(set); #endif size = sl_set_size(set); printf("Set size : %d\n", size); printf("Level max : %d\n", *levelmax); // Access set from all threads barrier_init(&barrier, nb_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); printf("Creating threads: "); for (i = 0; i < nb_threads; i++) { printf("%d, ", i); data[i].first = last; data[i].range = range; data[i].update = update; data[i].unit_tx = unit_tx; data[i].alternate = alternate; data[i].pq = pq; data[i].sl = sl; data[i].es = es; data[i].effective = effective; data[i].first_remove = -1; data[i].nb_collisions = 0; data[i].nb_add = 0; data[i].nb_clean = 0; data[i].nb_added = 0; data[i].nb_remove = 0; data[i].nb_removed = 0; data[i].nb_contains = 0; data[i].nb_found = 0; data[i].nb_aborts = 0; data[i].nb_aborts_locked_read = 0; data[i].nb_aborts_locked_write = 0; data[i].nb_aborts_validate_read = 0; data[i].nb_aborts_validate_write = 0; data[i].nb_aborts_validate_commit = 0; data[i].nb_aborts_invalid_memory = 0; data[i].nb_aborts_double_write = 0; data[i].max_retries = 0; data[i].nb_threads = nb_threads; data[i].seed = rand(); data[i].seed2 = rand(); data[i].set = set; data[i].barrier = &barrier; data[i].failures_because_contention = 0; data[i].id = i; /* LINDEN */ data[i].lin = lin; data[i].linden_set = linden_set; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); // Catch some signals if (signal(SIGHUP, catcher) == SIG_ERR || //signal(SIGINT, catcher) == SIG_ERR || signal(SIGTERM, catcher) == SIG_ERR) { perror("signal"); exit(1); } // Start threads barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); #ifndef DISTRIBUTION_EXPERIMENT // don't sleep if doing distro experiment if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } #endif /* AO_store_full(&stop, 1); */ *running = 0; // if (!es) { gettimeofday(&end, NULL); // } printf("STOPPING...\n"); // Wait for thread completion for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } // if (es) { // gettimeofday(&end, NULL); // time when all threads finish // } printf ("duration = %d\n", duration); duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); printf ("duration = %d\n", duration); aborts = 0; aborts_locked_read = 0; aborts_locked_write = 0; aborts_validate_read = 0; aborts_validate_write = 0; aborts_validate_commit = 0; aborts_invalid_memory = 0; aborts_double_write = 0; failures_because_contention = 0; reads = 0; effreads = 0; updates = 0; collisions = 0; add = 0; added = 0; remove = 0; removed = 0; effupds = 0; max_retries = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #add : %lu\n", data[i].nb_add); printf(" #added : %lu\n", data[i].nb_added); printf(" #remove : %lu\n", data[i].nb_remove); printf(" #removed : %lu\n", data[i].nb_removed); printf(" #cleaned : %lu\n", data[i].nb_clean); printf("first remove : %d\n", data[i].first_remove); printf(" #collisions : %lu\n", data[i].nb_collisions); printf(" #contains : %lu\n", data[i].nb_contains); printf(" #found : %lu\n", data[i].nb_found); printf(" #aborts : %lu\n", data[i].nb_aborts); printf(" #lock-r : %lu\n", data[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", data[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", data[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", data[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", data[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", data[i].nb_aborts_invalid_memory); printf(" #dup-w : %lu\n", data[i].nb_aborts_double_write); printf(" #failures : %lu\n", data[i].failures_because_contention); printf(" Max retries : %lu\n", data[i].max_retries); aborts += data[i].nb_aborts; aborts_locked_read += data[i].nb_aborts_locked_read; aborts_locked_write += data[i].nb_aborts_locked_write; aborts_validate_read += data[i].nb_aborts_validate_read; aborts_validate_write += data[i].nb_aborts_validate_write; aborts_validate_commit += data[i].nb_aborts_validate_commit; aborts_invalid_memory += data[i].nb_aborts_invalid_memory; aborts_double_write += data[i].nb_aborts_double_write; failures_because_contention += data[i].failures_because_contention; reads += data[i].nb_contains; effreads += data[i].nb_contains + (data[i].nb_add - data[i].nb_added) + (data[i].nb_remove - data[i].nb_removed); updates += (data[i].nb_add + data[i].nb_remove); collisions += data[i].nb_collisions; add += data[i].nb_add; added += data[i].nb_added; remove += data[i].nb_remove; removed += data[i].nb_removed; effupds += data[i].nb_removed + data[i].nb_added; size += data[i].nb_added - data[i].nb_removed; if (max_retries < data[i].max_retries) max_retries = data[i].max_retries; } printf("Set size : %d (expected: %d)\n", sl_set_size(set), size); printf("Duration : %d (ms)\n", duration); printf("#txs : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration); printf("#read txs : "); if (effective) { printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration); printf(" #contains : %lu (%f / s)\n", reads, reads * 1000.0 / duration); } else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration); printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads)); printf("#update txs : "); if (effective) { printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration); printf(" #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / duration); } else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration); printf("#total_remove : %lu\n", remove); printf("#total_removed: %lu\n", removed); printf("#total_add : %lu\n", add); printf("#total_added : %lu\n", added); printf("#net (rem-add): %lu\n", removed-added); printf("#total_collide: %lu\n", collisions); printf("#norm_collide : %f\n", ((double)collisions)/removed); printf("#aborts : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration); printf(" #lock-r : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration); printf(" #lock-w : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration); printf(" #val-r : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration); printf(" #val-w : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration); printf(" #val-c : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration); printf(" #inv-mem : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration); printf(" #dup-w : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration); printf(" #failures : %lu\n", failures_because_contention); printf("Max retries : %lu\n", max_retries); #ifdef PRINT_END print_skiplist(set); #endif #ifdef PAPI long total_L1_miss = 0; unsigned k = 0; for (k = 0; k < nb_threads; k++) { total_L1_miss += g_values[k][0]; //printf("[Thread %d] L1_DCM: %lld\n", i, g_values[i][0]); //printf("[Thread %d] L2_DCM: %lld\n", i, g_values[i][1]); } printf("\n#L1 Cache Misses: %lld\n", total_L1_miss); printf("#Normalized Cache Misses: %f\n", ((double)total_L1_miss)/(reads+updates)); #endif // Delete set sl_set_delete(set); // Cleanup STM TM_SHUTDOWN(); free(threads); free(data); return 0; }
int main(int argc, char **argv) { set_cpu(the_cores[0]); assert(sizeof(clht_hashtable_t) == 2*CACHE_LINE_SIZE); struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"duration", required_argument, NULL, 'd'}, {"num-threads", required_argument, NULL, 'n'}, {"range", required_argument, NULL, 'r'}, {"correctness", no_argument, NULL, 'c'}, {"num-buckets", required_argument, NULL, 'b'}, {"print-vals", required_argument, NULL, 'v'}, {"vals-pf", required_argument, NULL, 'f'}, {"obj-size", required_argument, NULL, 's'}, {NULL, 0, NULL, 0} }; int i, c; while(1) { i = 0; c = getopt_long(argc, argv, "hAf:d:i:n:r:s:u:m:a:l:p:b:v:f:c", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: /* Flag is automatically set */ break; case 'h': printf("intset -- STM stress test " "(linked list)\n" "\n" "Usage:\n" " intset [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -d, --duration <int>\n" " Test duration in milliseconds\n" " -n, --num-threads <int>\n" " Number of threads\n" " -r, --range <int>\n" " Range of integer values inserted in set\n" " -s, --obj-size <int>\n" " Size of the objects stored in the hash table\n" " -b, --num-buckets <int>\n" " Number of initial buckets (stronger than -l)\n" " -v, --print-vals <int>\n" " When using detailed profiling, how many values to print.\n" " -f, --val-pf <int>\n" " When using detailed profiling, how many values to keep track of.\n" ); exit(0); case 'd': duration = atoi(optarg); break; case 'n': num_threads = atoi(optarg); break; case 's': obj_size = atol(optarg); break; case 'v': print_vals_num = atoi(optarg); break; case 'f': pf_vals_num = pow2roundup(atoi(optarg)) - 1; break; case '?': default: printf("Use -h or --help for help\n"); exit(1); } } rand_max = num_elements; struct timeval start, end; struct timespec timeout; timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; printf("//duration: sec: %lu, ns: %lu\n", timeout.tv_sec, timeout.tv_nsec); stop = 0; /* Initialize the hashtable */ snap = (clht_snapshot_t*) memalign(CACHE_LINE_SIZE, CACHE_LINE_SIZE); assert(snap != NULL); /* Initializes the local data */ putting_succ = (ticks *) calloc(num_threads , sizeof(ticks)); putting_fail = (ticks *) calloc(num_threads , sizeof(ticks)); getting_succ = (ticks *) calloc(num_threads , sizeof(ticks)); getting_fail = (ticks *) calloc(num_threads , sizeof(ticks)); removing_succ = (ticks *) calloc(num_threads , sizeof(ticks)); removing_fail = (ticks *) calloc(num_threads , sizeof(ticks)); putting_count = (ticks *) calloc(num_threads , sizeof(ticks)); putting_count_succ = (ticks *) calloc(num_threads , sizeof(ticks)); getting_count = (ticks *) calloc(num_threads , sizeof(ticks)); getting_count_succ = (ticks *) calloc(num_threads , sizeof(ticks)); removing_count = (ticks *) calloc(num_threads , sizeof(ticks)); removing_count_succ = (ticks *) calloc(num_threads , sizeof(ticks)); pthread_t threads[num_threads]; pthread_attr_t attr; int rc; void *status; barrier_init(&barrier_global, num_threads + 1); barrier_init(&barrier, num_threads); /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); thread_data_t* tds = (thread_data_t*) malloc(num_threads * sizeof(thread_data_t)); long t; for(t = 0; t < num_threads; t++) { tds[t].id = t; rc = pthread_create(&threads[t], &attr, test, tds + t); if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } /* Free attribute and wait for the other threads */ pthread_attr_destroy(&attr); barrier_cross(&barrier_global); gettimeofday(&start, NULL); nanosleep(&timeout, NULL); stop = 1; gettimeofday(&end, NULL); duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); for(t = 0; t < num_threads; t++) { rc = pthread_join(threads[t], &status); if (rc) { printf("ERROR; return code from pthread_join() is %d\n", rc); exit(-1); } } free(tds); volatile ticks putting_suc_total = 1; volatile ticks putting_fal_total = 1; volatile ticks getting_suc_total = 1; volatile ticks getting_fal_total = 1; volatile ticks removing_suc_total = 1; volatile ticks removing_fal_total = 1; volatile uint64_t putting_count_total = 1; volatile uint64_t putting_count_total_succ = 1; volatile uint64_t getting_count_total = 1; volatile uint64_t getting_count_total_succ = 1; volatile uint64_t removing_count_total = 1; volatile uint64_t removing_count_total_succ = 1; for(t=0; t < num_threads; t++) { putting_suc_total += putting_succ[t]; putting_fal_total += putting_fail[t]; getting_suc_total += getting_succ[t]; getting_fal_total += getting_fail[t]; removing_suc_total += removing_succ[t]; removing_fal_total += removing_fail[t]; putting_count_total += putting_count[t]; putting_count_total_succ += putting_count_succ[t]; getting_count_total += getting_count[t]; getting_count_total_succ += getting_count_succ[t]; removing_count_total += removing_count[t]; removing_count_total_succ += removing_count_succ[t]; } if(putting_count_total == 0) { putting_suc_total = 0; putting_fal_total = 0; putting_count_total = 1; putting_count_total_succ = 2; } if(getting_count_total == 0) { getting_suc_total = 0; getting_fal_total = 0; getting_count_total = 1; getting_count_total_succ = 2; } if(removing_count_total == 0) { removing_suc_total = 0; removing_fal_total = 0; removing_count_total = 1; removing_count_total_succ = 2; } #if defined(COMPUTE_LATENCY) # if defined(DEBUG) printf("#thread get_suc get_fal put_suc put_fal rem_suc rem_fal\n"); fflush(stdout); # endif printf("%d\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\n", num_threads, getting_suc_total / getting_count_total_succ, getting_fal_total / (getting_count_total - getting_count_total_succ), putting_suc_total / putting_count_total_succ, putting_fal_total / (putting_count_total - putting_count_total_succ), removing_suc_total / removing_count_total_succ, removing_fal_total / (removing_count_total - removing_count_total_succ) ); #endif #define LLU long long unsigned int int pr = (int) (putting_count_total_succ - removing_count_total_succ); int size_after = 0; for (i = 0; i < rand_max; i++) { size_after += (snap->map[i] == MAP_VALID); } printf("\n"); printf("#Maps | "); for (i = 0; i < rand_max; i++) { printf("#%d = %-5d | ", i, snap->map[i]); } printf("\n"); printf("#Keys | "); for (i = 0; i < rand_max; i++) { printf("#%d = %-5jd | ", i, key[i]); } printf("\n"); printf("#Vals | "); for (i = 0; i < rand_max; i++) { printf("#%d = %-5jd | ", i, (val[i]) ? *(size_t*) val[i] : -1); } printf("\n"); #if defined(DEBUG) printf("puts - rems : %d\n", pr); #endif /* assert(size_after == (pr)); */ if (size_after != pr) { printf("###### SIZE missmatch\n"); } printf(" : %-10s | %-10s | %-11s | %s\n", "total", "success", "succ %", "total %"); uint64_t total = putting_count_total + getting_count_total + removing_count_total; double putting_perc = 100.0 * (1 - ((double)(total - putting_count_total) / total)); double removing_perc = 100.0 * (1 - ((double)(total - removing_count_total) / total)); printf("puts: %-10llu | %-10llu | %10.1f%% | %.1f%%\n", (LLU) putting_count_total, (LLU) putting_count_total_succ, (1 - (double) (putting_count_total - putting_count_total_succ) / putting_count_total) * 100, putting_perc); printf("rems: %-10llu | %-10llu | %10.1f%% | %.1f%%\n", (LLU) removing_count_total, (LLU) removing_count_total_succ, (1 - (double) (removing_count_total - removing_count_total_succ) / removing_count_total) * 100, removing_perc); size_t all_total = putting_count_total + getting_count_total + removing_count_total; double throughput = (all_total) * 1000.0 / duration; printf("#txs tot (%zu\n", all_total); printf("#txs %-4d(%-10.0f = %.3f M\n", num_threads, throughput, throughput / 1e6); /* Last thing that main() should do */ //printf("Main: program completed. Exiting.\n"); pthread_exit(NULL); return 0; }
int main(int argc, char **argv) { set_cpu(the_cores[0]); ssalloc_init(); seeds = seed_rand(); pin(pthread_self(), 0); #ifdef PAPI if (PAPI_VER_CURRENT != PAPI_library_init(PAPI_VER_CURRENT)) { printf("PAPI_library_init error.\n"); return 0; } else { printf("PAPI_library_init success.\n"); } if (PAPI_OK != PAPI_query_event(PAPI_L1_DCM)) { printf("Cannot count PAPI_L1_DCM."); } printf("PAPI_query_event: PAPI_L1_DCM OK.\n"); if (PAPI_OK != PAPI_query_event(PAPI_L2_DCM)) { printf("Cannot count PAPI_L2_DCM."); } printf("PAPI_query_event: PAPI_L2_DCM OK.\n"); #endif struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"num-threads", required_argument, NULL, 'n'}, {"seed", required_argument, NULL, 's'}, {"input-file", required_argument, NULL, 'i'}, {"output-file", required_argument, NULL, 'o'}, {"max-size", required_argument, NULL, 'm'}, {"nothing", required_argument, NULL, 'l'}, {NULL, 0, NULL, 0} }; sl_intset_t *set; pq_t *linden_set; int i, c, size, edges; unsigned long reads, effreads, updates, collisions, effupds, add, added, remove, removed; thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; int nb_threads = DEFAULT_NB_THREADS; int seed = DEFAULT_SEED; int seed2 = DEFAULT_SEED; int pq = DEFAULT_PQ; int sl = DEFAULT_SL; int lin = DEFAULT_LIN; char *input = ""; char *output = ""; int src = 0; int max = -1; int weighted = 0; int bimodal = 0; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "hplLwbn:s:i:o:m:", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: break; case 'h': printf("SSSP " "(priority queue)\n" "\n" "Usage:\n" " sssp [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -l, --spray-list\n" " Remove via delete_min operations using a spray list\n" " -p, --priority-queue\n" " Remove via delete_min operations using a skip list\n" " -L, --linden\n" " Use Linden's priority queue\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" " -s, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" " -i, --input-file <string>\n" " file to read the graph from (required) \n" " -o, --output-file <string>\n" " file to write the resulting shortest paths to\n" " -m, --max-size <int>\n" " if input graph exceeds max-size, use only first max-size nodes\n" " -w, --weighted\n" " use random edge weights uniformly chosen in [0,1]; fixed between trials given fixed seed\n" " -b, --bimodal\n" " use random edge weights chosen in [20,30]U[70,80]; fixed between trials given fixed seed\n" ); exit(0); case 'l': sl = 1; break; case 'p': pq = 1; break; case 'L': lin = 1; break; case 'w': weighted = 1; break; case 'b': bimodal = 1; break; case 'n': nb_threads = atoi(optarg); break; case 's': seed = atoi(optarg); break; case 'i': input = optarg; break; case 'o': output = optarg; break; case 'm': max = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(nb_threads > 0); if (seed == 0) srand((int)time(0)); else srand(seed); printf("Set type : skip list\n"); printf("Nb threads : %d\n", nb_threads); printf("Seed : %d\n", seed); printf("Priority Q : %d\n", pq); printf("Spray List : %d\n", sl); printf("Linden : %d\n", lin); printf("Type sizes : int=%d/long=%d/ptr=%d/word=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(uintptr_t)); if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } // TODO: Build graph here FILE* fp = fopen(input, "r"); fscanf(fp, "# Nodes: %d Edges: %d\n", &size, &edges); if (size > max && max != -1) size = max; #ifndef STATIC if ((nodes = (graph_node_t*)malloc(size * sizeof(graph_node_t))) == NULL) { perror("malloc"); exit(1); } #endif for (i = 0;i < size;i++) { nodes[i].deg = 0; nodes[i].dist = -1; nodes[i].times_processed = 0; } int u,v; int cur = 0, count = 0; while (fscanf(fp, "%d %d\n", &u, &v) == 2) { if (u >= size) continue; if (v >= size) continue; nodes[u].deg++; } #ifndef STATIC for (i = 0;i < size;i++) { if ((nodes[i].adj = (int*)malloc(nodes[i].deg * sizeof(int))) == NULL) { perror("malloc"); exit(1); } if ((nodes[i].weights = (int*)malloc(nodes[i].deg * sizeof(int))) == NULL) { perror("malloc"); exit(1); } } #endif fclose(fp); nodes[src].dist = 0; fp = fopen(input, "r"); int tmp; fscanf(fp, "# Nodes: %d Edges: %d\n", &tmp, &edges); int *idx; if ((idx= (int*)malloc(size * sizeof(int))) == NULL) { perror("malloc"); exit(1); } for (i = 0;i < size;i++) { idx[i] = 0; } while (fscanf(fp, "%d %d\n", &u, &v) == 2) { if (u >= size) continue; if (v >= size) continue; assert(idx[u] < nodes[u].deg); nodes[u].adj[idx[u]] = v; if (weighted) { nodes[u].weights[idx[u]] = rand() % 100; } else if (bimodal) { if (rand() % 2) { nodes[u].weights[idx[u]] = (rand() % 11) + 20; } else { nodes[u].weights[idx[u]] = (rand() % 11) + 70; } } else { nodes[u].weights[idx[u]] = 1; } idx[u]++; } free(idx); // for (u = 0; u < size; u++) { // for (count = 0; count < nodes[u].deg; count++) { // printf("%d %d\n", u, nodes[u].adj[count]); // } // } // pq/sl *levelmax = floor_log_2(size)+2; set = sl_set_new(); sl_add_val(set, 0, src, TRANSACTIONAL); // linden if (lin) { int offset = 32; // not sure what this does _init_gc_subsystem(); linden_set = pq_init(offset); insert(linden_set, 1, src); nodes[src].dist = 1; // account for the fact that keys must be positive } printf("Graph size : %d\n", size); printf("Level max : %d\n", *levelmax); // Access set from all threads barrier_init(&barrier, nb_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); printf("Creating threads: "); for (i = 0; i < nb_threads; i++) { printf("%d, ", i); data[i].pq = pq; data[i].sl = sl; data[i].first_remove = -1; data[i].nb_collisions = 0; data[i].nb_add = 0; data[i].nb_clean = 0; data[i].nb_added = 0; data[i].nb_remove = 0; data[i].nb_removed = 0; data[i].nb_contains = 0; data[i].nb_found = 0; data[i].nb_aborts = 0; data[i].nb_aborts_locked_read = 0; data[i].nb_aborts_locked_write = 0; data[i].nb_aborts_validate_read = 0; data[i].nb_aborts_validate_write = 0; data[i].nb_aborts_validate_commit = 0; data[i].nb_aborts_invalid_memory = 0; data[i].nb_aborts_double_write = 0; data[i].max_retries = 0; data[i].nb_threads = nb_threads; data[i].seed = rand(); data[i].seed2 = rand(); data[i].set = set; data[i].barrier = &barrier; data[i].failures_because_contention = 0; data[i].id = i; /* LINDEN */ data[i].lin = lin; data[i].linden_set = linden_set; if (pthread_create(&threads[i], &attr, sssp, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); // Catch some signals if (signal(SIGHUP, catcher) == SIG_ERR || //signal(SIGINT, catcher) == SIG_ERR || signal(SIGTERM, catcher) == SIG_ERR) { perror("signal"); exit(1); } /* stop = 0; */ *running = 1; // Start threads barrier_cross(&barrier); printf("STARTING...\n"); gettimeofday(&start, NULL); // Wait for thread completion for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } gettimeofday(&end, NULL); printf("STOPPING...\n"); long nb_processed = 0; long unreachable = 0; if (strcmp(output,"")) { FILE *out = fopen(output, "w"); for (i = 0;i < size;i++) { fprintf(out, "%d %d\n", i, nodes[i].dist); } fclose(out); } else { for (i = 0;i < size;i++) { printf("%d %d\n", i, nodes[i].dist); } } for (i = 0;i < size;i++) { nb_processed += nodes[i].times_processed; if (nodes[i].times_processed == 0) { unreachable++; } } int duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); printf ("duration = %d\n", duration); reads = 0; effreads = 0; updates = 0; collisions = 0; add = 0; added = 0; remove = 0; removed = 0; effupds = 0; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #add : %lu\n", data[i].nb_add); printf(" #added : %lu\n", data[i].nb_added); printf(" #remove : %lu\n", data[i].nb_remove); printf(" #removed : %lu\n", data[i].nb_removed); printf(" #cleaned : %lu\n", data[i].nb_clean); printf(" #collisions : %lu\n", data[i].nb_collisions); printf(" #contains : %lu\n", data[i].nb_contains); printf(" #found : %lu\n", data[i].nb_found); reads += data[i].nb_contains; effreads += data[i].nb_contains + (data[i].nb_add - data[i].nb_added) + (data[i].nb_remove - data[i].nb_removed); updates += (data[i].nb_add + data[i].nb_remove); collisions += data[i].nb_collisions; add += data[i].nb_add; added += data[i].nb_added; remove += data[i].nb_remove; removed += data[i].nb_removed; effupds += data[i].nb_removed + data[i].nb_added; size += data[i].nb_added - data[i].nb_removed; } printf("Set size : %d (expected: %d)\n", sl_set_size(set), size); printf("nodes processed:%d\n", nb_processed); printf("unreachable : %d\n", unreachable); printf("wasted work : %d\n", nb_processed - (size - unreachable)); printf("Duration : %d (ms)\n", duration); printf("#ops : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration); printf("#read ops : "); printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration); printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads)); printf("#update ops : "); printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration); printf("#total_remove : %lu\n", remove); printf("#total_removed: %lu\n", removed); printf("#total_add : %lu\n", add); printf("#total_added : %lu\n", added); printf("#net (rem-add): %lu\n", removed-added); printf("#total_collide: %lu\n", collisions); printf("#norm_collide : %f\n", ((double)collisions)/removed); #ifdef PRINT_END print_skiplist(set); #endif #ifdef PAPI long total_L1_miss = 0; unsigned k = 0; for (k = 0; k < nb_threads; k++) { total_L1_miss += g_values[k][0]; total_L2_miss += g_values[k][1]; //printf("[Thread %d] L1_DCM: %lld\n", i, g_values[i][0]); //printf("[Thread %d] L2_DCM: %lld\n", i, g_values[i][1]); } printf("\n#L1 Cache Misses: %lld\n", total_L1_miss); printf("#Normalized Cache Misses: %f\n", ((double)total_L1_miss)/(reads+updates)); printf("\n#L2 Cache Misses: %lld\n", total_L2_miss); printf("#Normalized Cache Misses: %f\n", ((double)total_L1_miss)/(reads+updates)); #endif // Delete set if (pq || sl) { sl_set_delete(set); } free(threads); free(data); return 0; }
int main(int argc, char* const argv[]) { set_cpu(the_cores[0]); #ifdef PRINT_OUTPUT fprintf(stderr, "The size of the data being tested: %lu\n",sizeof(data_type)); fprintf(stderr, "Number of entries per cache line: %lu\n",CACHE_LINE_SIZE / sizeof(data_t)); #endif struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"entries", required_argument, NULL, 'e'}, {"duration", required_argument, NULL, 'd'}, {"pause", required_argument, NULL, 'p'}, {"num-threads", required_argument, NULL, 'n'}, {"seed", required_argument, NULL, 's'}, {NULL, 0, NULL, 0} }; int i, c; thread_data_t *data; pthread_t *threads; pthread_attr_t attr; barrier_t barrier; struct timeval start, end; struct timespec timeout; num_entries = DEFAULT_NUM_ENTRIES; num_threads = DEFAULT_NUM_THREADS; duration = DEFAULT_DURATION; seed = DEFAULT_SEED; op_pause = DEFAULT_PAUSE; sigset_t block_set; while(1) { i = 0; c = getopt_long(argc, argv, "he:d:p:n:s", long_options, &i); if(c == -1) break; if(c == 0 && long_options[i].flag == 0) c = long_options[i].val; switch(c) { case 0: /* Flag is automatically set */ break; case 'h': printf("lock stress test\n" "\n" "Usage:\n" " stress_test [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -e, --entires <int>\n" " Number of entries in the test (default=" XSTR(DEFAULT_NUM_LOCKS) ")\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -p, --pause <int>\n" " Pause between consecutive atomic operations in cycles (default=" XSTR(DEFAULT_DURATION) ")\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NUM_THREADS) ")\n" " -s, --seed <int>\n" " RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n" ); exit(0); case 'e': num_entries = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'n': num_threads = atoi(optarg); break; case 'p': op_pause = atoi(optarg); break; case 's': seed = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } op_pause=op_pause/NOP_DURATION; num_entries = pow2roundup(num_entries); assert(duration >= 0); assert(num_entries >= 1); assert(num_threads > 0); #ifdef PRINT_OUTPUT printf("Number of entries : %d\n", num_entries); printf("Duration : %d\n", duration); printf("Number of threads : %d\n", num_threads); printf("Type sizes : int=%d/long=%d/ptr=%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *)); #endif timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; the_data = (data_t*)malloc(num_entries * sizeof(data_t)); for (i = 0; i < num_entries; i++) { the_data[i].data=0; } if ((data = (thread_data_t *)malloc(num_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(num_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } if (seed == 0) srand((int)time(NULL)); else srand(seed); stop = 0; /* Access set from all threads */ barrier_init(&barrier, num_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < num_threads; i++) { #ifdef PRINT_OUTPUT printf("Creating thread %d\n", i); #endif data[i].id = i; data[i].num_operations = 0; data[i].seed = rand(); data[i].barrier = &barrier; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); /* Catch some signals */ if (signal(SIGHUP, catcher) == SIG_ERR || signal(SIGINT, catcher) == SIG_ERR || signal(SIGTERM, catcher) == SIG_ERR) { perror("signal"); exit(1); } /* Start threads */ barrier_cross(&barrier); #ifdef PRINT_OUTPUT printf("STARTING...\n"); #endif gettimeofday(&start, NULL); if (duration > 0) { nanosleep(&timeout, NULL); } else { sigemptyset(&block_set); sigsuspend(&block_set); } stop = 1; gettimeofday(&end, NULL); #ifdef PRINT_OUTPUT printf("STOPPING...\n"); #endif /* Wait for thread completion */ for (i = 0; i < num_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000); unsigned long operations = 0; for (i = 0; i < num_threads; i++) { #ifdef PRINT_OUTPUT printf("Thread %d\n", i); printf(" #operations : %lu\n", data[i].num_operations); #endif operations += data[i].num_operations; } #ifdef PRINT_OUTPUT printf("Duration : %d (ms)\n", duration); #endif printf("#operations : %lu (%f / s)\n", operations, operations * 1000.0 / duration); free((data_t*) the_data); free(threads); free(data); return 0; }
int main(int argc, char* const argv[]) { num_threads = 3; int i; v = (uint8_t*) malloc((1+op_count) * sizeof(uint8_t)); for (i = 1; i <= op_count; i++) { v[i] = 0; } //place thread on the first cpu set_cpu(7); ssalloc_init(); //alignment in the custom memory allocator to a 64 byte boundary pthread_t *threads; pthread_attr_t attr; thread_data_t *data; barrier_t barrier; root = bst_initialize(); printf("Initialized tree\n"); //initialize the data which will be passed to the threads if ((data = (thread_data_t *)malloc(num_threads * sizeof(thread_data_t))) == NULL) { perror("malloc"); exit(1); } if ((threads = (pthread_t *)malloc(num_threads * sizeof(pthread_t))) == NULL) { perror("malloc"); exit(1); } //global barrier initialization (used to start the threads at the same time) barrier_init(&barrier, num_threads + 1); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < num_threads; i++) { data[i].id = i; data[i].num_insert=0; data[i].num_remove=0; data[i].num_search=0; data[i].barrier = &barrier; if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); /* Start threads */ barrier_cross(&barrier); /* Wait for thread completion */ for (i = 0; i < num_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } for (i = 0; i < num_threads; i++) { printf("Thread %d\n", i); printf(" #inserts : %lu\n", data[i].num_insert); printf(" #searches : %lu\n", data[i].num_search); printf(" #removes : %lu\n", data[i].num_remove); } bool_t correct = TRUE; for (i = 1; i <= op_count; i++) { if (v[i] != 2) { correct = FALSE; fprintf(stderr, "Incorrect value %d\n", i); } } if (correct == TRUE) { fprintf(stderr, "Okey-dokey\n"); } free(threads); free(data); return 0; }
void *test(void *data) { // Read this locally to prevent possible cache effects. thread_data_t d = *(thread_data_t *)data; // Wait for all threads to become ready. barrier_cross(d.barrier); // Last value to be inserted, or -ve if last action was remove. // Start -ve here so that alternate mode will not hang. int last = -1; // If we're in bias mode, should start positive so that something // gets removed. if (d.bias_enabled) last = d.bias_offset; while (atomic_load(&stop) == 0) { // Is the next op an update? int do_update; if (d.effective) do_update = (100 * (d.nb_added + d.nb_removed)) < (d.update * (d.nb_add + d.nb_remove + d.nb_contains)); else do_update = rand_range_re(&d.seed, 100) - 1 < d.update; // Value on which to operate. (may be modified later, // if in alternate mode or bias mode) int value = rand_range_re(&d.seed, d.range); // If we're in bias mode, restrict the range, and just choose adding or removing at random if (d.bias_enabled) { value = d.bias_offset + rand_range_re(&d.seed, d.bias_range) - 1; last = (rand_range_re(&d.seed, 2) == 1) ? -1 : value; } if (do_update && last < 0) { // Add if (set_insert(d.set, value)) { d.nb_added++; last = value; } d.nb_add++; } else if (do_update && last >= 0) { // Remove // If in alternate mode, remove the last item added. if (d.alternate) { if (set_remove(d.set, last)) d.nb_removed++; last = -1; } else { if (set_remove(d.set, value)) { d.nb_removed++; last = -1; } } d.nb_remove++; } else { // Read if (d.alternate) { if (d.update == 0) { if (last < 0) last = value = d.first; else last = -1; } else { // update != 0 if (last >= 0) value = last; } } if (set_contains(d.set, value)) d.nb_found++; d.nb_contains++; } } *(thread_data_t *)data = d; return NULL; }