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. */
10 #include <xbt/automaton.h>
12 #include <xbt/sysdep.h>
13 #include <xbt/dynar.h>
16 #include "src/mc/mc_comm_pattern.h"
17 #include "src/mc/mc_safety.h"
18 #include "src/mc/mc_liveness.h"
19 #include "src/mc/mc_private.h"
20 #include "src/mc/Process.hpp"
21 #include "src/mc/mc_smx.h"
25 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
26 "Logging specific to state equaity detection mechanisms");
33 xbt_dynar_t visited_pairs;
38 xbt_dynar_t visited_states;
40 static int is_exploration_stack_state(mc_visited_state_t state){
41 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
43 if (((mc_state_t)xbt_fifo_get_item_content(item))->num == state->num){
44 ((mc_state_t)xbt_fifo_get_item_content(item))->in_visited_states = 0;
47 item = xbt_fifo_get_next_item(item);
52 void visited_state_free(mc_visited_state_t state)
56 if(!is_exploration_stack_state(state))
57 delete state->system_state;
61 void visited_state_free_voidp(void *s)
63 visited_state_free((mc_visited_state_t) * (void **) s);
67 * \brief Save the current state
68 * \return Snapshot of the current state.
70 static mc_visited_state_t visited_state_new()
72 simgrid::mc::Process* process = &(mc_model_checker->process());
73 mc_visited_state_t new_state = xbt_new0(s_mc_visited_state_t, 1);
74 new_state->heap_bytes_used = mmalloc_get_bytes_used_remote(
75 process->get_heap()->heaplimit,
76 process->get_malloc_info());
78 MC_process_smx_refresh(&mc_model_checker->process());
79 new_state->nb_processes =
80 mc_model_checker->process().smx_process_infos.size();
82 new_state->system_state = simgrid::mc::take_snapshot(mc_stats->expanded_states);
83 new_state->num = mc_stats->expanded_states;
84 new_state->other_num = -1;
91 simgrid::mc::VisitedPair* visited_pair_new(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state)
93 simgrid::mc::Process* process = &(mc_model_checker->process());
94 simgrid::mc::VisitedPair* pair = nullptr;
95 pair = xbt_new0(simgrid::mc::VisitedPair, 1);
96 pair->graph_state = graph_state;
97 if(pair->graph_state->system_state == nullptr)
98 pair->graph_state->system_state = simgrid::mc::take_snapshot(pair_num);
99 pair->heap_bytes_used = mmalloc_get_bytes_used_remote(
100 process->get_heap()->heaplimit,
101 process->get_malloc_info());
103 MC_process_smx_refresh(&mc_model_checker->process());
105 mc_model_checker->process().smx_process_infos.size();
107 pair->automaton_state = automaton_state;
108 pair->num = pair_num;
109 pair->other_num = -1;
110 pair->acceptance_removed = 0;
111 pair->visited_removed = 0;
112 pair->acceptance_pair = 0;
113 pair->atomic_propositions = xbt_dynar_new(sizeof(int), nullptr);
114 unsigned int cursor = 0;
116 xbt_dynar_foreach(atomic_propositions, cursor, value)
117 xbt_dynar_push_as(pair->atomic_propositions, int, value);
121 static int is_exploration_stack_pair(simgrid::mc::VisitedPair* pair){
122 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
124 if (((simgrid::mc::Pair*)xbt_fifo_get_item_content(item))->num == pair->num){
125 ((simgrid::mc::Pair*)xbt_fifo_get_item_content(item))->visited_pair_removed = 1;
128 item = xbt_fifo_get_next_item(item);
133 void visited_pair_delete(simgrid::mc::VisitedPair* p)
135 p->automaton_state = nullptr;
136 if( !is_exploration_stack_pair(p))
137 MC_state_delete(p->graph_state, 1);
138 xbt_dynar_free(&(p->atomic_propositions));
147 * \brief Find a suitable subrange of candidate duplicates for a given state
148 * \param list dynamic array of states/pairs with candidate duplicates of the current state;
149 * \param ref current state/pair;
150 * \param min (output) index of the beginning of the the subrange
151 * \param max (output) index of the enf of the subrange
153 * Given a suitably ordered array of states/pairs, this function extracts a subrange
154 * (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
155 * This function uses only fast discriminating criterions and does not use the
156 * full state/pair comparison algorithms.
158 * The states/pairs in list MUST be ordered using a (given) weak order
159 * (based on nb_processes and heap_bytes_used).
160 * The subrange is the subrange of "equivalence" of the given state/pair.
162 int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
164 int cursor = 0, previous_cursor;
165 int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
168 if (_sg_mc_liveness) {
169 nb_processes = ((simgrid::mc::VisitedPair*) ref)->nb_processes;
170 heap_bytes_used = ((simgrid::mc::VisitedPair*) ref)->heap_bytes_used;
172 nb_processes = ((mc_visited_state_t) ref)->nb_processes;
173 heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
177 int end = xbt_dynar_length(list) - 1;
179 while (start <= end) {
180 cursor = (start + end) / 2;
181 if (_sg_mc_liveness) {
182 ref_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(list, cursor, simgrid::mc::VisitedPair*);
183 nb_processes_test = ((simgrid::mc::VisitedPair*) ref_test)->nb_processes;
184 heap_bytes_used_test = ((simgrid::mc::VisitedPair*) ref_test)->heap_bytes_used;
186 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, cursor, mc_visited_state_t);
187 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
188 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
190 if (nb_processes_test < nb_processes)
192 else if (nb_processes_test > nb_processes)
194 else if (heap_bytes_used_test < heap_bytes_used)
196 else if (heap_bytes_used_test > heap_bytes_used)
199 *min = *max = cursor;
200 previous_cursor = cursor - 1;
201 while (previous_cursor >= 0) {
202 if (_sg_mc_liveness) {
203 ref_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(list, previous_cursor, simgrid::mc::VisitedPair*);
204 nb_processes_test = ((simgrid::mc::VisitedPair*) ref_test)->nb_processes;
205 heap_bytes_used_test = ((simgrid::mc::VisitedPair*) ref_test)->heap_bytes_used;
207 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor, mc_visited_state_t);
208 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
209 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
211 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
213 *min = previous_cursor;
216 size_t next_cursor = cursor + 1;
217 while (next_cursor < xbt_dynar_length(list)) {
218 if (_sg_mc_liveness) {
219 ref_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(list, next_cursor, simgrid::mc::VisitedPair*);
220 nb_processes_test = ((simgrid::mc::VisitedPair*) ref_test)->nb_processes;
221 heap_bytes_used_test = ((simgrid::mc::VisitedPair*) ref_test)->heap_bytes_used;
223 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor, mc_visited_state_t);
224 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
225 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
227 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
240 mc_visited_state_t state_test, mc_visited_state_t new_state, int cursor)
242 if (state_test->other_num == -1)
243 new_state->other_num = state_test->num;
245 new_state->other_num = state_test->other_num;
247 if (dot_output == nullptr)
248 XBT_DEBUG("State %d already visited ! (equal to state %d)",
249 new_state->num, state_test->num);
252 "State %d already visited ! (equal to state %d (state %d in dot_output))",
253 new_state->num, state_test->num, new_state->other_num);
255 /* Replace the old state with the new one (with a bigger num)
256 (when the max number of visited states is reached, the oldest
257 one is removed according to its number (= with the min number) */
258 xbt_dynar_remove_at(visited_states, cursor, nullptr);
259 xbt_dynar_insert_at(visited_states, cursor, &new_state);
260 XBT_DEBUG("Replace visited state %d with the new visited state %d",
261 state_test->num, new_state->num);
265 bool some_dommunications_are_not_finished()
267 for (size_t current_process = 1; current_process < MC_smx_get_maxpid(); current_process++) {
268 xbt_dynar_t pattern = xbt_dynar_get_as(
269 incomplete_communications_pattern, current_process, xbt_dynar_t);
270 if (!xbt_dynar_is_empty(pattern)) {
271 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.
282 mc_visited_state_t is_visited_state(mc_state_t graph_state)
284 if (_sg_mc_visited == 0)
287 /* If comm determinism verification, we cannot stop the exploration if some
288 communications are not finished (at least, data are transfered). These communications
289 are incomplete and they cannot be analyzed and compared with the initial pattern. */
290 int partial_comm = (_sg_mc_comms_determinism || _sg_mc_send_determinism) &&
291 some_dommunications_are_not_finished();
293 mc_visited_state_t new_state = visited_state_new();
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 (xbt_dynar_is_empty(visited_states)) {
299 xbt_dynar_push(visited_states, &new_state);
303 int min = -1, max = -1, index;
305 index = get_search_interval(visited_states, new_state, &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 mc_visited_state_t state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor, mc_visited_state_t);
315 if (snapshot_compare(state_test, new_state) == 0) {
316 // The state has been visited:
318 replace_state(state_test, new_state, cursor);
325 xbt_dynar_insert_at(visited_states, min, &new_state);
326 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
330 // The state has not been visited: insert the state in the dynamic array.
331 mc_visited_state_t state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, index, mc_visited_state_t);
332 if (state_test->nb_processes < new_state->nb_processes)
333 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
334 else if (state_test->heap_bytes_used < new_state->heap_bytes_used)
335 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
337 xbt_dynar_insert_at(visited_states, index, &new_state);
339 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
343 if ((ssize_t) xbt_dynar_length(visited_states) <= _sg_mc_visited)
346 // We have reached the maximum number of stored states;
348 XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)");
350 // Find the (index of the) older state (with the smallest num):
351 int min2 = mc_stats->expanded_states;
352 unsigned int cursor2 = 0;
353 unsigned int index2 = 0;
355 mc_visited_state_t state_test;
356 xbt_dynar_foreach(visited_states, cursor2, state_test)
357 if (!mc_model_checker->is_important_snapshot(*state_test->system_state)
358 && state_test->num < min2) {
360 min2 = state_test->num;
364 xbt_dynar_remove_at(visited_states, index2, nullptr);
365 XBT_DEBUG("Remove visited state (maximum number of stored states reached)");
374 * \brief Checks whether a given pair has already been visited by the algorithm.
376 int is_visited_pair(simgrid::mc::VisitedPair* visited_pair, simgrid::mc::Pair* pair) {
378 if (_sg_mc_visited == 0)
381 simgrid::mc::VisitedPair* new_visited_pair = nullptr;
382 if (visited_pair == nullptr)
383 new_visited_pair = simgrid::mc::visited_pair_new(
384 pair->num, pair->automaton_state, pair->atomic_propositions.get(),
387 new_visited_pair = visited_pair;
389 if (xbt_dynar_is_empty(visited_pairs)) {
390 xbt_dynar_push(visited_pairs, &new_visited_pair);
394 int min = -1, max = -1, index;
396 simgrid::mc::VisitedPair* pair_test;
399 index = get_search_interval(visited_pairs, new_visited_pair, &min, &max);
401 if (min != -1 && max != -1) { // Visited pair with same number of processes and same heap bytes used exists
403 while (cursor <= max) {
404 pair_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(visited_pairs, cursor, simgrid::mc::VisitedPair*);
405 if (xbt_automaton_state_compare(pair_test->automaton_state, new_visited_pair->automaton_state) == 0) {
406 if (xbt_automaton_propositional_symbols_compare_value(pair_test->atomic_propositions, new_visited_pair->atomic_propositions) == 0) {
407 if (snapshot_compare(pair_test, new_visited_pair) == 0) {
408 if (pair_test->other_num == -1)
409 new_visited_pair->other_num = pair_test->num;
411 new_visited_pair->other_num = pair_test->other_num;
412 if (dot_output == nullptr)
413 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", new_visited_pair->num, pair_test->num);
415 XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", new_visited_pair->num, pair_test->num, new_visited_pair->other_num);
416 xbt_dynar_remove_at(visited_pairs, cursor, &pair_test);
417 xbt_dynar_insert_at(visited_pairs, cursor, &new_visited_pair);
418 pair_test->visited_removed = 1;
419 if (!pair_test->acceptance_pair
420 || pair_test->acceptance_removed == 1)
421 simgrid::mc::visited_pair_delete(pair_test);
422 return new_visited_pair->other_num;
428 xbt_dynar_insert_at(visited_pairs, min, &new_visited_pair);
430 pair_test = (simgrid::mc::VisitedPair*) xbt_dynar_get_as(visited_pairs, index, simgrid::mc::VisitedPair*);
431 if (pair_test->nb_processes < new_visited_pair->nb_processes)
432 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
433 else if (pair_test->heap_bytes_used < new_visited_pair->heap_bytes_used)
434 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
436 xbt_dynar_insert_at(visited_pairs, index, &new_visited_pair);
439 if ((ssize_t) xbt_dynar_length(visited_pairs) > _sg_mc_visited) {
440 int min2 = mc_stats->expanded_pairs;
441 unsigned int cursor2 = 0;
442 unsigned int index2 = 0;
443 xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
444 if (!mc_model_checker->is_important_snapshot(*pair_test->graph_state->system_state)
445 && pair_test->num < min2) {
447 min2 = pair_test->num;
450 xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
451 pair_test->visited_removed = 1;
452 if (!pair_test->acceptance_pair || pair_test->acceptance_removed)
453 simgrid::mc::visited_pair_delete(pair_test);