1 /* Copyright (c) 2011-2014. 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. */
7 #include "mc_private.h"
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
12 "Logging specific to state equaity detection mechanisms");
14 xbt_dynar_t visited_pairs;
15 xbt_dynar_t visited_states;
17 void visited_state_free(mc_visited_state_t state)
20 MC_free_snapshot(state->system_state);
25 void visited_state_free_voidp(void *s)
27 visited_state_free((mc_visited_state_t) * (void **) s);
31 * \brief Save the current state
32 * \return Snapshot of the current state.
34 static mc_visited_state_t visited_state_new()
36 mc_visited_state_t new_state = NULL;
37 new_state = xbt_new0(s_mc_visited_state_t, 1);
38 new_state->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
39 new_state->nb_processes = xbt_swag_size(simix_global->process_list);
40 new_state->system_state = MC_take_snapshot(mc_stats->expanded_states);
41 new_state->num = mc_stats->expanded_states;
42 new_state->other_num = -1;
47 mc_visited_pair_t MC_visited_pair_new(int pair_num,
48 xbt_automaton_state_t automaton_state,
49 xbt_dynar_t atomic_propositions)
51 mc_visited_pair_t pair = NULL;
52 pair = xbt_new0(s_mc_visited_pair_t, 1);
53 pair->graph_state = MC_state_new();
54 pair->graph_state->system_state = MC_take_snapshot(pair_num);
55 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
56 pair->nb_processes = xbt_swag_size(simix_global->process_list);
57 pair->automaton_state = automaton_state;
60 pair->acceptance_removed = 0;
61 pair->visited_removed = 0;
62 pair->acceptance_pair = 0;
63 pair->atomic_propositions = xbt_dynar_new(sizeof(int), NULL);
64 unsigned int cursor = 0;
66 xbt_dynar_foreach(atomic_propositions, cursor, value)
67 xbt_dynar_push_as(pair->atomic_propositions, int, value);
71 void MC_visited_pair_delete(mc_visited_pair_t p)
73 p->automaton_state = NULL;
74 MC_state_delete(p->graph_state);
75 xbt_dynar_free(&(p->atomic_propositions));
81 * \brief Find a suitable subrange of candidate duplicates for a given state
82 * \param list dynamic array of states/pairs with candidate duplicates of the current state;
83 * \param ref current state/pair;
84 * \param min (output) index of the beginning of the the subrange
85 * \param max (output) index of the enf of the subrange
87 * Given a suitably ordered array of states/pairs, this function extracts a subrange
88 * (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
89 * This function uses only fast discriminating criterions and does not use the
90 * full state/pair comparison algorithms.
92 * The states/pairs in list MUST be ordered using a (given) weak order
93 * (based on nb_processes and heap_bytes_used).
94 * The subrange is the subrange of "equivalence" of the given state/pair.
96 int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
99 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
103 int cursor = 0, previous_cursor, next_cursor;
104 int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
108 nb_processes = ((mc_visited_state_t) ref)->nb_processes;
109 heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
110 } else if (_sg_mc_liveness) {
111 nb_processes = ((mc_visited_pair_t) ref)->nb_processes;
112 heap_bytes_used = ((mc_visited_pair_t) ref)->heap_bytes_used;
114 xbt_die("Both liveness and safety are disabled.");
118 int end = xbt_dynar_length(list) - 1;
120 while (start <= end) {
121 cursor = (start + end) / 2;
124 (mc_visited_state_t) xbt_dynar_get_as(list, cursor,
126 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
127 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
128 } else if (_sg_mc_liveness) {
130 (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
131 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
132 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
134 nb_processes_test = 0;
135 heap_bytes_used_test = 0;
136 xbt_die("Both liveness and safety are disabled.");
138 if (nb_processes_test < nb_processes) {
140 } else if (nb_processes_test > nb_processes) {
143 if (heap_bytes_used_test < heap_bytes_used) {
145 } else if (heap_bytes_used_test > heap_bytes_used) {
148 *min = *max = cursor;
149 previous_cursor = cursor - 1;
150 while (previous_cursor >= 0) {
153 (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor,
155 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
156 heap_bytes_used_test =
157 ((mc_visited_state_t) ref_test)->heap_bytes_used;
158 } else if (_sg_mc_liveness) {
160 (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor,
162 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
163 heap_bytes_used_test =
164 ((mc_visited_pair_t) ref_test)->heap_bytes_used;
166 if (nb_processes_test != nb_processes
167 || heap_bytes_used_test != heap_bytes_used)
169 *min = previous_cursor;
172 next_cursor = cursor + 1;
173 while (next_cursor < xbt_dynar_length(list)) {
176 (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor,
178 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
179 heap_bytes_used_test =
180 ((mc_visited_state_t) ref_test)->heap_bytes_used;
181 } else if (_sg_mc_liveness) {
183 (mc_visited_pair_t) xbt_dynar_get_as(list, next_cursor,
185 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
186 heap_bytes_used_test =
187 ((mc_visited_pair_t) ref_test)->heap_bytes_used;
189 if (nb_processes_test != nb_processes
190 || heap_bytes_used_test != heap_bytes_used)
210 * \brief Checks whether a given state has already been visited by the algorithm.
212 int is_visited_state()
215 if (_sg_mc_visited == 0)
218 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
222 mc_visited_state_t new_state = visited_state_new();
224 if (xbt_dynar_is_empty(visited_states)) {
226 xbt_dynar_push(visited_states, &new_state);
235 int min = -1, max = -1, index;
237 mc_visited_state_t state_test;
240 index = get_search_interval(visited_states, new_state, &min, &max);
242 if (min != -1 && max != -1) {
244 // Parallell implementation
245 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state);
247 state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t);
248 if(state_test->other_num == -1)
249 new_state->other_num = state_test->num;
251 new_state->other_num = state_test->other_num;
252 if(dot_output == NULL)
253 XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
255 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);
256 xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL);
257 xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state);
260 return new_state->other_num;
264 while (cursor <= max) {
266 (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor,
268 if (snapshot_compare(state_test, new_state) == 0) {
269 // The state has been visited:
271 if (state_test->other_num == -1)
272 new_state->other_num = state_test->num;
274 new_state->other_num = state_test->other_num;
275 if (dot_output == NULL)
276 XBT_DEBUG("State %d already visited ! (equal to state %d)",
277 new_state->num, state_test->num);
280 ("State %d already visited ! (equal to state %d (state %d in dot_output))",
281 new_state->num, state_test->num, new_state->other_num);
283 // Replace the old state with the new one (why?):
284 xbt_dynar_remove_at(visited_states, cursor, NULL);
285 xbt_dynar_insert_at(visited_states, cursor, &new_state);
289 return new_state->other_num;
294 // The state has not been visited, add it to the list:
295 xbt_dynar_insert_at(visited_states, min, &new_state);
299 // The state has not been visited: insert the state in the dynamic array.
301 (mc_visited_state_t) xbt_dynar_get_as(visited_states, index,
303 if (state_test->nb_processes < new_state->nb_processes) {
304 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
306 if (state_test->heap_bytes_used < new_state->heap_bytes_used)
307 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
309 xbt_dynar_insert_at(visited_states, index, &new_state);
314 // We have reached the maximum number of stored states;
315 if (xbt_dynar_length(visited_states) > _sg_mc_visited) {
317 // Find the (index of the) older state:
318 int min2 = mc_stats->expanded_states;
319 unsigned int cursor2 = 0;
320 unsigned int index2 = 0;
321 xbt_dynar_foreach(visited_states, cursor2, state_test){
322 if (!mc_important_snapshot(state_test->system_state) && state_test->num < min2) {
324 min2 = state_test->num;
329 xbt_dynar_remove_at(visited_states, index2, NULL);
341 * \brief Checks whether a given pair has already been visited by the algorithm.
343 int is_visited_pair(mc_visited_pair_t pair, int pair_num,
344 xbt_automaton_state_t automaton_state,
345 xbt_dynar_t atomic_propositions)
348 if (_sg_mc_visited == 0)
351 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
355 mc_visited_pair_t new_pair = NULL;
359 MC_visited_pair_new(pair_num, automaton_state, atomic_propositions);
364 if (xbt_dynar_is_empty(visited_pairs)) {
366 xbt_dynar_push(visited_pairs, &new_pair);
370 int min = -1, max = -1, index;
372 mc_visited_pair_t pair_test;
375 index = get_search_interval(visited_pairs, new_pair, &min, &max);
377 if (min != -1 && max != -1) { // Visited pair with same number of processes and same heap bytes used exists
378 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_pairs, min), (max-min)+1, pair);
380 pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, (min+res)-1, mc_pair_t);
381 if(pair_test->other_num == -1)
382 pair->other_num = pair_test->num;
384 pair->other_num = pair_test->other_num;
385 if(dot_output == NULL)
386 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", pair->num, pair_test->num);
388 XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", pair->num, pair_test->num, pair->other_num);
389 xbt_dynar_remove_at(visited_pairs, (min + res) - 1, NULL);
390 xbt_dynar_insert_at(visited_pairs, (min+res) - 1, &pair);
391 pair_test->visited_removed = 1;
392 if(pair_test->stack_removed && pair_test->visited_removed){
393 if((pair_test->automaton_state->type == 1) || (pair_test->automaton_state->type == 2)){
394 if(pair_test->acceptance_removed){
395 MC_pair_delete(pair_test);
398 MC_pair_delete(pair_test);
403 return pair->other_num;
406 while (cursor <= max) {
408 (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, cursor,
410 //if(pair_test->acceptance_pair == 0){ /* Acceptance pair have been already checked before */
411 if (xbt_automaton_state_compare
412 (pair_test->automaton_state, new_pair->automaton_state) == 0) {
413 if (xbt_automaton_propositional_symbols_compare_value
414 (pair_test->atomic_propositions,
415 new_pair->atomic_propositions) == 0) {
416 if (snapshot_compare(pair_test, new_pair) == 0) {
417 if (pair_test->other_num == -1)
418 new_pair->other_num = pair_test->num;
420 new_pair->other_num = pair_test->other_num;
421 if (dot_output == NULL)
422 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)",
423 new_pair->num, pair_test->num);
426 ("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))",
427 new_pair->num, pair_test->num, new_pair->other_num);
428 xbt_dynar_remove_at(visited_pairs, cursor, NULL);
429 xbt_dynar_insert_at(visited_pairs, cursor, &new_pair);
430 pair_test->visited_removed = 1;
431 if (pair_test->acceptance_pair) {
432 if (pair_test->acceptance_removed == 1)
433 MC_visited_pair_delete(pair_test);
435 MC_visited_pair_delete(pair_test);
439 return new_pair->other_num;
446 xbt_dynar_insert_at(visited_pairs, min, &new_pair);
449 (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, index,
451 if (pair_test->nb_processes < new_pair->nb_processes) {
452 xbt_dynar_insert_at(visited_pairs, index + 1, &new_pair);
454 if (pair_test->heap_bytes_used < new_pair->heap_bytes_used)
455 xbt_dynar_insert_at(visited_pairs, index + 1, &new_pair);
457 xbt_dynar_insert_at(visited_pairs, index, &new_pair);
461 if (xbt_dynar_length(visited_pairs) > _sg_mc_visited) {
462 int min2 = mc_stats->expanded_pairs;
463 unsigned int cursor2 = 0;
464 unsigned int index2 = 0;
465 xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
466 if (!mc_important_snapshot(pair_test->graph_state->system_state) && pair_test->num < min2) {
468 min2 = pair_test->num;
471 xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
472 pair_test->visited_removed = 1;
473 if (pair_test->acceptance_pair) {
474 if (pair_test->acceptance_removed)
475 MC_visited_pair_delete(pair_test);
477 MC_visited_pair_delete(pair_test);