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 "mc_comm_pattern.h"
11 #include "mc_safety.h"
12 #include "mc_liveness.h"
13 #include "mc_private.h"
14 #include "mc/Process.hpp"
19 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
20 "Logging specific to state equaity detection mechanisms");
22 xbt_dynar_t visited_pairs;
23 xbt_dynar_t visited_states;
25 static int is_exploration_stack_state(mc_visited_state_t state){
26 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
28 if (((mc_state_t)xbt_fifo_get_item_content(item))->num == state->num){
29 ((mc_state_t)xbt_fifo_get_item_content(item))->in_visited_states = 0;
32 item = xbt_fifo_get_next_item(item);
37 void visited_state_free(mc_visited_state_t state)
40 if(!is_exploration_stack_state(state))
41 delete state->system_state;
46 void visited_state_free_voidp(void *s)
48 visited_state_free((mc_visited_state_t) * (void **) s);
52 * \brief Save the current state
53 * \return Snapshot of the current state.
55 static mc_visited_state_t visited_state_new()
57 simgrid::mc::Process* process = &(mc_model_checker->process());
58 mc_visited_state_t new_state = xbt_new0(s_mc_visited_state_t, 1);
59 new_state->heap_bytes_used = mmalloc_get_bytes_used_remote(
60 process->get_heap()->heaplimit,
61 process->get_malloc_info());
63 MC_process_smx_refresh(&mc_model_checker->process());
64 new_state->nb_processes = xbt_dynar_length(
65 mc_model_checker->process().smx_process_infos);
67 new_state->system_state = MC_take_snapshot(mc_stats->expanded_states);
68 new_state->num = mc_stats->expanded_states;
69 new_state->other_num = -1;
73 mc_visited_pair_t MC_visited_pair_new(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state)
75 simgrid::mc::Process* process = &(mc_model_checker->process());
76 mc_visited_pair_t pair = NULL;
77 pair = xbt_new0(s_mc_visited_pair_t, 1);
78 pair->graph_state = graph_state;
79 if(pair->graph_state->system_state == NULL)
80 pair->graph_state->system_state = MC_take_snapshot(pair_num);
81 pair->heap_bytes_used = mmalloc_get_bytes_used_remote(
82 process->get_heap()->heaplimit,
83 process->get_malloc_info());
85 MC_process_smx_refresh(&mc_model_checker->process());
86 pair->nb_processes = xbt_dynar_length(
87 mc_model_checker->process().smx_process_infos);
89 pair->automaton_state = automaton_state;
92 pair->acceptance_removed = 0;
93 pair->visited_removed = 0;
94 pair->acceptance_pair = 0;
95 pair->atomic_propositions = xbt_dynar_new(sizeof(int), NULL);
96 unsigned int cursor = 0;
98 xbt_dynar_foreach(atomic_propositions, cursor, value)
99 xbt_dynar_push_as(pair->atomic_propositions, int, value);
103 static int is_exploration_stack_pair(mc_visited_pair_t pair){
104 xbt_fifo_item_t item = xbt_fifo_get_first_item(mc_stack);
106 if (((mc_pair_t)xbt_fifo_get_item_content(item))->num == pair->num){
107 ((mc_pair_t)xbt_fifo_get_item_content(item))->visited_pair_removed = 1;
110 item = xbt_fifo_get_next_item(item);
115 void MC_visited_pair_delete(mc_visited_pair_t p)
117 p->automaton_state = NULL;
118 if( !is_exploration_stack_pair(p))
119 MC_state_delete(p->graph_state, 1);
120 xbt_dynar_free(&(p->atomic_propositions));
126 * \brief Find a suitable subrange of candidate duplicates for a given state
127 * \param list dynamic array of states/pairs with candidate duplicates of the current state;
128 * \param ref current state/pair;
129 * \param min (output) index of the beginning of the the subrange
130 * \param max (output) index of the enf of the subrange
132 * Given a suitably ordered array of states/pairs, this function extracts a subrange
133 * (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
134 * This function uses only fast discriminating criterions and does not use the
135 * full state/pair comparison algorithms.
137 * The states/pairs in list MUST be ordered using a (given) weak order
138 * (based on nb_processes and heap_bytes_used).
139 * The subrange is the subrange of "equivalence" of the given state/pair.
141 int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
143 int cursor = 0, previous_cursor;
144 int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
147 if (_sg_mc_liveness) {
148 nb_processes = ((mc_visited_pair_t) ref)->nb_processes;
149 heap_bytes_used = ((mc_visited_pair_t) ref)->heap_bytes_used;
151 nb_processes = ((mc_visited_state_t) ref)->nb_processes;
152 heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
156 int end = xbt_dynar_length(list) - 1;
158 while (start <= end) {
159 cursor = (start + end) / 2;
160 if (_sg_mc_liveness) {
161 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
162 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
163 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
165 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, cursor, mc_visited_state_t);
166 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
167 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
169 if (nb_processes_test < nb_processes) {
171 } else if (nb_processes_test > nb_processes) {
174 if (heap_bytes_used_test < heap_bytes_used) {
176 } else if (heap_bytes_used_test > heap_bytes_used) {
179 *min = *max = cursor;
180 previous_cursor = cursor - 1;
181 while (previous_cursor >= 0) {
182 if (_sg_mc_liveness) {
183 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor, mc_visited_pair_t);
184 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
185 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
187 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor, mc_visited_state_t);
188 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
189 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
191 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
193 *min = previous_cursor;
196 size_t next_cursor = cursor + 1;
197 while (next_cursor < xbt_dynar_length(list)) {
198 if (_sg_mc_liveness) {
199 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, next_cursor, mc_visited_pair_t);
200 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
201 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
203 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor, mc_visited_state_t);
204 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
205 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
207 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
221 mc_visited_state_t state_test, mc_visited_state_t new_state, int cursor)
223 if (state_test->other_num == -1)
224 new_state->other_num = state_test->num;
226 new_state->other_num = state_test->other_num;
228 if (dot_output == NULL)
229 XBT_DEBUG("State %d already visited ! (equal to state %d)",
230 new_state->num, state_test->num);
233 "State %d already visited ! (equal to state %d (state %d in dot_output))",
234 new_state->num, state_test->num, new_state->other_num);
236 /* Replace the old state with the new one (with a bigger num)
237 (when the max number of visited states is reached, the oldest
238 one is removed according to its number (= with the min number) */
239 xbt_dynar_remove_at(visited_states, cursor, NULL);
240 xbt_dynar_insert_at(visited_states, cursor, &new_state);
241 XBT_DEBUG("Replace visited state %d with the new visited state %d",
242 state_test->num, new_state->num);
246 * \brief Checks whether a given state has already been visited by the algorithm.
249 mc_visited_state_t is_visited_state(mc_state_t graph_state)
252 if (_sg_mc_visited == 0)
255 /* If comm determinism verification, we cannot stop the exploration if some
256 communications are not finished (at least, data are transfered). These communications
257 are incomplete and they cannot be analyzed and compared with the initial pattern. */
258 int partial_comm = 0;
259 if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
260 for (size_t current_process = 1; current_process < MC_smx_get_maxpid(); current_process++) {
261 if (!xbt_dynar_is_empty((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, current_process, xbt_dynar_t))){
262 XBT_DEBUG("Some communications are not finished, cannot stop the exploration ! State not visited.");
269 mc_visited_state_t new_state = visited_state_new();
270 graph_state->system_state = new_state->system_state;
271 graph_state->in_visited_states = 1;
272 XBT_DEBUG("Snapshot %p of visited state %d (exploration stack state %d)", new_state->system_state, new_state->num, graph_state->num);
274 if (xbt_dynar_is_empty(visited_states)) {
276 xbt_dynar_push(visited_states, &new_state);
281 int min = -1, max = -1, index;
283 index = get_search_interval(visited_states, new_state, &min, &max);
285 if (min != -1 && max != -1) {
287 // Parallell implementation
288 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state);
290 mc_visited_state_t state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t);
291 if(state_test->other_num == -1)
292 new_state->other_num = state_test->num;
294 new_state->other_num = state_test->other_num;
295 if(dot_output == NULL)
296 XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
298 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);
299 xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL);
300 xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state);
301 return new_state->other_num;
304 if (_sg_mc_safety || (!partial_comm
305 && initial_global_state->initial_communications_pattern_done)) {
308 while (cursor <= max) {
309 mc_visited_state_t state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor, mc_visited_state_t);
310 if (snapshot_compare(state_test, new_state) == 0) {
311 // The state has been visited:
313 replace_state(state_test, new_state, cursor);
320 xbt_dynar_insert_at(visited_states, min, &new_state);
321 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
325 // The state has not been visited: insert the state in the dynamic array.
326 mc_visited_state_t state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, index, mc_visited_state_t);
327 if (state_test->nb_processes < new_state->nb_processes) {
328 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
330 if (state_test->heap_bytes_used < new_state->heap_bytes_used)
331 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
333 xbt_dynar_insert_at(visited_states, index, &new_state);
336 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
340 // We have reached the maximum number of stored states;
341 if ((ssize_t) xbt_dynar_length(visited_states) > _sg_mc_visited) {
343 XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)");
345 // Find the (index of the) older state (with the smallest num):
346 int min2 = mc_stats->expanded_states;
347 unsigned int cursor2 = 0;
348 unsigned int index2 = 0;
350 mc_visited_state_t state_test;
351 xbt_dynar_foreach(visited_states, cursor2, state_test){
352 if (!MC_important_snapshot(state_test->system_state) && state_test->num < min2) {
354 min2 = state_test->num;
359 xbt_dynar_remove_at(visited_states, index2, NULL);
360 XBT_DEBUG("Remove visited state (maximum number of stored states reached)");
368 * \brief Checks whether a given pair has already been visited by the algorithm.
370 int is_visited_pair(mc_visited_pair_t visited_pair, mc_pair_t pair) {
372 if (_sg_mc_visited == 0)
375 mc_visited_pair_t new_visited_pair = NULL;
377 if (visited_pair == NULL) {
378 new_visited_pair = MC_visited_pair_new(pair->num, pair->automaton_state, pair->atomic_propositions, pair->graph_state);
380 new_visited_pair = visited_pair;
383 if (xbt_dynar_is_empty(visited_pairs)) {
385 xbt_dynar_push(visited_pairs, &new_visited_pair);
389 int min = -1, max = -1, index;
391 mc_visited_pair_t pair_test;
394 index = get_search_interval(visited_pairs, new_visited_pair, &min, &max);
396 if (min != -1 && max != -1) { // Visited pair with same number of processes and same heap bytes used exists
397 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_pairs, min), (max-min)+1, pair);
399 pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, (min+res)-1, mc_pair_t);
400 if(pair_test->other_num == -1)
401 pair->other_num = pair_test->num;
403 pair->other_num = pair_test->other_num;
404 if(dot_output == NULL)
405 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", pair->num, pair_test->num);
407 XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", pair->num, pair_test->num, pair->other_num);
408 xbt_dynar_remove_at(visited_pairs, (min + res) - 1, NULL);
409 xbt_dynar_insert_at(visited_pairs, (min+res) - 1, &pair);
410 pair_test->visited_removed = 1;
411 if(pair_test->stack_removed && pair_test->visited_removed){
412 if((pair_test->automaton_state->type == 1) || (pair_test->automaton_state->type == 2)){
413 if(pair_test->acceptance_removed){
414 MC_pair_delete(pair_test);
417 MC_pair_delete(pair_test);
420 return pair->other_num;
423 while (cursor <= max) {
424 pair_test = (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, cursor, mc_visited_pair_t);
425 if (xbt_automaton_state_compare(pair_test->automaton_state, new_visited_pair->automaton_state) == 0) {
426 if (xbt_automaton_propositional_symbols_compare_value(pair_test->atomic_propositions, new_visited_pair->atomic_propositions) == 0) {
427 if (snapshot_compare(pair_test, new_visited_pair) == 0) {
428 if (pair_test->other_num == -1)
429 new_visited_pair->other_num = pair_test->num;
431 new_visited_pair->other_num = pair_test->other_num;
432 if (dot_output == NULL)
433 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", new_visited_pair->num, pair_test->num);
435 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);
436 xbt_dynar_remove_at(visited_pairs, cursor, &pair_test);
437 xbt_dynar_insert_at(visited_pairs, cursor, &new_visited_pair);
438 pair_test->visited_removed = 1;
439 if (pair_test->acceptance_pair) {
440 if (pair_test->acceptance_removed == 1)
441 MC_visited_pair_delete(pair_test);
443 MC_visited_pair_delete(pair_test);
445 return new_visited_pair->other_num;
451 xbt_dynar_insert_at(visited_pairs, min, &new_visited_pair);
453 pair_test = (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, index, mc_visited_pair_t);
454 if (pair_test->nb_processes < new_visited_pair->nb_processes) {
455 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
457 if (pair_test->heap_bytes_used < new_visited_pair->heap_bytes_used)
458 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
460 xbt_dynar_insert_at(visited_pairs, index, &new_visited_pair);
464 if ((ssize_t) xbt_dynar_length(visited_pairs) > _sg_mc_visited) {
465 int min2 = mc_stats->expanded_pairs;
466 unsigned int cursor2 = 0;
467 unsigned int index2 = 0;
468 xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
469 if (!MC_important_snapshot(pair_test->graph_state->system_state)
470 && pair_test->num < min2) {
472 min2 = pair_test->num;
475 xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
476 pair_test->visited_removed = 1;
477 if (pair_test->acceptance_pair) {
478 if (pair_test->acceptance_removed)
479 MC_visited_pair_delete(pair_test);
481 MC_visited_pair_delete(pair_test);