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. */
12 #include <xbt/automaton.h>
14 #include <xbt/sysdep.h>
15 #include <xbt/dynar.h>
18 #include "src/mc/mc_comm_pattern.h"
19 #include "src/mc/mc_safety.h"
20 #include "src/mc/mc_liveness.h"
21 #include "src/mc/mc_private.h"
22 #include "src/mc/Process.hpp"
23 #include "src/mc/mc_smx.h"
25 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
26 "Logging specific to state equaity detection mechanisms");
31 std::vector<std::unique_ptr<simgrid::mc::VisitedState>> visited_states;
33 static int is_exploration_stack_state(simgrid::mc::VisitedState* state){
34 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
36 if (((mc_state_t)xbt_fifo_get_item_content(item))->num == state->num){
37 ((mc_state_t)xbt_fifo_get_item_content(item))->in_visited_states = 0;
40 item = xbt_fifo_get_next_item(item);
46 * \brief Save the current state
47 * \return Snapshot of the current state.
49 VisitedState::VisitedState()
51 simgrid::mc::Process* process = &(mc_model_checker->process());
52 this->heap_bytes_used = mmalloc_get_bytes_used_remote(
53 process->get_heap()->heaplimit,
54 process->get_malloc_info());
57 mc_model_checker->process().simix_processes().size();
59 this->system_state = simgrid::mc::take_snapshot(mc_stats->expanded_states);
60 this->num = mc_stats->expanded_states;
64 VisitedState::~VisitedState()
66 if(!is_exploration_stack_state(this))
67 delete this->system_state;
70 VisitedPair::VisitedPair(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state)
72 simgrid::mc::Process* process = &(mc_model_checker->process());
74 this->graph_state = graph_state;
75 if(this->graph_state->system_state == nullptr)
76 this->graph_state->system_state = simgrid::mc::take_snapshot(pair_num);
77 this->heap_bytes_used = mmalloc_get_bytes_used_remote(
78 process->get_heap()->heaplimit,
79 process->get_malloc_info());
82 mc_model_checker->process().simix_processes().size();
84 this->automaton_state = automaton_state;
87 this->acceptance_removed = 0;
88 this->visited_removed = 0;
89 this->acceptance_pair = 0;
90 this->atomic_propositions = simgrid::xbt::unique_ptr<s_xbt_dynar_t>(
91 xbt_dynar_new(sizeof(int), nullptr));
93 unsigned int cursor = 0;
95 xbt_dynar_foreach(atomic_propositions, cursor, value)
96 xbt_dynar_push_as(this->atomic_propositions.get(), int, value);
99 static int is_exploration_stack_pair(simgrid::mc::VisitedPair* pair){
100 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
102 if (((simgrid::mc::Pair*)xbt_fifo_get_item_content(item))->num == pair->num){
103 ((simgrid::mc::Pair*)xbt_fifo_get_item_content(item))->visited_pair_removed = 1;
106 item = xbt_fifo_get_next_item(item);
111 VisitedPair::~VisitedPair()
113 if( !is_exploration_stack_pair(this))
114 MC_state_delete(this->graph_state, 1);
121 * \brief Find a suitable subrange of candidate duplicates for a given state
122 * \param list dynamic array of states/pairs with candidate duplicates of the current state;
123 * \param ref current state/pair;
124 * \param min (output) index of the beginning of the the subrange
125 * \param max (output) index of the enf of the subrange
127 * Given a suitably ordered array of states/pairs, this function extracts a subrange
128 * (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
129 * This function uses only fast discriminating criterions and does not use the
130 * full state/pair comparison algorithms.
132 * The states/pairs in list MUST be ordered using a (given) weak order
133 * (based on nb_processes and heap_bytes_used).
134 * The subrange is the subrange of "equivalence" of the given state/pair.
136 int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
138 int cursor = 0, previous_cursor;
139 int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
142 if (_sg_mc_liveness) {
143 nb_processes = ((simgrid::mc::VisitedPair*) ref)->nb_processes;
144 heap_bytes_used = ((simgrid::mc::VisitedPair*) ref)->heap_bytes_used;
146 nb_processes = ((simgrid::mc::VisitedState*) ref)->nb_processes;
147 heap_bytes_used = ((simgrid::mc::VisitedState*) ref)->heap_bytes_used;
151 int end = xbt_dynar_length(list) - 1;
153 while (start <= end) {
154 cursor = (start + end) / 2;
155 if (_sg_mc_liveness) {
156 ref_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(list, cursor, simgrid::mc::VisitedPair*);
157 nb_processes_test = ((simgrid::mc::VisitedPair*) ref_test)->nb_processes;
158 heap_bytes_used_test = ((simgrid::mc::VisitedPair*) ref_test)->heap_bytes_used;
160 ref_test = (simgrid::mc::VisitedState*) xbt_dynar_get_as(list, cursor, simgrid::mc::VisitedState*);
161 nb_processes_test = ((simgrid::mc::VisitedState*) ref_test)->nb_processes;
162 heap_bytes_used_test = ((simgrid::mc::VisitedState*) ref_test)->heap_bytes_used;
164 if (nb_processes_test < nb_processes)
166 else if (nb_processes_test > nb_processes)
168 else if (heap_bytes_used_test < heap_bytes_used)
170 else if (heap_bytes_used_test > heap_bytes_used)
173 *min = *max = cursor;
174 previous_cursor = cursor - 1;
175 while (previous_cursor >= 0) {
176 if (_sg_mc_liveness) {
177 ref_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(list, previous_cursor, simgrid::mc::VisitedPair*);
178 nb_processes_test = ((simgrid::mc::VisitedPair*) ref_test)->nb_processes;
179 heap_bytes_used_test = ((simgrid::mc::VisitedPair*) ref_test)->heap_bytes_used;
181 ref_test = (simgrid::mc::VisitedState*) xbt_dynar_get_as(list, previous_cursor, simgrid::mc::VisitedState*);
182 nb_processes_test = ((simgrid::mc::VisitedState*) ref_test)->nb_processes;
183 heap_bytes_used_test = ((simgrid::mc::VisitedState*) ref_test)->heap_bytes_used;
185 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
187 *min = previous_cursor;
190 size_t next_cursor = cursor + 1;
191 while (next_cursor < xbt_dynar_length(list)) {
192 if (_sg_mc_liveness) {
193 ref_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(list, next_cursor, simgrid::mc::VisitedPair*);
194 nb_processes_test = ((simgrid::mc::VisitedPair*) ref_test)->nb_processes;
195 heap_bytes_used_test = ((simgrid::mc::VisitedPair*) ref_test)->heap_bytes_used;
197 ref_test = (simgrid::mc::VisitedState*) xbt_dynar_get_as(list, next_cursor, simgrid::mc::VisitedState*);
198 nb_processes_test = ((simgrid::mc::VisitedState*) ref_test)->nb_processes;
199 heap_bytes_used_test = ((simgrid::mc::VisitedState*) ref_test)->heap_bytes_used;
201 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
212 // TODO, it would make sense to use std::set instead
214 int get_search_interval(std::vector<std::unique_ptr<T>> const& list, T *ref, int *min, int *max)
216 int nb_processes = ref->nb_processes;
217 int heap_bytes_used = ref->heap_bytes_used;
221 int end = list.size() - 1;
222 while (start <= end) {
223 cursor = (start + end) / 2;
224 int nb_processes_test = list[cursor]->nb_processes;
225 int heap_bytes_used_test = list[cursor]->heap_bytes_used;
227 if (nb_processes_test < nb_processes)
229 else if (nb_processes_test > nb_processes)
231 else if (heap_bytes_used_test < heap_bytes_used)
233 else if (heap_bytes_used_test > heap_bytes_used)
236 *min = *max = cursor;
237 int previous_cursor = cursor - 1;
238 while (previous_cursor >= 0) {
239 nb_processes_test = list[previous_cursor]->nb_processes;
240 heap_bytes_used_test = list[previous_cursor]->heap_bytes_used;
241 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
243 *min = previous_cursor;
246 size_t next_cursor = cursor + 1;
247 while (next_cursor < list.size()) {
248 nb_processes_test = list[next_cursor]->nb_processes;
249 heap_bytes_used_test = list[next_cursor]->heap_bytes_used;
250 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
262 bool some_communications_are_not_finished()
264 for (size_t current_process = 1; current_process < MC_smx_get_maxpid(); current_process++) {
265 xbt_dynar_t pattern = xbt_dynar_get_as(
266 incomplete_communications_pattern, current_process, xbt_dynar_t);
267 if (!xbt_dynar_is_empty(pattern)) {
268 XBT_DEBUG("Some communications are not finished, cannot stop the exploration ! State not visited.");
279 * \brief Checks whether a given state has already been visited by the algorithm.
281 std::unique_ptr<simgrid::mc::VisitedState> is_visited_state(mc_state_t graph_state)
283 if (_sg_mc_visited == 0)
286 /* If comm determinism verification, we cannot stop the exploration if some
287 communications are not finished (at least, data are transfered). These communications
288 are incomplete and they cannot be analyzed and compared with the initial pattern. */
289 int partial_comm = (_sg_mc_comms_determinism || _sg_mc_send_determinism) &&
290 some_communications_are_not_finished();
292 std::unique_ptr<simgrid::mc::VisitedState> new_state =
293 std::unique_ptr<simgrid::mc::VisitedState>(new VisitedState());
294 graph_state->system_state = new_state->system_state;
295 graph_state->in_visited_states = 1;
296 XBT_DEBUG("Snapshot %p of visited state %d (exploration stack state %d)", new_state->system_state, new_state->num, graph_state->num);
298 if (visited_states.empty()) {
299 visited_states.push_back(std::move(new_state));
303 int min = -1, max = -1, index;
305 index = get_search_interval(visited_states, new_state.get(), &min, &max);
307 if (min != -1 && max != -1) {
309 if (_sg_mc_safety || (!partial_comm
310 && initial_global_state->initial_communications_pattern_done)) {
313 while (cursor <= max) {
314 if (snapshot_compare(visited_states[cursor].get(), new_state.get()) == 0) {
315 // The state has been visited:
317 std::unique_ptr<simgrid::mc::VisitedState> old_state =
318 std::move(visited_states[cursor]);
320 if (old_state->other_num == -1)
321 new_state->other_num = old_state->num;
323 new_state->other_num = old_state->other_num;
325 if (dot_output == nullptr)
326 XBT_DEBUG("State %d already visited ! (equal to state %d)",
327 new_state->num, old_state->num);
330 "State %d already visited ! (equal to state %d (state %d in dot_output))",
331 new_state->num, old_state->num, new_state->other_num);
333 /* Replace the old state with the new one (with a bigger num)
334 (when the max number of visited states is reached, the oldest
335 one is removed according to its number (= with the min number) */
336 XBT_DEBUG("Replace visited state %d with the new visited state %d",
337 old_state->num, new_state->num);
339 simgrid::mc::visited_states[cursor] = std::move(new_state);
340 return std::move(old_state);
346 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, (unsigned long) visited_states.size());
347 visited_states.insert(visited_states.begin() + min, std::move(new_state));
351 // The state has not been visited: insert the state in the dynamic array.
352 simgrid::mc::VisitedState* state_test = &*visited_states[index];
353 std::size_t position;
354 if (state_test->nb_processes < new_state->nb_processes)
355 position = index + 1;
356 else if (state_test->heap_bytes_used < new_state->heap_bytes_used)
357 position = index + 1;
360 visited_states.insert(visited_states.begin() + position, std::move(new_state));
361 XBT_DEBUG("Insert new visited state %d (total : %lu)",
362 visited_states[index]->num,
363 (unsigned long) visited_states.size());
367 if (visited_states.size() <= (std::size_t) _sg_mc_visited)
370 // We have reached the maximum number of stored states;
372 XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)");
374 // Find the (index of the) older state (with the smallest num):
375 int min2 = mc_stats->expanded_states;
376 unsigned int index2 = 0;
378 for (std::size_t cursor2 = 0; cursor2 != visited_states.size(); ++cursor2)
379 if (!mc_model_checker->is_important_snapshot(
380 *visited_states[cursor2]->system_state)
381 && visited_states[cursor2]->num < min2) {
383 min2 = visited_states[cursor2]->num;
387 visited_states.erase(visited_states.begin() + index2);
388 XBT_DEBUG("Remove visited state (maximum number of stored states reached)");