void * _ITM_CALL_CONVENTION _ITM_getTMCloneOrIrrevocable (void *ptr) { // if the function (ptr) have a TM version, give the pointer to the TM function // otherwise, set transaction to irrevocable mode void *ret = find_clone (ptr); if (ret) return ret; /* TODO Check we are in an active transaction */ // if (stm_current_tx() != NULL && stm_is_active(tx)) /* GCC always use implicit transaction descriptor */ stm_set_irrevocable(1); return ptr; }
void _ITM_CALL_CONVENTION _ITM_changeTransactionMode(TX_ARGS _ITM_transactionState __mode, const _ITM_srcLocation *__loc) { /* FIXME: it seems there is a problem with irrevocable and intel c */ switch (__mode) { case modeSerialIrrevocable: stm_set_irrevocable(1); /* TODO a_runUninstrumentedCode must be set at rollback! */ break; case modeObstinate: case modeOptimistic: case modePessimistic: default: fprintf(stderr, "This mode %d is not implemented yet\n", __mode); } }
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; }
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; }