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 static int is_exploration_stack_state(mc_visited_state_t state){
22 xbt_fifo_item_t item = xbt_fifo_get_last_item(mc_stack);
24 if (((mc_state_t)xbt_fifo_get_item_content(item))->num == state->num){
25 ((mc_state_t)xbt_fifo_get_item_content(item))->in_visited_states = 0;
28 item = xbt_fifo_get_prev_item(item);
33 void visited_state_free(mc_visited_state_t state)
36 if(!is_exploration_stack_state(state)){
37 MC_free_snapshot(state->system_state);
43 void visited_state_free_voidp(void *s)
45 visited_state_free((mc_visited_state_t) * (void **) s);
49 * \brief Save the current state
50 * \return Snapshot of the current state.
52 static mc_visited_state_t visited_state_new()
54 mc_visited_state_t new_state = NULL;
55 new_state = xbt_new0(s_mc_visited_state_t, 1);
56 new_state->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
57 new_state->nb_processes = xbt_swag_size(simix_global->process_list);
58 new_state->system_state = MC_take_snapshot(mc_stats->expanded_states);
59 new_state->num = mc_stats->expanded_states;
60 new_state->other_num = -1;
64 mc_visited_pair_t MC_visited_pair_new(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_snapshot_t system_state)
66 mc_visited_pair_t pair = NULL;
67 pair = xbt_new0(s_mc_visited_pair_t, 1);
68 pair->graph_state = MC_state_new();
69 pair->graph_state->system_state = (system_state == NULL) ? MC_take_snapshot(pair_num) : system_state;
70 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
71 pair->nb_processes = xbt_swag_size(simix_global->process_list);
72 pair->automaton_state = automaton_state;
75 pair->acceptance_removed = 0;
76 pair->visited_removed = 0;
77 pair->acceptance_pair = 0;
78 pair->in_exploration_stack = 1;
79 pair->atomic_propositions = xbt_dynar_new(sizeof(int), NULL);
80 unsigned int cursor = 0;
82 xbt_dynar_foreach(atomic_propositions, cursor, value)
83 xbt_dynar_push_as(pair->atomic_propositions, int, value);
87 static int is_exploration_stack_pair(mc_visited_pair_t pair){
88 xbt_fifo_item_t item = xbt_fifo_get_last_item(mc_stack);
90 if (((mc_pair_t)xbt_fifo_get_item_content(item))->num == pair->num){
91 ((mc_pair_t)xbt_fifo_get_item_content(item))->visited_pair_removed = 1;
94 item = xbt_fifo_get_prev_item(item);
99 void MC_visited_pair_delete(mc_visited_pair_t p)
101 p->automaton_state = NULL;
102 MC_state_delete(p->graph_state, !is_exploration_stack_pair(p));
103 xbt_dynar_free(&(p->atomic_propositions));
109 * \brief Find a suitable subrange of candidate duplicates for a given state
110 * \param list dynamic array of states/pairs with candidate duplicates of the current state;
111 * \param ref current state/pair;
112 * \param min (output) index of the beginning of the the subrange
113 * \param max (output) index of the enf of the subrange
115 * Given a suitably ordered array of states/pairs, this function extracts a subrange
116 * (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
117 * This function uses only fast discriminating criterions and does not use the
118 * full state/pair comparison algorithms.
120 * The states/pairs in list MUST be ordered using a (given) weak order
121 * (based on nb_processes and heap_bytes_used).
122 * The subrange is the subrange of "equivalence" of the given state/pair.
124 int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
127 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
131 int cursor = 0, previous_cursor, next_cursor;
132 int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
135 if (_sg_mc_liveness) {
136 nb_processes = ((mc_visited_pair_t) ref)->nb_processes;
137 heap_bytes_used = ((mc_visited_pair_t) ref)->heap_bytes_used;
139 nb_processes = ((mc_visited_state_t) ref)->nb_processes;
140 heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
144 int end = xbt_dynar_length(list) - 1;
146 while (start <= end) {
147 cursor = (start + end) / 2;
148 if (_sg_mc_liveness) {
149 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
150 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
151 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
153 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, cursor, mc_visited_state_t);
154 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
155 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
157 if (nb_processes_test < nb_processes) {
159 } else if (nb_processes_test > nb_processes) {
162 if (heap_bytes_used_test < heap_bytes_used) {
164 } else if (heap_bytes_used_test > heap_bytes_used) {
167 *min = *max = cursor;
168 previous_cursor = cursor - 1;
169 while (previous_cursor >= 0) {
170 if (_sg_mc_liveness) {
171 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor, mc_visited_pair_t);
172 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
173 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
175 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor, mc_visited_state_t);
176 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
177 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
179 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
181 *min = previous_cursor;
184 next_cursor = cursor + 1;
185 while (next_cursor < xbt_dynar_length(list)) {
186 if (_sg_mc_liveness) {
187 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, next_cursor, mc_visited_pair_t);
188 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
189 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
191 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor, mc_visited_state_t);
192 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
193 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
195 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
215 * \brief Checks whether a given state has already been visited by the algorithm.
218 mc_visited_state_t is_visited_state(mc_state_t graph_state)
221 if (_sg_mc_visited == 0)
224 int partial_comm = 0;
226 /* If comm determinism verification, we cannot stop the exploration if some
227 communications are not finished (at least, data are transfered). These communications
228 are incomplete and they cannot be analyzed and compared with the initial pattern. */
229 if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
230 int current_process = 1;
231 while (current_process < simix_process_maxpid) {
232 if (!xbt_dynar_is_empty((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, current_process, xbt_dynar_t))){
233 XBT_DEBUG("Some communications are not finished, cannot stop the exploration ! State not visited.");
241 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
245 mc_visited_state_t new_state = visited_state_new();
246 graph_state->system_state = new_state->system_state;
247 graph_state->in_visited_states = 1;
248 XBT_DEBUG("Snapshot %p of visited state %d (exploration stack state %d)", new_state->system_state, new_state->num, graph_state->num);
250 if (xbt_dynar_is_empty(visited_states)) {
252 xbt_dynar_push(visited_states, &new_state);
261 int min = -1, max = -1, index;
263 mc_visited_state_t state_test;
266 index = get_search_interval(visited_states, new_state, &min, &max);
268 if (min != -1 && max != -1) {
270 // Parallell implementation
271 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state);
273 state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t);
274 if(state_test->other_num == -1)
275 new_state->other_num = state_test->num;
277 new_state->other_num = state_test->other_num;
278 if(dot_output == NULL)
279 XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
281 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);
282 xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL);
283 xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state);
286 return new_state->other_num;
289 if(!partial_comm && initial_global_state->initial_communications_pattern_done){
292 while (cursor <= max) {
293 state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor, mc_visited_state_t);
294 if (snapshot_compare(state_test, new_state) == 0) {
295 // The state has been visited:
297 if (state_test->other_num == -1)
298 new_state->other_num = state_test->num;
300 new_state->other_num = state_test->other_num;
301 if (dot_output == NULL)
302 XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
304 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);
306 /* Replace the old state with the new one (with a bigger num)
307 (when the max number of visited states is reached, the oldest
308 one is removed according to its number (= with the min number) */
309 xbt_dynar_remove_at(visited_states, cursor, NULL);
310 xbt_dynar_insert_at(visited_states, cursor, &new_state);
311 XBT_DEBUG("Replace visited state %d with the new visited state %d", state_test->num, new_state->num);
321 xbt_dynar_insert_at(visited_states, min, &new_state);
322 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
326 // The state has not been visited: insert the state in the dynamic array.
327 state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, index, mc_visited_state_t);
328 if (state_test->nb_processes < new_state->nb_processes) {
329 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
331 if (state_test->heap_bytes_used < new_state->heap_bytes_used)
332 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
334 xbt_dynar_insert_at(visited_states, index, &new_state);
337 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
341 // We have reached the maximum number of stored states;
342 if (xbt_dynar_length(visited_states) > _sg_mc_visited) {
344 XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)");
346 // Find the (index of the) older state (with the smallest num):
347 int min2 = mc_stats->expanded_states;
348 unsigned int cursor2 = 0;
349 unsigned int index2 = 0;
350 xbt_dynar_foreach(visited_states, cursor2, state_test){
351 if (!mc_important_snapshot(state_test->system_state) && state_test->num < min2) {
353 min2 = state_test->num;
358 xbt_dynar_remove_at(visited_states, index2, NULL);
359 XBT_DEBUG("Remove visited state (maximum number of stored states reached)");
371 * \brief Checks whether a given pair has already been visited by the algorithm.
373 int is_visited_pair(mc_visited_pair_t visited_pair, mc_pair_t pair) {
375 if (_sg_mc_visited == 0)
378 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
382 mc_visited_pair_t new_visited_pair = NULL;
384 if (visited_pair == NULL) {
385 new_visited_pair = MC_visited_pair_new(pair->num, pair->automaton_state, pair->atomic_propositions, pair->graph_state->system_state);
387 new_visited_pair = visited_pair;
390 if (xbt_dynar_is_empty(visited_pairs)) {
392 xbt_dynar_push(visited_pairs, &new_visited_pair);
396 int min = -1, max = -1, index;
398 mc_visited_pair_t pair_test;
401 index = get_search_interval(visited_pairs, new_visited_pair, &min, &max);
403 if (min != -1 && max != -1) { // Visited pair with same number of processes and same heap bytes used exists
404 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_pairs, min), (max-min)+1, pair);
406 pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, (min+res)-1, mc_pair_t);
407 if(pair_test->other_num == -1)
408 pair->other_num = pair_test->num;
410 pair->other_num = pair_test->other_num;
411 if(dot_output == NULL)
412 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", pair->num, pair_test->num);
414 XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", pair->num, pair_test->num, pair->other_num);
415 xbt_dynar_remove_at(visited_pairs, (min + res) - 1, NULL);
416 xbt_dynar_insert_at(visited_pairs, (min+res) - 1, &pair);
417 pair_test->visited_removed = 1;
418 if(pair_test->stack_removed && pair_test->visited_removed){
419 if((pair_test->automaton_state->type == 1) || (pair_test->automaton_state->type == 2)){
420 if(pair_test->acceptance_removed){
421 MC_pair_delete(pair_test);
424 MC_pair_delete(pair_test);
429 return pair->other_num;
432 while (cursor <= max) {
433 pair_test = (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, cursor, mc_visited_pair_t);
434 if (xbt_automaton_state_compare(pair_test->automaton_state, new_visited_pair->automaton_state) == 0) {
435 if (xbt_automaton_propositional_symbols_compare_value(pair_test->atomic_propositions, new_visited_pair->atomic_propositions) == 0) {
436 if (snapshot_compare(pair_test, new_visited_pair) == 0) {
437 if (pair_test->other_num == -1)
438 new_visited_pair->other_num = pair_test->num;
440 new_visited_pair->other_num = pair_test->other_num;
441 if (dot_output == NULL)
442 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", new_visited_pair->num, pair_test->num);
444 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);
445 xbt_dynar_remove_at(visited_pairs, cursor, &pair_test);
446 xbt_dynar_insert_at(visited_pairs, cursor, &new_visited_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_visited_pair->other_num;
462 xbt_dynar_insert_at(visited_pairs, min, &new_visited_pair);
464 pair_test = (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, index, mc_visited_pair_t);
465 if (pair_test->nb_processes < new_visited_pair->nb_processes) {
466 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
468 if (pair_test->heap_bytes_used < new_visited_pair->heap_bytes_used)
469 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
471 xbt_dynar_insert_at(visited_pairs, index, &new_visited_pair);
475 if (xbt_dynar_length(visited_pairs) > _sg_mc_visited) {
476 int min2 = mc_stats->expanded_pairs;
477 unsigned int cursor2 = 0;
478 unsigned int index2 = 0;
479 xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
480 if (!mc_important_snapshot(pair_test->graph_state->system_state) && pair_test->num < min2) {
482 min2 = pair_test->num;
485 xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
486 pair_test->visited_removed = 1;
487 if (pair_test->acceptance_pair) {
488 if (pair_test->acceptance_removed)
489 MC_visited_pair_delete(pair_test);
491 MC_visited_pair_delete(pair_test);