/* * Initialize module. */ void mod_order_init(void) { if (mod_order_initialized) return; #if CM == CM_MODULAR if (!stm_register(NULL, NULL, mod_order_on_start, mod_order_on_precommit, mod_order_on_commit, NULL, NULL)) { fprintf(stderr, "Could not set callbacks for module 'mod_order'. Exiting.\n"); goto err; } if (stm_set_parameter("cm_function", mod_order_cm) == 0) { fprintf(stderr, "Could not set contention manager for module 'mod_order'. Exiting.\n"); goto err; } mod_order_key = stm_create_specific(); if (mod_order_key < 0) { fprintf(stderr, "Cannot create specific key\n"); goto err; } mod_order_initialized = 1; return; err: #else /* CM != CM_MODULAR */ fprintf(stderr, "The 'mod_order' module requires CM_MODULAR.\n"); #endif /* CM != CM_MODULAR */ exit(1); }
int main(int argc, char **argv) { struct option long_options[] = { // These options don't set a flag {"help", no_argument, NULL, 'h'}, {"contention-manager", required_argument, NULL, 'c'}, {"duration", required_argument, NULL, 'd'}, {"irrevocable-percent", required_argument, NULL, 'i'}, {"num-threads", required_argument, NULL, 'n'}, {NULL, 0, NULL, 0} }; int i, c; 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; thread_data_t *td; pthread_t *threads; pthread_attr_t attr; struct timespec timeout; int duration = DEFAULT_DURATION; int irrevocable_percent = DEFAULT_IRREVOCABLE_PERCENT; int nb_threads = DEFAULT_NB_THREADS; char *cm = NULL; while(1) { i = 0; c = getopt_long(argc, argv, "hc:d:i:n:", 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("irrevocability -- STM stress test " "\n" "Usage:\n" " irrevocability [options...]\n" "\n" "Options:\n" " -h, --help\n" " Print this message\n" " -c, --contention-manager <string>\n" " Contention manager for resolving conflicts (default=suicide)\n" " -d, --duration <int>\n" " Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n" " -i, --irrevocable-percent <int>\n" " (default=" XSTR(DEFAULT_IRREVOCABLE_PERCENT) ")\n" " -n, --num-threads <int>\n" " Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n" ); exit(0); case 'c': cm = optarg; break; case 'd': duration = atoi(optarg); break; case 'n': nb_threads = atoi(optarg); break; case 'i': irrevocable_percent = atoi(optarg); break; case '?': printf("Use -h or --help for help\n"); exit(0); default: exit(1); } } assert(duration >= 0); assert(nb_threads > 0); assert(irrevocable_percent >= 0 && irrevocable_percent <= 100); printf("CM : %s\n", (cm == NULL ? "DEFAULT" : cm)); printf("Duration : %d\n", duration); printf("Irrevocable : %d\%%\n", irrevocable_percent); printf("Nb threads : %d\n", nb_threads); for (i = 0; i < NB_ELEMENTS; i++) data[i] = 0; /* Init STM */ printf("Initializing STM\n"); stm_init(); /* Set contention manager */ if (cm != NULL) { if (stm_set_parameter("cm_policy", cm) == 0) printf("WARNING: cannot set contention manager \"%s\"\n", cm); } printf("int/long/ptr/word size: %d/%d/%d/%d\n", (int)sizeof(int), (int)sizeof(long), (int)sizeof(void *), (int)sizeof(stm_word_t)); stop = 0; printf("TESTING CONCURRENT UPDATES...\n"); timeout.tv_sec = duration / 1000; timeout.tv_nsec = (duration % 1000) * 1000000; if ((td = (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); } pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < nb_threads; i++) { td[i].nb_aborts = 0; td[i].nb_aborts_1 = 0; td[i].nb_aborts_2 = 0; td[i].nb_aborts_locked_read = 0; td[i].nb_aborts_locked_write = 0; td[i].nb_aborts_validate_read = 0; td[i].nb_aborts_validate_write = 0; td[i].nb_aborts_validate_commit = 0; td[i].nb_aborts_invalid_memory = 0; td[i].nb_aborts_killed = 0; td[i].locked_reads_ok = 0; td[i].locked_reads_failed = 0; td[i].max_retries = 0; td[i].irrevocable_percent = irrevocable_percent; if (pthread_create(&threads[i], &attr, test, (void *)(&td[i])) != 0) { fprintf(stderr, "Error creating thread\n"); exit(1); } } pthread_attr_destroy(&attr); nanosleep(&timeout, NULL); printf("STOPPING...\n"); stop = 1; for (i = 0; i < nb_threads; i++) { if (pthread_join(threads[i], NULL) != 0) { fprintf(stderr, "Error waiting for thread completion\n"); exit(1); } } printf("PASSED\n"); printf("Number of successful irrevocable-serial executions : %ld\n", nb_irrevocable_serial); printf("Number of successful irrevocable-parallel executions : %ld\n", nb_irrevocable_parallel); 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; for (i = 0; i < nb_threads; i++) { printf("Thread %d\n", i); printf(" #aborts : %lu\n", td[i].nb_aborts); printf(" #lock-r : %lu\n", td[i].nb_aborts_locked_read); printf(" #lock-w : %lu\n", td[i].nb_aborts_locked_write); printf(" #val-r : %lu\n", td[i].nb_aborts_validate_read); printf(" #val-w : %lu\n", td[i].nb_aborts_validate_write); printf(" #val-c : %lu\n", td[i].nb_aborts_validate_commit); printf(" #inv-mem : %lu\n", td[i].nb_aborts_invalid_memory); printf(" #killed : %lu\n", td[i].nb_aborts_killed); printf(" #aborts>=1 : %lu\n", td[i].nb_aborts_1); printf(" #aborts>=2 : %lu\n", td[i].nb_aborts_2); printf(" #lr-ok : %lu\n", td[i].locked_reads_ok); printf(" #lr-failed : %lu\n", td[i].locked_reads_failed); printf(" Max retries : %lu\n", td[i].max_retries); aborts += td[i].nb_aborts; aborts_1 += td[i].nb_aborts_1; aborts_2 += td[i].nb_aborts_2; aborts_locked_read += td[i].nb_aborts_locked_read; aborts_locked_write += td[i].nb_aborts_locked_write; aborts_validate_read += td[i].nb_aborts_validate_read; aborts_validate_write += td[i].nb_aborts_validate_write; aborts_validate_commit += td[i].nb_aborts_validate_commit; aborts_invalid_memory += td[i].nb_aborts_invalid_memory; aborts_killed += td[i].nb_aborts_killed; locked_reads_ok += td[i].locked_reads_ok; locked_reads_failed += td[i].locked_reads_failed; if (max_retries < td[i].max_retries) max_retries = td[i].max_retries; } printf("Duration : %d (ms)\n", 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(" #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); /* Cleanup STM */ stm_exit(); 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; }