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. */
10 #include "mc_comm_pattern.h"
11 #include "mc_safety.h"
12 #include "mc_liveness.h"
13 #include "mc_private.h"
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
16 "Logging specific to state equaity detection mechanisms");
18 xbt_dynar_t visited_pairs;
19 xbt_dynar_t visited_states;
21 void visited_state_free(mc_visited_state_t state)
24 MC_free_snapshot(state->system_state);
29 void visited_state_free_voidp(void *s)
31 visited_state_free((mc_visited_state_t) * (void **) s);
35 * \brief Save the current state
36 * \return Snapshot of the current state.
38 static mc_visited_state_t visited_state_new()
40 mc_visited_state_t new_state = NULL;
41 new_state = xbt_new0(s_mc_visited_state_t, 1);
42 new_state->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
43 new_state->nb_processes = xbt_swag_size(simix_global->process_list);
44 new_state->system_state = MC_take_snapshot(mc_stats->expanded_states);
45 new_state->num = mc_stats->expanded_states;
46 new_state->other_num = -1;
51 mc_visited_pair_t MC_visited_pair_new(int pair_num,
52 xbt_automaton_state_t automaton_state,
53 xbt_dynar_t atomic_propositions)
55 mc_visited_pair_t pair = NULL;
56 pair = xbt_new0(s_mc_visited_pair_t, 1);
57 pair->graph_state = MC_state_new();
58 pair->graph_state->system_state = MC_take_snapshot(pair_num);
59 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
60 pair->nb_processes = xbt_swag_size(simix_global->process_list);
61 pair->automaton_state = automaton_state;
64 pair->acceptance_removed = 0;
65 pair->visited_removed = 0;
66 pair->acceptance_pair = 0;
67 pair->atomic_propositions = xbt_dynar_new(sizeof(int), NULL);
68 unsigned int cursor = 0;
70 xbt_dynar_foreach(atomic_propositions, cursor, value)
71 xbt_dynar_push_as(pair->atomic_propositions, int, value);
75 void MC_visited_pair_delete(mc_visited_pair_t p)
77 p->automaton_state = NULL;
78 MC_state_delete(p->graph_state);
79 xbt_dynar_free(&(p->atomic_propositions));
85 * \brief Find a suitable subrange of candidate duplicates for a given state
86 * \param list dynamic array of states/pairs with candidate duplicates of the current state;
87 * \param ref current state/pair;
88 * \param min (output) index of the beginning of the the subrange
89 * \param max (output) index of the enf of the subrange
91 * Given a suitably ordered array of states/pairs, this function extracts a subrange
92 * (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
93 * This function uses only fast discriminating criterions and does not use the
94 * full state/pair comparison algorithms.
96 * The states/pairs in list MUST be ordered using a (given) weak order
97 * (based on nb_processes and heap_bytes_used).
98 * The subrange is the subrange of "equivalence" of the given state/pair.
100 int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
103 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
107 int cursor = 0, previous_cursor, next_cursor;
108 int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
111 if (_sg_mc_liveness) {
112 nb_processes = ((mc_visited_pair_t) ref)->nb_processes;
113 heap_bytes_used = ((mc_visited_pair_t) ref)->heap_bytes_used;
115 nb_processes = ((mc_visited_state_t) ref)->nb_processes;
116 heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
120 int end = xbt_dynar_length(list) - 1;
122 while (start <= end) {
123 cursor = (start + end) / 2;
124 if (_sg_mc_liveness) {
126 (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
127 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
128 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
131 (mc_visited_state_t) xbt_dynar_get_as(list, cursor,
133 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
134 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
136 if (nb_processes_test < nb_processes) {
138 } else if (nb_processes_test > nb_processes) {
141 if (heap_bytes_used_test < heap_bytes_used) {
143 } else if (heap_bytes_used_test > heap_bytes_used) {
146 *min = *max = cursor;
147 previous_cursor = cursor - 1;
148 while (previous_cursor >= 0) {
149 if (_sg_mc_liveness) {
151 (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor,
153 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
154 heap_bytes_used_test =
155 ((mc_visited_pair_t) ref_test)->heap_bytes_used;
158 (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor,
160 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
161 heap_bytes_used_test =
162 ((mc_visited_state_t) ref_test)->heap_bytes_used;
164 if (nb_processes_test != nb_processes
165 || heap_bytes_used_test != heap_bytes_used)
167 *min = previous_cursor;
170 next_cursor = cursor + 1;
171 while (next_cursor < xbt_dynar_length(list)) {
172 if (_sg_mc_liveness) {
174 (mc_visited_pair_t) xbt_dynar_get_as(list, next_cursor,
176 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
177 heap_bytes_used_test =
178 ((mc_visited_pair_t) ref_test)->heap_bytes_used;
181 (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor,
183 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
184 heap_bytes_used_test =
185 ((mc_visited_state_t) ref_test)->heap_bytes_used;
187 if (nb_processes_test != nb_processes
188 || heap_bytes_used_test != heap_bytes_used)
208 * \brief Checks whether a given state has already been visited by the algorithm.
211 mc_visited_state_t is_visited_state(mc_state_t graph_state)
214 if (_sg_mc_visited == 0)
217 int partial_comm = 0;
219 /* If comm determinism verification, we cannot stop the exploration if some
220 communications are not finished (at least, data are transfered). These communications
221 are incomplete and they cannot be analyzed and compared with the initial pattern. */
222 if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
223 int current_process = 1;
224 while (current_process < simix_process_maxpid) {
225 if (!xbt_dynar_is_empty((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, current_process, xbt_dynar_t))){
226 XBT_DEBUG("Some communications are not finished, cannot stop the exploration ! State not visited.");
234 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
238 mc_visited_state_t new_state = visited_state_new();
240 if (xbt_dynar_is_empty(visited_states)) {
242 xbt_dynar_push(visited_states, &new_state);
251 int min = -1, max = -1, index;
253 mc_visited_state_t state_test;
256 index = get_search_interval(visited_states, new_state, &min, &max);
258 if (min != -1 && max != -1) {
260 // Parallell implementation
261 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state);
263 state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t);
264 if(state_test->other_num == -1)
265 new_state->other_num = state_test->num;
267 new_state->other_num = state_test->other_num;
268 if(dot_output == NULL)
269 XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
271 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);
272 xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL);
273 xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state);
276 return new_state->other_num;
280 while (cursor <= max) {
282 (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor,
284 if (snapshot_compare(state_test, new_state) == 0) {
285 // The state has been visited:
287 if (state_test->other_num == -1)
288 new_state->other_num = state_test->num;
290 new_state->other_num = state_test->other_num;
291 if (dot_output == NULL)
292 XBT_DEBUG("State %d already visited ! (equal to state %d)",
293 new_state->num, state_test->num);
296 ("State %d already visited ! (equal to state %d (state %d in dot_output))",
297 new_state->num, state_test->num, new_state->other_num);
299 /* Replace the old state with the new one (with a bigger num)
300 (when the max number of visited states is reached, the oldest
301 one is removed according to its number (= with the min number) */
302 xbt_dynar_remove_at(visited_states, cursor, NULL);
303 xbt_dynar_insert_at(visited_states, cursor, &new_state);
312 // The state has not been visited: insert the state in the dynamic array.
313 xbt_dynar_insert_at(visited_states, min, &new_state);
317 // The state has not been visited: insert the state in the dynamic array.
319 (mc_visited_state_t) xbt_dynar_get_as(visited_states, index,
321 if (state_test->nb_processes < new_state->nb_processes) {
322 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
324 if (state_test->heap_bytes_used < new_state->heap_bytes_used)
325 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
327 xbt_dynar_insert_at(visited_states, index, &new_state);
332 // We have reached the maximum number of stored states;
333 if (xbt_dynar_length(visited_states) > _sg_mc_visited) {
335 // Find the (index of the) older state (with the smallest num):
336 int min2 = mc_stats->expanded_states;
337 unsigned int cursor2 = 0;
338 unsigned int index2 = 0;
339 xbt_dynar_foreach(visited_states, cursor2, state_test){
340 if (!mc_important_snapshot(state_test->system_state) && state_test->num < min2) {
342 min2 = state_test->num;
347 xbt_dynar_remove_at(visited_states, index2, NULL);
359 * \brief Checks whether a given pair has already been visited by the algorithm.
361 int is_visited_pair(mc_visited_pair_t pair, int pair_num,
362 xbt_automaton_state_t automaton_state,
363 xbt_dynar_t atomic_propositions)
366 if (_sg_mc_visited == 0)
369 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
373 mc_visited_pair_t new_pair = NULL;
377 MC_visited_pair_new(pair_num, automaton_state, atomic_propositions);
382 if (xbt_dynar_is_empty(visited_pairs)) {
384 xbt_dynar_push(visited_pairs, &new_pair);
388 int min = -1, max = -1, index;
390 mc_visited_pair_t pair_test;
393 index = get_search_interval(visited_pairs, new_pair, &min, &max);
395 if (min != -1 && max != -1) { // Visited pair with same number of processes and same heap bytes used exists
396 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_pairs, min), (max-min)+1, pair);
398 pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, (min+res)-1, mc_pair_t);
399 if(pair_test->other_num == -1)
400 pair->other_num = pair_test->num;
402 pair->other_num = pair_test->other_num;
403 if(dot_output == NULL)
404 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", pair->num, pair_test->num);
406 XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", pair->num, pair_test->num, pair->other_num);
407 xbt_dynar_remove_at(visited_pairs, (min + res) - 1, NULL);
408 xbt_dynar_insert_at(visited_pairs, (min+res) - 1, &pair);
409 pair_test->visited_removed = 1;
410 if(pair_test->stack_removed && pair_test->visited_removed){
411 if((pair_test->automaton_state->type == 1) || (pair_test->automaton_state->type == 2)){
412 if(pair_test->acceptance_removed){
413 MC_pair_delete(pair_test);
416 MC_pair_delete(pair_test);
421 return pair->other_num;
424 while (cursor <= max) {
426 (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, cursor,
428 if (xbt_automaton_state_compare
429 (pair_test->automaton_state, new_pair->automaton_state) == 0) {
430 if (xbt_automaton_propositional_symbols_compare_value
431 (pair_test->atomic_propositions,
432 new_pair->atomic_propositions) == 0) {
433 if (snapshot_compare(pair_test, new_pair) == 0) {
434 if (pair_test->other_num == -1)
435 new_pair->other_num = pair_test->num;
437 new_pair->other_num = pair_test->other_num;
438 if (dot_output == NULL)
439 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)",
440 new_pair->num, pair_test->num);
443 ("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))",
444 new_pair->num, pair_test->num, new_pair->other_num);
445 xbt_dynar_remove_at(visited_pairs, cursor, NULL);
446 xbt_dynar_insert_at(visited_pairs, cursor, &new_pair);
447 pair_test->visited_removed = 1;
448 if (pair_test->acceptance_pair) {
449 if (pair_test->acceptance_removed == 1)
450 MC_visited_pair_delete(pair_test);
452 MC_visited_pair_delete(pair_test);
456 return new_pair->other_num;
462 xbt_dynar_insert_at(visited_pairs, min, &new_pair);
465 (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, index,
467 if (pair_test->nb_processes < new_pair->nb_processes) {
468 xbt_dynar_insert_at(visited_pairs, index + 1, &new_pair);
470 if (pair_test->heap_bytes_used < new_pair->heap_bytes_used)
471 xbt_dynar_insert_at(visited_pairs, index + 1, &new_pair);
473 xbt_dynar_insert_at(visited_pairs, index, &new_pair);
477 if (xbt_dynar_length(visited_pairs) > _sg_mc_visited) {
478 int min2 = mc_stats->expanded_pairs;
479 unsigned int cursor2 = 0;
480 unsigned int index2 = 0;
481 xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
482 if (!mc_important_snapshot(pair_test->graph_state->system_state) && pair_test->num < min2) {
484 min2 = pair_test->num;
487 xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
488 pair_test->visited_removed = 1;
489 if (pair_test->acceptance_pair) {
490 if (pair_test->acceptance_removed)
491 MC_visited_pair_delete(pair_test);
493 MC_visited_pair_delete(pair_test);