grt_bool_t hashtable_find(grt_word_t val) { unsigned bucket = compute_hash(val); grt_word_t *loc = (grt_word_t*) &table[bucket]; node_t *p; stm_start(); stm_open_for_read(table_proc, loc); stm_read(table_proc, loc, (grt_word_t*) &p); grt_bool_t result = find_node_stm(val, p) == 0 ? GRT_FALSE : GRT_TRUE; stm_commit(); return result; }
sigjmp_buf * tm_start(TXPARAMS stm_tx_attr_t attr) { TX_GET; if (!tx->software) { return hytm_start(TXARGS attr); } else { return stm_start(TXARGS attr); } }
grt_bool_t hashtable_insert(grt_word_t val) { unsigned bucket = compute_hash(val); node_t *p, *q; stm_start(); grt_word_t *loc = (grt_word_t*) &table[bucket]; stm_open_for_read(table_proc, loc); stm_read(table_proc, loc, (grt_word_t*) &p); if (find_node_stm(val, p)) { stm_commit(); return GRT_TRUE; } q = (node_t*) stm_alloc(table_proc, sizeof(node_t)); loc = (grt_word_t*) &q->next; stm_open_for_write(table_proc, loc); stm_write(table_proc, (grt_word_t) p, loc); loc = (grt_word_t*) &q->val; stm_open_for_write(table_proc, loc); stm_write(table_proc, val, loc); loc = (grt_word_t*) &table[bucket]; stm_open_for_write(table_proc, loc); stm_write(table_proc, (grt_word_t) q, loc); stm_commit(); return GRT_FALSE; }
static void test1load(int ro) { uint64_t m_s[MEASURE_NB]; uint64_t m_r[MEASURE_NB]; uint64_t m_c[MEASURE_NB]; uint64_t m_rdtsc; uint64_t start; uint64_t min; double avg; uint64_t med; unsigned long i; stm_tx_attr_t _a = {{.read_only = ro}}; m_rdtsc = ~0UL; for (i = 0; i < MEASURE_NB; i++) { start = rdtsc(); start = rdtsc() - start; if (start < m_rdtsc) m_rdtsc = start; } for (i = 0; i < MEASURE_NB; i++) { sigjmp_buf *_e; start = rdtsc(); _e = stm_start(_a); m_s[i] = rdtsc() - start; sigsetjmp(*_e, 0); stm_load(&global_ctr[0]); stm_inc_clock(); stm_commit(); } for (i = 0; i < MEASURE_NB; i++) { sigjmp_buf *_e = stm_start(_a); sigsetjmp(*_e, 0); start = rdtsc(); stm_load(&global_ctr[0]); m_r[i] = rdtsc() - start; stm_inc_clock(); stm_commit(); } for (i = 0; i < MEASURE_NB; i++) { sigjmp_buf *_e = stm_start(_a); sigsetjmp(*_e, 0); stm_load(&global_ctr[0]); stm_inc_clock(); start = rdtsc(); stm_commit(); m_c[i] = rdtsc() - start; } remove_cst_cost(m_s, MEASURE_NB, m_rdtsc); remove_cst_cost(m_r, MEASURE_NB, m_rdtsc); remove_cst_cost(m_c, MEASURE_NB, m_rdtsc); if (ro) printf("RO transaction - 1 load\n"); else printf("RW transaction - 1 load\n"); printf("%12s %12s %12s %12s\n", "", "min", "avg", "med"); stats(m_s, MEASURE_NB, &min, &avg, &med); printf("%12s %12lu %12.2f %12lu\n", "start", (unsigned long)min, avg, (unsigned long)med); stats(m_r, MEASURE_NB, &min, &avg, &med); printf("%12s %12lu %12.2f %12lu\n", "load", (unsigned long)min, avg, (unsigned long)med); stats(m_c, MEASURE_NB, &min, &avg, &med); printf("%12s %12lu %12.2f %12lu\n", "commit", (unsigned long)min, avg, (unsigned long)med); }
static void testnloadnstore(size_t load_nb, size_t store_nb) { uint64_t m_s[MEASURE_NB]; uint64_t m_r[MEASURE_NB]; uint64_t m_w[MEASURE_NB]; uint64_t m_c[MEASURE_NB]; uint64_t m_rdtsc; uint64_t start; uint64_t min; double avg; uint64_t med; unsigned long i; size_t j; stm_tx_attr_t _a = {{.read_only = 0}}; m_rdtsc = ~0UL; for (i = 0; i < MEASURE_NB; i++) { start = rdtsc(); start = rdtsc() - start; if (start < m_rdtsc) m_rdtsc = start; } for (i = 0; i < MEASURE_NB; i++) { sigjmp_buf *_e; start = rdtsc(); _e = stm_start(_a); m_s[i] = rdtsc() - start; sigsetjmp(*_e, 0); for (j = 0; j < load_nb; j++) stm_load(&global_ctr[j]); for (j = 0; j < store_nb; j++) stm_store(&global_ctr[j], (stm_word_t)0); stm_inc_clock(); stm_commit(); } for (i = 0; i < MEASURE_NB; i++) { sigjmp_buf *_e = stm_start(_a); sigsetjmp(*_e, 0); start = rdtsc(); for (j = 0; j < load_nb; j++) stm_load(&global_ctr[j]); m_r[i] = rdtsc() - start; for (j = 0; j < store_nb; j++) stm_store(&global_ctr[j], (stm_word_t)0); stm_inc_clock(); stm_commit(); } for (i = 0; i < MEASURE_NB; i++) { sigjmp_buf *_e = stm_start(_a); sigsetjmp(*_e, 0); for (j = 0; j < load_nb; j++) stm_load(&global_ctr[j]); start = rdtsc(); for (j = 0; j < store_nb; j++) stm_store(&global_ctr[j], (stm_word_t)0); m_w[i] = rdtsc() - start; stm_inc_clock(); stm_commit(); } for (i = 0; i < MEASURE_NB; i++) { sigjmp_buf *_e = stm_start(_a); sigsetjmp(*_e, 0); for (j = 0; j < load_nb; j++) stm_load(&global_ctr[j]); for (j = 0; j < store_nb; j++) stm_store(&global_ctr[j], (stm_word_t)0); stm_inc_clock(); start = rdtsc(); stm_commit(); m_c[i] = rdtsc() - start; } remove_cst_cost(m_s, MEASURE_NB, m_rdtsc); remove_cst_cost(m_r, MEASURE_NB, m_rdtsc); remove_cst_cost(m_w, MEASURE_NB, m_rdtsc); remove_cst_cost(m_c, MEASURE_NB, m_rdtsc); printf("RW transaction - %lu load - %lu store\n", (unsigned long)load_nb, (unsigned long)store_nb); printf("%12s %12s %12s %12s\n", "", "min", "avg", "med"); stats(m_s, MEASURE_NB, &min, &avg, &med); printf("%12s %12lu %12.2f %12lu\n", "start", (unsigned long)min, avg, (unsigned long)med); stats(m_r, MEASURE_NB, &min, &avg, &med); if (load_nb) printf("%12s %12lu %12.2f %12lu\n", "load", (unsigned long)min/load_nb, avg/load_nb, (unsigned long)med/load_nb); stats(m_w, MEASURE_NB, &min, &avg, &med); if (store_nb) printf("%12s %12lu %12.2f %12lu\n", "store", (unsigned long)min/store_nb, avg/store_nb, (unsigned long)med/store_nb); stats(m_c, MEASURE_NB, &min, &avg, &med); printf("%12s %12lu %12.2f %12lu\n", "commit", (unsigned long)min, avg, (unsigned long)med); }
void *test(void *v) { unsigned int seed; int i, n, irrevocable, serial; long l; sigjmp_buf *e; thread_data_t *d = (thread_data_t *)v; seed = (unsigned int)time(0); stm_init_thread(); while (stop == 0) { irrevocable = (rand_r(&seed) < RAND_MAX / 100 * d->irrevocable_percent ? 1 : 0); serial = (rand_r(&seed) < RAND_MAX / 2 ? 1 : 0); // irrevocable=1; // serial=1; e = stm_start(NULL); if (e != NULL) sigsetjmp(*e, 0); if (irrevocable == 4) { /* Aborted while in irrevocable mode => error */ fprintf(stderr, "ERROR: aborted while in irrevocable mode\n"); exit(1); } for (n = rand_r(&seed) % NB_SHUFFLES; n > 0; n--) { i = rand_r(&seed) % NB_ELEMENTS; stm_store_long(&data[i], stm_load_long(&data[i]) + 1); i = rand_r(&seed) % NB_ELEMENTS; stm_store_long(&data[i], stm_load_long(&data[i]) - 1); } if (irrevocable) { if (irrevocable == 3) { /* Already tried entering irrevocable mode once => error */ fprintf(stderr, "ERROR: failed entering irrevocable mode upon retry\n"); exit(1); } irrevocable++; if (!stm_set_irrevocable(serial)) { fprintf(stderr, "ERROR: cannot enter irrevocable mode\n"); exit(1); } irrevocable = 4; /* Once in irrevocable mode, we cannot abort */ if (serial) { /* No other transaction can execute concurrently */ for (i = 0, l = 0; i < NB_ELEMENTS; i++) l += data[i]; assert(l == 0); for (i = 0; i < NB_ELEMENTS; i++) data[i] = 0; nb_irrevocable_serial++; } else { /* Non-conflicting transactions can execute concurrently */ for (i = 0, l = 0; i < NB_ELEMENTS; i++) l += stm_load_long(&data[i]); assert(l == 0); for (i = 0; i < NB_ELEMENTS; i++) stm_store_long(&data[i], 0); nb_irrevocable_parallel++; } } for (i = 0, l = 0; i < NB_ELEMENTS; i++) l += stm_load_long(&data[i]); assert(l == 0); stm_commit(); } 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); stm_exit_thread(); return NULL; }
void run() { unsigned i, time; gasnett_tick_t start, end; hash_map_create(params[HASHMAP_SIZE], (grt_bool_t) params[ON_PTHREAD]); grt_barrier(); #ifdef LOCKS grt_lock_state_t state; #endif for (i = 0; i < MY_NUM_OPS; ++i) { grt_word_t key = keys[i], val = values[i]; #ifdef LOCKS hash_t hash = compute_hash(key); hash_map_lock(hash.proc, hash.offset, WRITE, &state); #endif hash_map_insert(key, val); #ifdef LOCKS hash_map_unlock(hash.proc, hash.offset); #endif } BARRIER(); start = gasnett_ticks_now(); #ifdef LOCKS grt_lock_state_t state1, state2; #endif for (i = 0; i < MY_NUM_OPS; ++i) { unsigned idx = grt_random_next() * MY_NUM_OPS; grt_word_t key1 = keys[i]; unsigned second_idx = grt_random_next() * MY_NUM_OPS; grt_word_t key2 = keys[second_idx]; #ifdef LOCKS lock(key1, key2, &state1, &state2); #endif grt_word_t val1, val2; #ifndef LOCKS #ifndef NOLOCKS stm_start(grt_id); #endif #endif grt_bool_t found1 = hash_map_find(key1, &val1); grt_bool_t found2 = hash_map_find(key2, &val2); hash_map_insert(key1, val2); hash_map_insert(key2, val1); #ifndef LOCKS #ifndef NOLOCKS stm_commit(grt_id); #endif #endif #if LOCKS unlock(key1, key2); #endif } end = gasnett_ticks_now(); time = ((unsigned) gasnett_ticks_to_us(end - start)); printf("processor %u: execution time=%f us\n", grt_id, (double) time); fflush(stdout); grt_write(0, time, ×[grt_id]); BARRIER(); if (grt_id == 0) { time = 0, max_time = 0; for (i = 0; i < grt_num_procs; ++i) { gasnett_tick_t this_time = times[i]; time += this_time; if (this_time >= max_time) max_time = this_time; } time_per_op = ((float) time) / params[NUM_OPS]; printf("total CPU time=%f us\n", (double) time); printf("time per operation=%f us\n", time_per_op); printf("max time=%f us\n", (double) max_time); } BARRIER(); hash_map_destroy(); BARRIER(); }
sigjmp_buf * hytm_start(TXPARAMS stm_tx_attr_t attr) { TX_GET; unsigned long err; tx->retries = 0; /* Set status */ UPDATE_STATUS(tx->status, TX_ACTIVE); stm_check_quiesce(tx); /* copy attributes if need to switch to software mode */ tx->attr = attr; tx->start = rdtsc(); hytm_restart: /* All registers are lost when ASF aborts, thus we discard registers */ asm volatile (ASF_SPECULATE :"=a" (err) : :"memory","rbp","rbx","rcx","rdx","rsi","rdi", "r8", "r9","r10","r11","r12","r13","r14","r15" ); tx = tls_get_tx(); if (unlikely(asf_status_code(err) != 0)) { /* Set status to ABORTED */ SET_STATUS(tx->status, TX_ABORTED); tx->retries++; /* Error management */ if (asf_status_code(err) == ASF_STATUS_CONTENTION) { if (tx->retries > ASF_ABORT_THRESHOLD) { /* There is too many conflicts, software will not help, start irrevocability. */ stm_set_irrevocable(TXARGS 1); /* Set irrevocable serial */ #if defined(TM_DTMC) || defined(TM_GCC) stm_set_irrevocable(TXARGS -1); /* Acquire irrevocability */ UPDATE_STATUS(tx->status, TX_IRREVOCABLE); LONGJMP(tx->env, 0x02); /* ABI 0x02 = runUninstrumented */ #else /* ! defined(TM_DTMC) && ! defined(TM_GCC) */ /* Non-tm compiler doesn't have path without instrumentation. */ tx->software = 1; #endif /* ! defined(TM_DTMC) && ! defined(TM_GCC) */ } } else if (asf_status_code(err) == ASF_STATUS_ABORT) { if (asf_abort_code(err) == ASF_FORCE_SOFTWARE) { tx->software = 1; #ifdef IRREVOCABLE_ENABLED } else if(asf_abort_code(err) == ASF_RETRY_IRREVOCABLE) { # if defined(TM_DTMC) || defined(TM_GCC) if (tx->irrevocable != 0) { stm_set_irrevocable(TXARGS -1); UPDATE_STATUS(tx->status, TX_IRREVOCABLE); LONGJMP(tx->env, 0x02); /* ABI 0x02 = runUninstrumented */ } # else /* ! defined(TM_DTMC) || defined(TM_GCC) */ /* Non-tm compiler doesn't have path without instrumentation. */ tx->software = 1; # endif /* ! defined(TM_DTMC) || defined(TM_GCC) */ #endif /* IRREVOCABLE_ENABLED */ } else { if (tx->retries > ASF_ABORT_THRESHOLD) { tx->software = 1; } } } else { /* Other cases are critical and needs software mode */ tx->software = 1; } if (tx->software) { /* Start a software transaction (it cannot use attr since the register/stack can be corrupted) */ stm_start(TXARGS tx->attr); /* Restoring the context */ #if defined(TM_DTMC) LONGJMP(tx->env, 0x01); /* ABI 0x01 = runInstrumented, DTMC explicitly needs 1 */ #else /* ! defined(TM_DTMC) */ LONGJMP(tx->env, 0x09); /* ABI 0x09 = runInstrumented + restoreLiveVariable */ #endif /* ! defined(TM_DTMC) */ } else { uint64_t cur = (uint64_t)rdtsc(); uint64_t wait = cur + (random() % (cur - tx->start)); /* XXX random but maybe not reliable */ /* Waiting... */ while (rdtsc() < wait); UPDATE_STATUS(tx->status, TX_ACTIVE); /* Check quiesce before to restart */ stm_check_quiesce(tx); goto hytm_restart; } } /* Reset write set */ tx->w_set.nb_entries = 0; if (tx->retries > 0) { /* Restoring registers for retry */ #if defined(TM_DTMC) LONGJMP(tx->env, 0x01); /* ABI 0x01 = runInstrumented, DTMC explicitly needs 1 */ #else /* ! defined(TM_DTMC) */ LONGJMP(tx->env, 0x09); /* ABI 0x09 = runInstrumented + restoreLiveVariable */ #endif /* ! defined(TM_DTMC) */ } return &tx->env; }