From: Marion Guthmuller Date: Tue, 3 Jun 2014 16:10:33 +0000 (+0200) Subject: model-checker : mc_dpor.c -> mc_safety.c X-Git-Tag: v3_12~956^2~15 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/91645ff367766eabbe1d2723e0ba8c18e2c3a682 model-checker : mc_dpor.c -> mc_safety.c --- diff --git a/src/mc/mc_dpor.c b/src/mc/mc_dpor.c deleted file mode 100644 index a0c5758d41..0000000000 --- a/src/mc/mc_dpor.c +++ /dev/null @@ -1,736 +0,0 @@ -/* Copyright (c) 2008-2014. The SimGrid Team. - * All rights reserved. */ - -/* This program is free software; you can redistribute it and/or modify it - * under the terms of the license (GNU LGPL) which comes with this package. */ - -#include "mc_private.h" - -#include "xbt/mmalloc/mmprivate.h" - -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dpor, mc, - "Logging specific to MC DPOR exploration"); - -/********** Global variables **********/ - -xbt_dynar_t visited_states; -xbt_dict_t first_enabled_state; - -/********** Static functions ***********/ - - -static void visited_state_free(mc_visited_state_t state) -{ - if (state) { - MC_free_snapshot(state->system_state); - xbt_free(state); - } -} - -static void visited_state_free_voidp(void *s) -{ - visited_state_free((mc_visited_state_t) * (void **) s); -} - -/** \brief Save the current state - * - * \return Snapshot of the current state. - */ -static mc_visited_state_t visited_state_new() -{ - - mc_visited_state_t new_state = NULL; - new_state = xbt_new0(s_mc_visited_state_t, 1); - new_state->heap_bytes_used = mmalloc_get_bytes_used(std_heap); - new_state->nb_processes = xbt_swag_size(simix_global->process_list); - new_state->system_state = MC_take_snapshot(mc_stats->expanded_states); - new_state->num = mc_stats->expanded_states; - new_state->other_num = -1; - - return new_state; - -} - -/** \brief Find a suitable subrange of candidate duplicates for a given state - * - * \param all_ pairs dynamic array of states with candidate duplicates of the current state; - * \param pair current state; - * \param min (output) index of the beginning of the the subrange - * \param max (output) index of the enf of the subrange - * - * Given a suitably ordered array of state, this function extracts a subrange - * (with index *min <= i <= *max) with candidate duplicates of the given state. - * This function uses only fast discriminating criterions and does not use the - * full state comparison algorithms. - * - * The states in all_pairs MUST be ordered using a (given) weak order - * (based on nb_processes and heap_bytes_used). - * The subrange is the subrange of "equivalence" of the given state. - */ -static int get_search_interval(xbt_dynar_t all_states, mc_visited_state_t state, - int *min, int *max) -{ - XBT_VERB - ("Searching interval for state %i: nd_processes=%zu heap_bytes_used=%zu", - state->num, (size_t) state->nb_processes, - (size_t) state->heap_bytes_used); - - int raw_mem_set = (mmalloc_get_current_heap() == mc_heap); - - MC_SET_MC_HEAP; - - int cursor = 0, previous_cursor, next_cursor; - mc_visited_state_t state_test; - int start = 0; - int end = xbt_dynar_length(all_states) - 1; - - while (start <= end) { - cursor = (start + end) / 2; - state_test = - (mc_visited_state_t) xbt_dynar_get_as(all_states, cursor, - mc_visited_state_t); - if (state_test->nb_processes < state->nb_processes) { - start = cursor + 1; - } else if (state_test->nb_processes > state->nb_processes) { - end = cursor - 1; - } else { - if (state_test->heap_bytes_used < state->heap_bytes_used) { - start = cursor + 1; - } else if (state_test->heap_bytes_used > state->heap_bytes_used) { - end = cursor - 1; - } else { - *min = *max = cursor; - previous_cursor = cursor - 1; - while (previous_cursor >= 0) { - state_test = - (mc_visited_state_t) xbt_dynar_get_as(all_states, previous_cursor, - mc_visited_state_t); - if (state_test->nb_processes != state->nb_processes - || state_test->heap_bytes_used != state->heap_bytes_used) - break; - *min = previous_cursor; - previous_cursor--; - } - next_cursor = cursor + 1; - while (next_cursor < xbt_dynar_length(all_states)) { - state_test = - (mc_visited_state_t) xbt_dynar_get_as(all_states, next_cursor, - mc_visited_state_t); - if (state_test->nb_processes != state->nb_processes - || state_test->heap_bytes_used != state->heap_bytes_used) - break; - *max = next_cursor; - next_cursor++; - } - if (!raw_mem_set) - MC_SET_STD_HEAP; - return -1; - } - } - } - - if (!raw_mem_set) - MC_SET_STD_HEAP; - - return cursor; -} - -/** \brief Take a snapshot the current state and process it. - * - * \return number of the duplicate state or -1 (not visited) - */ -static int is_visited_state() -{ - - /* Reduction on visited states disabled for the first execution - path if the detection of the communication determinism is - enabled (we need to a complete initial communication pattern) */ - if ((_sg_mc_visited == 0) || - ((_sg_mc_comms_determinism || _sg_mc_send_determinism) - && !initial_state_safety->initial_communications_pattern_done)) - return -1; - - int raw_mem_set = (mmalloc_get_current_heap() == mc_heap); - - MC_SET_MC_HEAP; - - mc_visited_state_t new_state = visited_state_new(); - - if (xbt_dynar_is_empty(visited_states)) { - - xbt_dynar_push(visited_states, &new_state); - - if (!raw_mem_set) - MC_SET_STD_HEAP; - - return -1; - - } else { - - int min = -1, max = -1, index; - //int res; - mc_visited_state_t state_test; - int cursor; - - index = get_search_interval(visited_states, new_state, &min, &max); - - if (min != -1 && max != -1) { - - // Parallell implementation - /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state); - if(res != -1){ - state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t); - if(state_test->other_num == -1) - new_state->other_num = state_test->num; - else - new_state->other_num = state_test->other_num; - if(dot_output == NULL) - XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num); - else - XBT_DEBUG("State %d already visited ! (equal to state %d (state %d in dot_output))", new_state->num, state_test->num, new_state->other_num); - xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL); - xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state); - if(!raw_mem_set) - MC_SET_STD_HEAP; - return new_state->other_num; - } */ - - cursor = min; - while (cursor <= max) { - state_test = - (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor, - mc_visited_state_t); - if (snapshot_compare(state_test, new_state) == 0) { - // The state has been visited: - - if (state_test->other_num == -1) - new_state->other_num = state_test->num; - else - new_state->other_num = state_test->other_num; - if (dot_output == NULL) - XBT_DEBUG("State %d already visited ! (equal to state %d)", - new_state->num, state_test->num); - else - XBT_DEBUG - ("State %d already visited ! (equal to state %d (state %d in dot_output))", - new_state->num, state_test->num, new_state->other_num); - - // Replace the old state with the new one (why?): - xbt_dynar_remove_at(visited_states, cursor, NULL); - xbt_dynar_insert_at(visited_states, cursor, &new_state); - - if (!raw_mem_set) - MC_SET_STD_HEAP; - return new_state->other_num; - } - cursor++; - } - - // The state has not been visited, add it to the list: - xbt_dynar_insert_at(visited_states, min, &new_state); - - } else { - - // The state has not been visited: insert the state in the dynamic array. - state_test = - (mc_visited_state_t) xbt_dynar_get_as(visited_states, index, - mc_visited_state_t); - if (state_test->nb_processes < new_state->nb_processes) { - xbt_dynar_insert_at(visited_states, index + 1, &new_state); - } else { - if (state_test->heap_bytes_used < new_state->heap_bytes_used) - xbt_dynar_insert_at(visited_states, index + 1, &new_state); - else - xbt_dynar_insert_at(visited_states, index, &new_state); - } - - } - - // We have reached the maximum number of stored states; - if (xbt_dynar_length(visited_states) > _sg_mc_visited) { - - // Find the (index of the) older state: - int min2 = mc_stats->expanded_states; - unsigned int cursor2 = 0; - unsigned int index2 = 0; - xbt_dynar_foreach(visited_states, cursor2, state_test) { - if (state_test->num < min2) { - index2 = cursor2; - min2 = state_test->num; - } - } - - // and drop it: - xbt_dynar_remove_at(visited_states, index2, NULL); - } - - if (!raw_mem_set) - MC_SET_STD_HEAP; - - return -1; - - } -} - -/** - * \brief Initialize the DPOR exploration algorithm - */ -void MC_dpor_init() -{ - - int raw_mem_set = (mmalloc_get_current_heap() == mc_heap); - - mc_state_t initial_state = NULL; - smx_process_t process; - - /* Create the initial state and push it into the exploration stack */ - MC_SET_MC_HEAP; - - if (_sg_mc_visited > 0) - visited_states = - xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp); - - if (mc_reduce_kind == e_mc_reduce_dpor) - first_enabled_state = xbt_dict_new_homogeneous(&xbt_free_f); - - if (_sg_mc_comms_determinism || _sg_mc_send_determinism) { - initial_communications_pattern = - xbt_dynar_new(sizeof(mc_comm_pattern_t), comm_pattern_free_voidp); - communications_pattern = - xbt_dynar_new(sizeof(mc_comm_pattern_t), comm_pattern_free_voidp); - incomplete_communications_pattern = xbt_dynar_new(sizeof(int), NULL); - nb_comm_pattern = 0; - } - - initial_state = MC_state_new(); - - MC_SET_STD_HEAP; - - XBT_DEBUG("**************************************************"); - XBT_DEBUG("Initial state"); - - /* Wait for requests (schedules processes) */ - MC_wait_for_requests(); - - MC_ignore_heap(simix_global->process_to_run->data, 0); - MC_ignore_heap(simix_global->process_that_ran->data, 0); - - MC_SET_MC_HEAP; - - /* Get an enabled process and insert it in the interleave set of the initial state */ - xbt_swag_foreach(process, simix_global->process_list) { - if (MC_process_is_enabled(process)) { - MC_state_interleave_process(initial_state, process); - if (mc_reduce_kind != e_mc_reduce_none) - break; - } - } - - xbt_fifo_unshift(mc_stack_safety, initial_state); - - if (mc_reduce_kind == e_mc_reduce_dpor) { - /* To ensure the soundness of DPOR, we have to keep a list of - processes which are still enabled at each step of the exploration. - If max depth is reached, we interleave them in the state in which they have - been enabled for the first time. */ - xbt_swag_foreach(process, simix_global->process_list) { - if (MC_process_is_enabled(process)) { - char *key = bprintf("%lu", process->pid); - char *data = bprintf("%d", xbt_fifo_size(mc_stack_safety)); - xbt_dict_set(first_enabled_state, key, data, NULL); - xbt_free(key); - } - } - } - - MC_SET_STD_HEAP; - - if (raw_mem_set) - MC_SET_MC_HEAP; - else - MC_SET_STD_HEAP; - -} - - -/** \brief Model-check the application using a DFS exploration - * with DPOR (Dynamic Partial Order Reductions) - */ -void MC_dpor(void) -{ - - char *req_str = NULL; - int value; - smx_simcall_t req = NULL, prev_req = NULL; - mc_state_t state = NULL, prev_state = NULL, next_state = - NULL, restored_state = NULL; - smx_process_t process = NULL; - xbt_fifo_item_t item = NULL; - mc_state_t state_test = NULL; - int pos; - int visited_state = -1; - int enabled = 0; - int comm_pattern = 0; - smx_action_t current_comm; - - while (xbt_fifo_size(mc_stack_safety) > 0) { - - /* Get current state */ - state = (mc_state_t) - xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_safety)); - - XBT_DEBUG("**************************************************"); - XBT_DEBUG - ("Exploration depth=%d (state=%p, num %d)(%u interleave, user_max_depth %d, first_enabled_state size : %d)", - xbt_fifo_size(mc_stack_safety), state, state->num, - MC_state_interleave_size(state), user_max_depth_reached, - xbt_dict_size(first_enabled_state)); - - /* Update statistics */ - mc_stats->visited_states++; - - /* If there are processes to interleave and the maximum depth has not been reached - then perform one step of the exploration algorithm */ - if (xbt_fifo_size(mc_stack_safety) <= _sg_mc_max_depth - && !user_max_depth_reached - && (req = MC_state_get_request(state, &value)) && visited_state == -1) { - - /* Debug information */ - if (XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)) { - req_str = MC_request_to_string(req, value); - XBT_DEBUG("Execute: %s", req_str); - xbt_free(req_str); - } - - MC_SET_MC_HEAP; - if (dot_output != NULL) - req_str = MC_request_get_dot_output(req, value); - MC_SET_STD_HEAP; - - MC_state_set_executed_request(state, req, value); - mc_stats->executed_transitions++; - - if (mc_reduce_kind == e_mc_reduce_dpor) { - MC_SET_MC_HEAP; - char *key = bprintf("%lu", req->issuer->pid); - xbt_dict_remove(first_enabled_state, key); - xbt_free(key); - MC_SET_STD_HEAP; - } - - /* TODO : handle test and testany simcalls */ - if (_sg_mc_comms_determinism || _sg_mc_send_determinism) { - if (req->call == SIMCALL_COMM_ISEND) - comm_pattern = 1; - else if (req->call == SIMCALL_COMM_IRECV) - comm_pattern = 2; - else if (req->call == SIMCALL_COMM_WAIT) - comm_pattern = 3; - else if (req->call == SIMCALL_COMM_WAITANY) - comm_pattern = 4; - } - - /* Answer the request */ - SIMIX_simcall_pre(req, value); /* After this call req is no longer usefull */ - - if (_sg_mc_comms_determinism || _sg_mc_send_determinism) { - MC_SET_MC_HEAP; - if (comm_pattern == 1 || comm_pattern == 2) { - if (!initial_state_safety->initial_communications_pattern_done) - get_comm_pattern(initial_communications_pattern, req, comm_pattern); - else - get_comm_pattern(communications_pattern, req, comm_pattern); - } else if (comm_pattern == 3) { - current_comm = simcall_comm_wait__get__comm(req); - if (current_comm->comm.refcount == 1) { /* First wait only must be considered */ - if (!initial_state_safety->initial_communications_pattern_done) - complete_comm_pattern(initial_communications_pattern, - current_comm); - else - complete_comm_pattern(communications_pattern, current_comm); - } - } else if (comm_pattern == 4) { - current_comm = - xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), value, - smx_action_t); - if (current_comm->comm.refcount == 1) { /* First wait only must be considered */ - if (!initial_state_safety->initial_communications_pattern_done) - complete_comm_pattern(initial_communications_pattern, - current_comm); - else - complete_comm_pattern(communications_pattern, current_comm); - } - } - MC_SET_STD_HEAP; - comm_pattern = 0; - } - - /* Wait for requests (schedules processes) */ - MC_wait_for_requests(); - - /* Create the new expanded state */ - MC_SET_MC_HEAP; - - next_state = MC_state_new(); - - if ((visited_state = is_visited_state()) == -1) { - - /* Get an enabled process and insert it in the interleave set of the next state */ - xbt_swag_foreach(process, simix_global->process_list) { - if (MC_process_is_enabled(process)) { - MC_state_interleave_process(next_state, process); - if (mc_reduce_kind != e_mc_reduce_none) - break; - } - } - - if (_sg_mc_checkpoint - && ((xbt_fifo_size(mc_stack_safety) + 1) % _sg_mc_checkpoint == - 0)) { - next_state->system_state = MC_take_snapshot(next_state->num); - } - - if (dot_output != NULL) - fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, - next_state->num, req_str); - - } else { - - if (dot_output != NULL) - fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, - visited_state, req_str); - - } - - xbt_fifo_unshift(mc_stack_safety, next_state); - - if (mc_reduce_kind == e_mc_reduce_dpor) { - /* Insert in dict all enabled processes, if not included yet */ - xbt_swag_foreach(process, simix_global->process_list) { - if (MC_process_is_enabled(process)) { - char *key = bprintf("%lu", process->pid); - if (xbt_dict_get_or_null(first_enabled_state, key) == NULL) { - char *data = bprintf("%d", xbt_fifo_size(mc_stack_safety)); - xbt_dict_set(first_enabled_state, key, data, NULL); - } - xbt_free(key); - } - } - } - - if (dot_output != NULL) - xbt_free(req_str); - - MC_SET_STD_HEAP; - - /* Let's loop again */ - - /* The interleave set is empty or the maximum depth is reached, let's back-track */ - } else { - - if ((xbt_fifo_size(mc_stack_safety) > _sg_mc_max_depth) - || user_max_depth_reached || visited_state != -1) { - - if (user_max_depth_reached && visited_state == -1) - XBT_DEBUG("User max depth reached !"); - else if (visited_state == -1) - XBT_WARN("/!\\ Max depth reached ! /!\\ "); - - if (mc_reduce_kind == e_mc_reduce_dpor) { - /* Interleave enabled processes in the state in which they have been enabled for the first time */ - xbt_swag_foreach(process, simix_global->process_list) { - if (MC_process_is_enabled(process)) { - char *key = bprintf("%lu", process->pid); - enabled = - (int) strtoul(xbt_dict_get_or_null(first_enabled_state, key), - 0, 10); - xbt_free(key); - int cursor = xbt_fifo_size(mc_stack_safety); - xbt_fifo_foreach(mc_stack_safety, item, state_test, mc_state_t) { - if (cursor-- == enabled) { - if (!MC_state_process_is_done(state_test, process) - && state_test->num != state->num) { - XBT_DEBUG("Interleave process %lu in state %d", - process->pid, state_test->num); - MC_state_interleave_process(state_test, process); - break; - } - } - } - } - } - } - - } else { - - XBT_DEBUG("There are no more processes to interleave. (depth %d)", - xbt_fifo_size(mc_stack_safety) + 1); - - } - - MC_SET_MC_HEAP; - - if (_sg_mc_comms_determinism || _sg_mc_send_determinism) { - if (initial_state_safety->initial_communications_pattern_done) { - if (visited_state == -1) { - deterministic_pattern(initial_communications_pattern, - communications_pattern); - if (initial_state_safety->comm_deterministic == 0 - && _sg_mc_comms_determinism) { - XBT_INFO("****************************************************"); - XBT_INFO("***** Non-deterministic communications pattern *****"); - XBT_INFO("****************************************************"); - XBT_INFO("Initial communications pattern:"); - print_communications_pattern(initial_communications_pattern); - XBT_INFO("Communications pattern counter-example:"); - print_communications_pattern(communications_pattern); - MC_print_statistics(mc_stats); - return; - } else if (initial_state_safety->send_deterministic == 0 - && _sg_mc_send_determinism) { - XBT_INFO - ("*********************************************************"); - XBT_INFO - ("***** Non-send-deterministic communications pattern *****"); - XBT_INFO - ("*********************************************************"); - XBT_INFO("Initial communications pattern:"); - print_communications_pattern(initial_communications_pattern); - XBT_INFO("Communications pattern counter-example:"); - print_communications_pattern(communications_pattern); - MC_print_statistics(mc_stats); - return; - } - } else { - - } - } else { - initial_state_safety->initial_communications_pattern_done = 1; - } - } - - /* Trash the current state, no longer needed */ - xbt_fifo_shift(mc_stack_safety); - MC_state_delete(state); - XBT_DEBUG("Delete state %d at depth %d", state->num, - xbt_fifo_size(mc_stack_safety) + 1); - - MC_SET_STD_HEAP; - - visited_state = -1; - - /* Check for deadlocks */ - if (MC_deadlock_check()) { - MC_show_deadlock(NULL); - return; - } - - MC_SET_MC_HEAP; - /* Traverse the stack backwards until a state with a non empty interleave - set is found, deleting all the states that have it empty in the way. - For each deleted state, check if the request that has generated it - (from it's predecesor state), depends on any other previous request - executed before it. If it does then add it to the interleave set of the - state that executed that previous request. */ - - while ((state = xbt_fifo_shift(mc_stack_safety)) != NULL) { - if (mc_reduce_kind == e_mc_reduce_dpor) { - req = MC_state_get_internal_request(state); - xbt_fifo_foreach(mc_stack_safety, item, prev_state, mc_state_t) { - if (MC_request_depend - (req, MC_state_get_internal_request(prev_state))) { - if (XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)) { - XBT_DEBUG("Dependent Transitions:"); - prev_req = MC_state_get_executed_request(prev_state, &value); - req_str = MC_request_to_string(prev_req, value); - XBT_DEBUG("%s (state=%d)", req_str, prev_state->num); - xbt_free(req_str); - prev_req = MC_state_get_executed_request(state, &value); - req_str = MC_request_to_string(prev_req, value); - XBT_DEBUG("%s (state=%d)", req_str, state->num); - xbt_free(req_str); - } - - if (!MC_state_process_is_done(prev_state, req->issuer)) - MC_state_interleave_process(prev_state, req->issuer); - else - XBT_DEBUG("Process %p is in done set", req->issuer); - - break; - - } else if (req->issuer == - MC_state_get_internal_request(prev_state)->issuer) { - - XBT_DEBUG("Simcall %d and %d with same issuer", req->call, - MC_state_get_internal_request(prev_state)->call); - break; - - } else { - - XBT_DEBUG - ("Simcall %d, process %lu (state %d) and simcall %d, process %lu (state %d) are independant", - req->call, req->issuer->pid, state->num, - MC_state_get_internal_request(prev_state)->call, - MC_state_get_internal_request(prev_state)->issuer->pid, - prev_state->num); - - } - } - } - - if (MC_state_interleave_size(state) - && xbt_fifo_size(mc_stack_safety) < _sg_mc_max_depth) { - /* We found a back-tracking point, let's loop */ - XBT_DEBUG("Back-tracking to state %d at depth %d", state->num, - xbt_fifo_size(mc_stack_safety) + 1); - if (_sg_mc_checkpoint) { - if (state->system_state != NULL) { - MC_restore_snapshot(state->system_state); - xbt_fifo_unshift(mc_stack_safety, state); - MC_SET_STD_HEAP; - } else { - pos = xbt_fifo_size(mc_stack_safety); - item = xbt_fifo_get_first_item(mc_stack_safety); - while (pos > 0) { - restored_state = (mc_state_t) xbt_fifo_get_item_content(item); - if (restored_state->system_state != NULL) { - break; - } else { - item = xbt_fifo_get_next_item(item); - pos--; - } - } - MC_restore_snapshot(restored_state->system_state); - xbt_fifo_unshift(mc_stack_safety, state); - MC_SET_STD_HEAP; - MC_replay(mc_stack_safety, pos); - } - } else { - xbt_fifo_unshift(mc_stack_safety, state); - MC_SET_STD_HEAP; - MC_replay(mc_stack_safety, -1); - } - XBT_DEBUG("Back-tracking to state %d at depth %d done", state->num, - xbt_fifo_size(mc_stack_safety)); - break; - } else { - /*req = MC_state_get_internal_request(state); - if(_sg_mc_comms_determinism || _sg_mc_send_determinism){ - if(req->call == SIMCALL_COMM_ISEND || req->call == SIMCALL_COMM_IRECV){ - if(!xbt_dynar_is_empty(communications_pattern)) - xbt_dynar_remove_at(communications_pattern, xbt_dynar_length(communications_pattern) - 1, NULL); - } - } */ - XBT_DEBUG("Delete state %d at depth %d", state->num, - xbt_fifo_size(mc_stack_safety) + 1); - MC_state_delete(state); - } - } - MC_SET_STD_HEAP; - } - } - MC_print_statistics(mc_stats); - MC_SET_STD_HEAP; - - return; -}