1 /* Copyright (c) 2011-2015. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
13 #include <xbt/automaton.h>
15 #include <xbt/sysdep.h>
16 #include <xbt/dynar.h>
17 #include <xbt/dynar.hpp>
20 #include "src/mc/mc_comm_pattern.h"
21 #include "src/mc/mc_safety.h"
22 #include "src/mc/mc_liveness.h"
23 #include "src/mc/mc_private.h"
24 #include "src/mc/Process.hpp"
25 #include "src/mc/mc_smx.h"
27 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
28 "Logging specific to state equaity detection mechanisms");
33 std::vector<std::unique_ptr<simgrid::mc::VisitedState>> visited_states;
35 static int is_exploration_stack_state(simgrid::mc::VisitedState* state){
36 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
38 if (((mc_state_t)xbt_fifo_get_item_content(item))->num == state->num){
39 ((mc_state_t)xbt_fifo_get_item_content(item))->in_visited_states = 0;
42 item = xbt_fifo_get_next_item(item);
48 * \brief Save the current state
49 * \return Snapshot of the current state.
51 VisitedState::VisitedState()
53 simgrid::mc::Process* process = &(mc_model_checker->process());
54 this->heap_bytes_used = mmalloc_get_bytes_used_remote(
55 process->get_heap()->heaplimit,
56 process->get_malloc_info());
59 mc_model_checker->process().simix_processes().size();
61 this->system_state = simgrid::mc::take_snapshot(mc_stats->expanded_states);
62 this->num = mc_stats->expanded_states;
66 VisitedState::~VisitedState()
68 if(!is_exploration_stack_state(this))
69 delete this->system_state;
72 VisitedPair::VisitedPair(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state)
74 simgrid::mc::Process* process = &(mc_model_checker->process());
76 this->graph_state = graph_state;
77 if(this->graph_state->system_state == nullptr)
78 this->graph_state->system_state = simgrid::mc::take_snapshot(pair_num);
79 this->heap_bytes_used = mmalloc_get_bytes_used_remote(
80 process->get_heap()->heaplimit,
81 process->get_malloc_info());
84 mc_model_checker->process().simix_processes().size();
86 this->automaton_state = automaton_state;
89 this->acceptance_removed = 0;
90 this->visited_removed = 0;
91 this->acceptance_pair = 0;
92 this->atomic_propositions = simgrid::xbt::unique_ptr<s_xbt_dynar_t>(
93 xbt_dynar_new(sizeof(int), nullptr));
95 unsigned int cursor = 0;
97 xbt_dynar_foreach(atomic_propositions, cursor, value)
98 xbt_dynar_push_as(this->atomic_propositions.get(), int, value);
101 static int is_exploration_stack_pair(simgrid::mc::VisitedPair* pair){
102 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
104 if (((simgrid::mc::Pair*)xbt_fifo_get_item_content(item))->num == pair->num){
105 ((simgrid::mc::Pair*)xbt_fifo_get_item_content(item))->visited_pair_removed = 1;
108 item = xbt_fifo_get_next_item(item);
113 VisitedPair::~VisitedPair()
115 if( !is_exploration_stack_pair(this))
116 MC_state_delete(this->graph_state, 1);
123 bool some_communications_are_not_finished()
125 for (size_t current_process = 1; current_process < MC_smx_get_maxpid(); current_process++) {
126 xbt_dynar_t pattern = xbt_dynar_get_as(
127 incomplete_communications_pattern, current_process, xbt_dynar_t);
128 if (!xbt_dynar_is_empty(pattern)) {
129 XBT_DEBUG("Some communications are not finished, cannot stop the exploration ! State not visited.");
139 static void prune_visited_states()
141 while (visited_states.size() > (std::size_t) _sg_mc_visited) {
142 XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)");
143 auto min_element = std::min_element(visited_states.begin(), visited_states.end(),
144 [](std::unique_ptr<simgrid::mc::VisitedState>& a, std::unique_ptr<simgrid::mc::VisitedState>& b) {
145 return a->num < b->num;
147 xbt_assert(min_element != visited_states.end());
149 visited_states.erase(min_element);
150 XBT_DEBUG("Remove visited state (maximum number of stored states reached)");
155 * \brief Checks whether a given state has already been visited by the algorithm.
157 std::unique_ptr<simgrid::mc::VisitedState> is_visited_state(mc_state_t graph_state)
159 if (_sg_mc_visited == 0)
162 /* If comm determinism verification, we cannot stop the exploration if some
163 communications are not finished (at least, data are transfered). These communications
164 are incomplete and they cannot be analyzed and compared with the initial pattern. */
165 int partial_comm = (_sg_mc_comms_determinism || _sg_mc_send_determinism) &&
166 some_communications_are_not_finished();
168 std::unique_ptr<simgrid::mc::VisitedState> new_state =
169 std::unique_ptr<simgrid::mc::VisitedState>(new VisitedState());
170 graph_state->system_state = new_state->system_state;
171 graph_state->in_visited_states = 1;
172 XBT_DEBUG("Snapshot %p of visited state %d (exploration stack state %d)", new_state->system_state, new_state->num, graph_state->num);
174 auto range = std::equal_range(visited_states.begin(), visited_states.end(),
175 new_state.get(), simgrid::mc::DerefAndCompareByNbProcessesAndUsedHeap());
177 if (_sg_mc_safety || (!partial_comm
178 && initial_global_state->initial_communications_pattern_done)) {
180 for (auto i = range.first; i != range.second; ++i) {
181 auto& visited_state = *i;
182 if (snapshot_compare(visited_state.get(), new_state.get()) == 0) {
183 // The state has been visited:
185 std::unique_ptr<simgrid::mc::VisitedState> old_state =
186 std::move(visited_state);
188 if (old_state->other_num == -1)
189 new_state->other_num = old_state->num;
191 new_state->other_num = old_state->other_num;
193 if (dot_output == nullptr)
194 XBT_DEBUG("State %d already visited ! (equal to state %d)",
195 new_state->num, old_state->num);
198 "State %d already visited ! (equal to state %d (state %d in dot_output))",
199 new_state->num, old_state->num, new_state->other_num);
201 /* Replace the old state with the new one (with a bigger num)
202 (when the max number of visited states is reached, the oldest
203 one is removed according to its number (= with the min number) */
204 XBT_DEBUG("Replace visited state %d with the new visited state %d",
205 old_state->num, new_state->num);
207 visited_state = std::move(new_state);
208 return std::move(old_state);
213 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, (unsigned long) visited_states.size());
214 visited_states.insert(range.first, std::move(new_state));
215 prune_visited_states();