static VALUE avl_tree_rsize( VALUE self ) { avl_tree_r *t; long size; Data_Get_Struct( self, avl_tree_r, t ); size = avl_tree_size( t->root ); return INT2FIX( size ); }
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; }