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_first_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_next_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_state_t graph_state)
66 mc_visited_pair_t pair = NULL;
67 pair = xbt_new0(s_mc_visited_pair_t, 1);
68 pair->graph_state = graph_state;
69 if(pair->graph_state->system_state == NULL)
70 pair->graph_state->system_state = MC_take_snapshot(pair_num);
71 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
72 pair->nb_processes = xbt_swag_size(simix_global->process_list);
73 pair->automaton_state = automaton_state;
76 pair->acceptance_removed = 0;
77 pair->visited_removed = 0;
78 pair->acceptance_pair = 0;
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_first_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_next_item(item);
99 void MC_visited_pair_delete(mc_visited_pair_t p)
101 p->automaton_state = NULL;
102 if( !is_exploration_stack_pair(p))
103 MC_state_delete(p->graph_state, 1);
104 xbt_dynar_free(&(p->atomic_propositions));
110 * \brief Find a suitable subrange of candidate duplicates for a given state
111 * \param list dynamic array of states/pairs with candidate duplicates of the current state;
112 * \param ref current state/pair;
113 * \param min (output) index of the beginning of the the subrange
114 * \param max (output) index of the enf of the subrange
116 * Given a suitably ordered array of states/pairs, this function extracts a subrange
117 * (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
118 * This function uses only fast discriminating criterions and does not use the
119 * full state/pair comparison algorithms.
121 * The states/pairs in list MUST be ordered using a (given) weak order
122 * (based on nb_processes and heap_bytes_used).
123 * The subrange is the subrange of "equivalence" of the given state/pair.
125 int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
128 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
132 int cursor = 0, previous_cursor, next_cursor;
133 int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
136 if (_sg_mc_liveness) {
137 nb_processes = ((mc_visited_pair_t) ref)->nb_processes;
138 heap_bytes_used = ((mc_visited_pair_t) ref)->heap_bytes_used;
140 nb_processes = ((mc_visited_state_t) ref)->nb_processes;
141 heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
145 int end = xbt_dynar_length(list) - 1;
147 while (start <= end) {
148 cursor = (start + end) / 2;
149 if (_sg_mc_liveness) {
150 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
151 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
152 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
154 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, cursor, mc_visited_state_t);
155 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
156 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
158 if (nb_processes_test < nb_processes) {
160 } else if (nb_processes_test > nb_processes) {
163 if (heap_bytes_used_test < heap_bytes_used) {
165 } else if (heap_bytes_used_test > heap_bytes_used) {
168 *min = *max = cursor;
169 previous_cursor = cursor - 1;
170 while (previous_cursor >= 0) {
171 if (_sg_mc_liveness) {
172 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor, mc_visited_pair_t);
173 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
174 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
176 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor, mc_visited_state_t);
177 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
178 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
180 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
182 *min = previous_cursor;
185 next_cursor = cursor + 1;
186 while (next_cursor < xbt_dynar_length(list)) {
187 if (_sg_mc_liveness) {
188 ref_test = (mc_visited_pair_t) xbt_dynar_get_as(list, next_cursor, mc_visited_pair_t);
189 nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
190 heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
192 ref_test = (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor, mc_visited_state_t);
193 nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
194 heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
196 if (nb_processes_test != nb_processes || heap_bytes_used_test != heap_bytes_used)
216 * \brief Checks whether a given state has already been visited by the algorithm.
219 mc_visited_state_t is_visited_state(mc_state_t graph_state)
222 if (_sg_mc_visited == 0)
225 int partial_comm = 0;
227 /* If comm determinism verification, we cannot stop the exploration if some
228 communications are not finished (at least, data are transfered). These communications
229 are incomplete and they cannot be analyzed and compared with the initial pattern. */
230 if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
231 int current_process = 1;
232 while (current_process < simix_process_maxpid) {
233 if (!xbt_dynar_is_empty((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, current_process, xbt_dynar_t))){
234 XBT_DEBUG("Some communications are not finished, cannot stop the exploration ! State not visited.");
242 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
246 mc_visited_state_t new_state = visited_state_new();
247 graph_state->system_state = new_state->system_state;
248 graph_state->in_visited_states = 1;
249 XBT_DEBUG("Snapshot %p of visited state %d (exploration stack state %d)", new_state->system_state, new_state->num, graph_state->num);
251 if (xbt_dynar_is_empty(visited_states)) {
253 xbt_dynar_push(visited_states, &new_state);
262 int min = -1, max = -1, index;
264 mc_visited_state_t state_test;
267 index = get_search_interval(visited_states, new_state, &min, &max);
269 if (min != -1 && max != -1) {
271 // Parallell implementation
272 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state);
274 state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t);
275 if(state_test->other_num == -1)
276 new_state->other_num = state_test->num;
278 new_state->other_num = state_test->other_num;
279 if(dot_output == NULL)
280 XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
282 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);
283 xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL);
284 xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state);
287 return new_state->other_num;
290 if(!partial_comm && initial_global_state->initial_communications_pattern_done){
293 while (cursor <= max) {
294 state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor, mc_visited_state_t);
295 if (snapshot_compare(state_test, new_state) == 0) {
296 // The state has been visited:
298 if (state_test->other_num == -1)
299 new_state->other_num = state_test->num;
301 new_state->other_num = state_test->other_num;
302 if (dot_output == NULL)
303 XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
305 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);
307 /* Replace the old state with the new one (with a bigger num)
308 (when the max number of visited states is reached, the oldest
309 one is removed according to its number (= with the min number) */
310 xbt_dynar_remove_at(visited_states, cursor, NULL);
311 xbt_dynar_insert_at(visited_states, cursor, &new_state);
312 XBT_DEBUG("Replace visited state %d with the new visited state %d", state_test->num, new_state->num);
322 xbt_dynar_insert_at(visited_states, min, &new_state);
323 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
327 // The state has not been visited: insert the state in the dynamic array.
328 state_test = (mc_visited_state_t) xbt_dynar_get_as(visited_states, index, mc_visited_state_t);
329 if (state_test->nb_processes < new_state->nb_processes) {
330 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
332 if (state_test->heap_bytes_used < new_state->heap_bytes_used)
333 xbt_dynar_insert_at(visited_states, index + 1, &new_state);
335 xbt_dynar_insert_at(visited_states, index, &new_state);
338 XBT_DEBUG("Insert new visited state %d (total : %lu)", new_state->num, xbt_dynar_length(visited_states));
342 // We have reached the maximum number of stored states;
343 if (xbt_dynar_length(visited_states) > _sg_mc_visited) {
345 XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)");
347 // Find the (index of the) older state (with the smallest num):
348 int min2 = mc_stats->expanded_states;
349 unsigned int cursor2 = 0;
350 unsigned int index2 = 0;
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)");
372 * \brief Checks whether a given pair has already been visited by the algorithm.
374 int is_visited_pair(mc_visited_pair_t visited_pair, mc_pair_t pair) {
376 if (_sg_mc_visited == 0)
379 int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
383 mc_visited_pair_t new_visited_pair = NULL;
385 if (visited_pair == NULL) {
386 new_visited_pair = MC_visited_pair_new(pair->num, pair->automaton_state, pair->atomic_propositions, pair->graph_state);
388 new_visited_pair = visited_pair;
391 if (xbt_dynar_is_empty(visited_pairs)) {
393 xbt_dynar_push(visited_pairs, &new_visited_pair);
397 int min = -1, max = -1, index;
399 mc_visited_pair_t pair_test;
402 index = get_search_interval(visited_pairs, new_visited_pair, &min, &max);
404 if (min != -1 && max != -1) { // Visited pair with same number of processes and same heap bytes used exists
405 /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_pairs, min), (max-min)+1, pair);
407 pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, (min+res)-1, mc_pair_t);
408 if(pair_test->other_num == -1)
409 pair->other_num = pair_test->num;
411 pair->other_num = pair_test->other_num;
412 if(dot_output == NULL)
413 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", pair->num, pair_test->num);
415 XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", pair->num, pair_test->num, pair->other_num);
416 xbt_dynar_remove_at(visited_pairs, (min + res) - 1, NULL);
417 xbt_dynar_insert_at(visited_pairs, (min+res) - 1, &pair);
418 pair_test->visited_removed = 1;
419 if(pair_test->stack_removed && pair_test->visited_removed){
420 if((pair_test->automaton_state->type == 1) || (pair_test->automaton_state->type == 2)){
421 if(pair_test->acceptance_removed){
422 MC_pair_delete(pair_test);
425 MC_pair_delete(pair_test);
430 return pair->other_num;
433 while (cursor <= max) {
434 pair_test = (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, cursor, mc_visited_pair_t);
435 if (xbt_automaton_state_compare(pair_test->automaton_state, new_visited_pair->automaton_state) == 0) {
436 if (xbt_automaton_propositional_symbols_compare_value(pair_test->atomic_propositions, new_visited_pair->atomic_propositions) == 0) {
437 if (snapshot_compare(pair_test, new_visited_pair) == 0) {
438 if (pair_test->other_num == -1)
439 new_visited_pair->other_num = pair_test->num;
441 new_visited_pair->other_num = pair_test->other_num;
442 if (dot_output == NULL)
443 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", new_visited_pair->num, pair_test->num);
445 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);
446 xbt_dynar_remove_at(visited_pairs, cursor, &pair_test);
447 xbt_dynar_insert_at(visited_pairs, cursor, &new_visited_pair);
448 pair_test->visited_removed = 1;
449 if (pair_test->acceptance_pair) {
450 if (pair_test->acceptance_removed == 1)
451 MC_visited_pair_delete(pair_test);
453 MC_visited_pair_delete(pair_test);
457 return new_visited_pair->other_num;
463 xbt_dynar_insert_at(visited_pairs, min, &new_visited_pair);
465 pair_test = (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, index, mc_visited_pair_t);
466 if (pair_test->nb_processes < new_visited_pair->nb_processes) {
467 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
469 if (pair_test->heap_bytes_used < new_visited_pair->heap_bytes_used)
470 xbt_dynar_insert_at(visited_pairs, index + 1, &new_visited_pair);
472 xbt_dynar_insert_at(visited_pairs, index, &new_visited_pair);
476 if (xbt_dynar_length(visited_pairs) > _sg_mc_visited) {
477 int min2 = mc_stats->expanded_pairs;
478 unsigned int cursor2 = 0;
479 unsigned int index2 = 0;
480 xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
481 if (!mc_important_snapshot(pair_test->graph_state->system_state) && pair_test->num < min2) {
483 min2 = pair_test->num;
486 xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
487 pair_test->visited_removed = 1;
488 if (pair_test->acceptance_pair) {
489 if (pair_test->acceptance_removed)
490 MC_visited_pair_delete(pair_test);
492 MC_visited_pair_delete(pair_test);