/** * move a stack state to the completed SCC set */ static void move_scc (wctx_t *ctx, ref_t state) { alg_local_t *loc = ctx->local; hash32_t hash; int success; Debug ("Marking %zu as SCC", state); // remove reference to stack state hash = ref_hash (state); success = fset_delete (loc->visited_states, &hash, &state); HREassert (success, "Could not remove SCC state from set"); // set SCC globally state_store_try_color (state, SCC_STATE, 0); }
static void ta_handle (void *arg, state_info_t *successor, transition_info_t *ti, int seen) { wctx_t *ctx = (wctx_t*) arg; ta_alg_shared_t *shared = (ta_alg_shared_t *) ctx->run->shared; alg_local_t *loc = ctx->local; ta_alg_local_t *ta_loc = (ta_alg_local_t *) ctx->local; ta_alg_global_t *sm = (ta_alg_global_t *) ctx->global; ta_loc->done = 0; ta_loc->subsumes = 0; // if a successor subsumes one in the set, it cannot be subsumed itself (see invariant paper) ta_loc->work = 0; ta_loc->added_at = LM_NULL_LOC; ta_loc->last = LM_NULL_LOC; ta_loc->successor = successor; lm_lock (shared->lmap, successor->ref); lm_loc_t last = lm_iterate (shared->lmap, successor->ref, ta_covered, ctx); if (!ta_loc->done) { last = (LM_NULL_LOC == ta_loc->last ? last : ta_loc->last); sm->lloc = lm_insert_from (shared->lmap, successor->ref, successor->lattice, TA_WAITING, &last); lm_unlock (shared->lmap, successor->ref); ta_loc->counters.inserts++; if (0) { // quite costly: flops if (ta_loc->work > 0) statistics_unrecord (&ta_loc->counters.lattice_ratio, ta_loc->work); statistics_record (&ta_loc->counters.lattice_ratio, ta_loc->work+1); } ta_queue_state (ctx, successor); ta_loc->counters.updates += LM_NULL_LOC != ta_loc->last; loc->counters.level_size++; } else { lm_unlock (shared->lmap, successor->ref); } action_detect (ctx, ti, successor); if (EXPECT_FALSE(loc->lts != NULL)) { int src = ctx->counters->explored; int *tgt = state_info_state (successor); int tgt_owner = ref_hash (successor->ref) % W; lts_write_edge (loc->lts, ctx->id, &src, tgt_owner, tgt, ti->labels); } ctx->counters->trans++; (void) seen; }
static void tarjan_handle (void *arg, state_info_t *successor, transition_info_t *ti, int seen) { // parent state is ctx->state wctx_t *ctx = (wctx_t *) arg; alg_local_t *loc = ctx->local; raw_data_t *addr; hash32_t hash; int found; ctx->counters->trans++; // self-loop if (ctx->state->ref == successor->ref) return; // completed SCC if (state_store_has_color (successor->ref, SCC_STATE, 0)) return; hash = ref_hash (successor->ref); found = fset_find (loc->visited_states, &hash, &successor->ref, (void **)&addr, false); if (found) { // previously visited state ==> update lowlink state_info_deserialize (loc->target, *addr); if (loc->state_tarjan.lowlink > loc->target_tarjan.lowlink) loc->state_tarjan.lowlink = loc->target_tarjan.lowlink; } else { // unseen state ==> push to search_stack raw_data_t stack_loc = dfs_stack_push (loc->search_stack, NULL); state_info_serialize (successor, stack_loc); } (void) ti; (void) seen; }
/** * move a search_stack state to the tarjan_stack */ static void move_tarjan (wctx_t *ctx, state_info_t *state, raw_data_t state_data) { alg_local_t *loc = ctx->local; raw_data_t *addr; hash32_t hash; int found; // add state to tarjan_stack raw_data_t tarjan_loc = dfs_stack_push (loc->tarjan_stack, NULL); state_info_serialize (state, tarjan_loc); // Update reference to the new stack hash = ref_hash (state->ref); found = fset_find (loc->visited_states, &hash, &state->ref, (void**) &addr, false); HREassert (*addr == state_data, "Wrong addr?"); HREassert (found, "Could not find key in set"); *addr = tarjan_loc; }
void timed_run (run_t *run, wctx_t *ctx) { transition_info_t ti = GB_NO_TRANSITION; if ( Strat_PBFS & strategy[0] ) { ta_queue_state = pbfs_queue_state; } if (0 == ctx->id) { // only w1 receives load, as it is propagated later if ( Strat_PBFS & strategy[0] ) { if (ctx->local->lts != NULL) { state_data_t initial = state_info_state(ctx->initial); int src_owner = ref_hash(ctx->initial->ref) % W; lts_write_init (ctx->local->lts, src_owner, initial); } } ta_handle (ctx, ctx->initial, &ti, 0); ctx->counters->trans = 0; //reset trans count } HREbarrier (HREglobal()); switch (get_strategy(run->alg)) { case Strat_TA_PBFS: ta_pbfs (ctx); break; case Strat_TA_SBFS: ta_sbfs (ctx); break; case Strat_TA_BFS: ta_bfs (ctx); break; case Strat_TA_DFS: ta_dfs (ctx); break; default: Abort ("Missing case in timed_run"); } }
void tarjan_run (run_t *run, wctx_t *ctx) { alg_local_t *loc = ctx->local; raw_data_t *addr; raw_data_t state_data; bool on_stack; hash32_t hash; #ifdef HAVE_PROFILER Warning (info, "Using the profiler"); ProfilerStart ("tarjan.perf"); #endif #ifdef SEARCH_COMPLETE_GRAPH int init_state = dlopen_get_worker_initial_state (ctx->id, W); int inits = 0; // loop until every state of the graph has been visited while ( 1 ) { inits ++; // use loc->target as a dummy for the initial state loc->target->ref = init_state; #endif tarjan_init (ctx); // continue until we are done exploring the graph while ( !run_is_stopped (run) ) { state_data = dfs_stack_top (loc->search_stack); if (state_data != NULL) { // there is a state on the current stackframe ==> explore it state_info_deserialize (ctx->state, state_data); // pop the state and continue if it is part of a completed SCC if (state_store_has_color (ctx->state->ref, SCC_STATE, 0)) { dfs_stack_pop (loc->search_stack); continue; } hash = ref_hash (ctx->state->ref); on_stack = fset_find (loc->visited_states, &hash, &ctx->state->ref, (void **) &addr, true); if (!on_stack) { // unseen state ==> initialize and explore HREassert (loc->cnt.tarjan_counter != UINT32_MAX); loc->cnt.tarjan_counter ++; loc->state_tarjan.index = loc->cnt.tarjan_counter; loc->state_tarjan.lowlink = loc->cnt.tarjan_counter; // point visited_states data to stack *addr = state_data; explore_state (ctx); state_info_serialize (ctx->state, state_data); } else { // previously visited state ==> update parent // NB: state is on tarjan_stack state_info_deserialize (ctx->state, *addr); update_parent (ctx, loc->state_tarjan.lowlink); dfs_stack_pop (loc->search_stack); } } else { // there is no state on the current stackframe ==> backtrack // we are done if we backtrack from the initial state if (0 == dfs_stack_nframes (loc->search_stack)) break; // leave the stackframe dfs_stack_leave (loc->search_stack); ctx->counters->level_cur--; // retrieve the parent state from search_stack (to be removed) state_data = dfs_stack_top (loc->search_stack); state_info_deserialize (ctx->state, state_data); Debug ("Backtracking %zu (%d, %d)", ctx->state->ref, loc->state_tarjan.index, loc->state_tarjan.lowlink); if (loc->state_tarjan.index == loc->state_tarjan.lowlink) { // index == lowlink ==> root of the SCC ==> report the SCC pop_scc (ctx, ctx->state->ref, loc->state_tarjan.lowlink); } else { // lowlink < index ==> LIVE SCC ==> move to tarjan_stack move_tarjan (ctx, ctx->state, state_data); update_parent (ctx, loc->state_tarjan.lowlink); } dfs_stack_pop (loc->search_stack); } } #ifdef SEARCH_COMPLETE_GRAPH init_state = dlopen_get_new_initial_state (init_state); if (init_state == -1) { Warning(info, "Number of inits : %d", inits); break; } } #endif #ifdef HAVE_PROFILER Warning(info, "Done profiling"); ProfilerStop(); #endif if (!run_is_stopped(run) && dfs_stack_size(loc->tarjan_stack) != 0) Warning (info, "Tarjan stack not empty: %zu (stack %zu)", dfs_stack_size(loc->tarjan_stack), dfs_stack_size(loc->search_stack)); if (!run_is_stopped(run) && fset_count(loc->visited_states) != 0) Warning (info, "Stack-set not empty: %zu", fset_count(loc->visited_states)); }