1 /* Copyright (c) 2011-2013 Da SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include "mc_private.h"
10 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc,
11 "Logging specific to algorithms for liveness properties verification");
13 /********* Global variables *********/
15 xbt_dynar_t acceptance_pairs;
16 xbt_dynar_t visited_pairs;
17 xbt_dynar_t successors;
20 /********* Static functions *********/
22 static xbt_dynar_t get_atomic_propositions_values(){
25 unsigned int cursor = 0;
26 xbt_automaton_propositional_symbol_t ps = NULL;
27 xbt_dynar_t values = xbt_dynar_new(sizeof(int), NULL);
29 xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, ps){
30 f = (int_f_void_t)ps->function;
32 xbt_dynar_push_as(values, int, res);
38 static int get_search_interval(xbt_dynar_t all_pairs, mc_pair_t pair, int *min, int *max){
40 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
44 int cursor = 0, previous_cursor, next_cursor;
47 int end = xbt_dynar_length(all_pairs) - 1;
50 cursor = (start + end) / 2;
51 pair_test = (mc_pair_t)xbt_dynar_get_as(all_pairs, cursor, mc_pair_t);
52 if(pair_test->nb_processes < pair->nb_processes){
54 }else if(pair_test->nb_processes > pair->nb_processes){
57 if(pair_test->heap_bytes_used < pair->heap_bytes_used){
59 }else if(pair_test->heap_bytes_used > pair->heap_bytes_used){
63 previous_cursor = cursor - 1;
64 while(previous_cursor >= 0){
65 pair_test = (mc_pair_t)xbt_dynar_get_as(all_pairs, previous_cursor, mc_pair_t);
66 if(pair_test->nb_processes != pair->nb_processes || pair_test->heap_bytes_used != pair->heap_bytes_used)
68 *min = previous_cursor;
71 next_cursor = cursor + 1;
72 while(next_cursor < xbt_dynar_length(all_pairs)){
73 pair_test = (mc_pair_t)xbt_dynar_get_as(all_pairs, next_cursor, mc_pair_t);
74 if(pair_test->nb_processes != pair->nb_processes || pair_test->heap_bytes_used != pair->heap_bytes_used)
92 static int is_reached_acceptance_pair(mc_pair_t pair){
94 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
98 if(xbt_dynar_is_empty(acceptance_pairs)){
100 if(pair->graph_state->system_state == NULL){
101 pair->graph_state->system_state = MC_take_snapshot();
102 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
104 xbt_dynar_push(acceptance_pairs, &pair);
113 if(pair->graph_state->system_state == NULL){
114 pair->graph_state->system_state = MC_take_snapshot();
115 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
118 int min = -1, max = -1, index;
122 index = get_search_interval(acceptance_pairs, pair, &min, &max);
124 if(min != -1 && max != -1){ /* Acceptance pair with same number of processes and same heap bytes used exists */
125 res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(acceptance_pairs, min), (max-min)+1, pair);
129 return ((mc_pair_t)xbt_dynar_get_as(acceptance_pairs, (min+res)-1, mc_pair_t))->num;
131 xbt_dynar_insert_at(acceptance_pairs, min, &pair);
133 pair_test = (mc_pair_t)xbt_dynar_get_as(acceptance_pairs, index, mc_pair_t);
134 if(pair_test->nb_processes < pair->nb_processes){
135 xbt_dynar_insert_at(acceptance_pairs, index+1, &pair);
137 if(pair_test->heap_bytes_used < pair->heap_bytes_used)
138 xbt_dynar_insert_at(acceptance_pairs, index + 1, &pair);
140 xbt_dynar_insert_at(acceptance_pairs, index, &pair);
154 static void set_acceptance_pair_reached(mc_pair_t pair){
156 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
160 if(xbt_dynar_is_empty(acceptance_pairs)){
162 if(pair->graph_state->system_state == NULL){
163 pair->graph_state->system_state = MC_take_snapshot();
164 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
166 xbt_dynar_push(acceptance_pairs, &pair);
170 if(pair->graph_state->system_state == NULL){
171 pair->graph_state->system_state = MC_take_snapshot();
172 pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
175 size_t current_bytes_used = pair->heap_bytes_used;
176 int current_nb_processes = pair->nb_processes;
180 int end = xbt_dynar_length(acceptance_pairs) - 1;
182 mc_pair_t pair_test = NULL;
183 size_t bytes_used_test = 0;
184 int nb_processes_test;
187 cursor = (start + end) / 2;
188 pair_test = (mc_pair_t)xbt_dynar_get_as(acceptance_pairs, cursor, mc_pair_t);
189 bytes_used_test = pair_test->heap_bytes_used;
190 nb_processes_test = pair_test->nb_processes;
191 if(nb_processes_test < current_nb_processes)
193 if(nb_processes_test > current_nb_processes)
195 if(nb_processes_test == current_nb_processes){
196 if(bytes_used_test < current_bytes_used)
198 if(bytes_used_test > current_bytes_used)
200 if(bytes_used_test == current_bytes_used)
205 if(bytes_used_test < current_bytes_used)
206 xbt_dynar_insert_at(acceptance_pairs, cursor + 1, &pair);
208 xbt_dynar_insert_at(acceptance_pairs, cursor, &pair);
216 static void remove_acceptance_pair(mc_pair_t pair){
218 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
222 unsigned int cursor = 0;
226 xbt_dynar_foreach(acceptance_pairs, cursor, pair_test){
227 if(pair_test->num == pair->num){
234 xbt_dynar_remove_at(acceptance_pairs, cursor, NULL);
236 pair->acceptance_removed = 1;
238 if(pair->stack_removed && pair->acceptance_removed){
239 if(_sg_mc_visited == 0){
240 MC_pair_delete(pair);
241 }else if(pair->visited_removed){
242 MC_pair_delete(pair);
250 static int is_visited_pair(mc_pair_t pair){
252 if(_sg_mc_visited == 0)
255 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
259 if(xbt_dynar_is_empty(visited_pairs)){
261 if(pair->graph_state->system_state == NULL)
262 pair->graph_state->system_state = MC_take_snapshot();
263 xbt_dynar_push(visited_pairs, &pair);
272 if(pair->graph_state->system_state == NULL)
273 pair->graph_state->system_state = MC_take_snapshot();
275 int min = -1, max = -1, index;
279 index = get_search_interval(visited_pairs, pair, &min, &max);
281 if(min != -1 && max != -1){ /* Visited pair with same number of processes and same heap bytes used exists */
282 res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_pairs, min), (max-min)+1, pair);
284 pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, (min+res)-1, mc_pair_t);
285 if(pair_test->other_num == -1)
286 pair->other_num = pair_test->num;
288 pair->other_num = pair_test->other_num;
289 if(dot_output == NULL)
290 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", pair->num, pair_test->num);
292 XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", pair->num, pair_test->num, pair->other_num);
293 xbt_dynar_remove_at(visited_pairs, (min + res) - 1, NULL);
294 xbt_dynar_insert_at(visited_pairs, (min+res) - 1, &pair);
295 pair_test->visited_removed = 1;
296 if(pair_test->stack_removed && pair_test->visited_removed){
297 if((pair_test->automaton_state->type == 1) || (pair_test->automaton_state->type == 2)){
298 if(pair_test->acceptance_removed){
299 MC_pair_delete(pair_test);
302 MC_pair_delete(pair_test);
307 return pair->other_num;
309 xbt_dynar_insert_at(visited_pairs, min, &pair);
311 pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, index, mc_pair_t);
312 if(pair_test->nb_processes < pair->nb_processes){
313 xbt_dynar_insert_at(visited_pairs, index+1, &pair);
315 if(pair_test->heap_bytes_used < pair->heap_bytes_used)
316 xbt_dynar_insert_at(visited_pairs, index + 1, &pair);
318 xbt_dynar_insert_at(visited_pairs, index, &pair);
322 if(xbt_dynar_length(visited_pairs) > _sg_mc_visited){
323 int min = mc_stats->expanded_states;
324 unsigned int cursor2 = 0;
325 unsigned int index2 = 0;
326 xbt_dynar_foreach(visited_pairs, cursor2, pair_test){
327 if(pair_test->num < min){
329 min = pair_test->num;
332 xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
333 pair_test->visited_removed = 1;
334 if(pair_test->stack_removed && pair_test->acceptance_removed && pair_test->visited_removed)
335 MC_pair_delete(pair_test);
347 static int MC_automaton_evaluate_label(xbt_automaton_exp_label_t l, xbt_dynar_t atomic_propositions_values){
351 int left_res = MC_automaton_evaluate_label(l->u.or_and.left_exp, atomic_propositions_values);
352 int right_res = MC_automaton_evaluate_label(l->u.or_and.right_exp, atomic_propositions_values);
353 return (left_res || right_res);
356 int left_res = MC_automaton_evaluate_label(l->u.or_and.left_exp, atomic_propositions_values);
357 int right_res = MC_automaton_evaluate_label(l->u.or_and.right_exp, atomic_propositions_values);
358 return (left_res && right_res);
361 int res = MC_automaton_evaluate_label(l->u.exp_not, atomic_propositions_values);
365 unsigned int cursor = 0;
366 xbt_automaton_propositional_symbol_t p = NULL;
367 xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, p){
368 if(strcmp(p->pred, l->u.predicat) == 0)
369 return (int)xbt_dynar_get_as(atomic_propositions_values, cursor, int);
382 /********* DDFS Algorithm *********/
385 void MC_ddfs_init(void){
387 initial_state_liveness->raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
389 XBT_DEBUG("**************************************************");
390 XBT_DEBUG("Double-DFS init");
391 XBT_DEBUG("**************************************************");
393 mc_pair_t initial_pair = NULL;
394 smx_process_t process;
396 MC_wait_for_requests();
400 acceptance_pairs = xbt_dynar_new(sizeof(mc_pair_t), NULL);
401 visited_pairs = xbt_dynar_new(sizeof(mc_pair_t), NULL);
402 successors = xbt_dynar_new(sizeof(mc_pair_t), NULL);
404 initial_state_liveness->snapshot = MC_take_snapshot();
405 initial_state_liveness->prev_pair = 0;
409 unsigned int cursor = 0;
410 xbt_automaton_state_t automaton_state;
412 xbt_dynar_foreach(_mc_property_automaton->states, cursor, automaton_state){
413 if(automaton_state->type == -1){ /* Initial automaton state */
417 initial_pair = MC_pair_new();
418 initial_pair->automaton_state = automaton_state;
419 initial_pair->graph_state = MC_state_new();
420 initial_pair->atomic_propositions = get_atomic_propositions_values();
422 /* Get enabled process and insert it in the interleave set of the graph_state */
423 xbt_swag_foreach(process, simix_global->process_list){
424 if(MC_process_is_enabled(process)){
425 MC_state_interleave_process(initial_pair->graph_state, process);
429 initial_pair->requests = MC_state_interleave_size(initial_pair->graph_state);
430 initial_pair->search_cycle = 0;
432 xbt_fifo_unshift(mc_stack_liveness, initial_pair);
439 MC_restore_snapshot(initial_state_liveness->snapshot);
444 }else if(automaton_state->type == 2){ /* Acceptance automaton state */
448 initial_pair = MC_pair_new();
449 initial_pair->automaton_state = automaton_state;
450 initial_pair->graph_state = MC_state_new();
451 initial_pair->atomic_propositions = get_atomic_propositions_values();
453 /* Get enabled process and insert it in the interleave set of the graph_state */
454 xbt_swag_foreach(process, simix_global->process_list){
455 if(MC_process_is_enabled(process)){
456 MC_state_interleave_process(initial_pair->graph_state, process);
460 initial_pair->requests = MC_state_interleave_size(initial_pair->graph_state);
461 initial_pair->search_cycle = 1;
463 xbt_fifo_unshift(mc_stack_liveness, initial_pair);
467 set_acceptance_pair_reached(initial_pair);
472 MC_restore_snapshot(initial_state_liveness->snapshot);
478 if(initial_state_liveness->raw_mem_set)
489 smx_process_t process;
490 mc_pair_t current_pair = NULL;
492 if(xbt_fifo_size(mc_stack_liveness) == 0)
495 /* Get current pair */
496 current_pair = (mc_pair_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_liveness));
498 /* Update current state in buchi automaton */
499 _mc_property_automaton->current_state = current_pair->automaton_state;
501 XBT_DEBUG("********************* ( Depth = %d, search_cycle = %d, interleave size %d)", xbt_fifo_size(mc_stack_liveness), current_pair->search_cycle, MC_state_interleave_size(current_pair->graph_state));
503 mc_stats->visited_pairs++;
506 smx_simcall_t req = NULL;
509 xbt_automaton_transition_t transition_succ;
510 unsigned int cursor = 0;
512 int reached_num, visited_num;
514 mc_pair_t next_pair = NULL;
515 xbt_dynar_t prop_values = NULL;
517 if(xbt_fifo_size(mc_stack_liveness) < _sg_mc_max_depth){
519 if(current_pair->requests > 0){
521 if(current_pair->search_cycle){
523 if((current_pair->automaton_state->type == 1) || (current_pair->automaton_state->type == 2)){
525 if((reached_num = is_reached_acceptance_pair(current_pair)) != -1){
527 XBT_INFO("Pair %d already reached (equal to pair %d) !", current_pair->num, reached_num);
530 xbt_fifo_shift(mc_stack_liveness);
531 if(dot_output != NULL)
532 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", initial_state_liveness->prev_pair, reached_num, initial_state_liveness->prev_req);
535 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
536 XBT_INFO("| ACCEPTANCE CYCLE |");
537 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
538 XBT_INFO("Counter-example that violates formula :");
539 MC_show_stack_liveness(mc_stack_liveness);
540 MC_dump_stack_liveness(mc_stack_liveness);
541 MC_print_statistics(mc_stats);
548 if((visited_num = is_visited_pair(current_pair)) != -1){
551 if(dot_output != NULL)
552 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", initial_state_liveness->prev_pair, visited_num, initial_state_liveness->prev_req);
558 while((req = MC_state_get_request(current_pair->graph_state, &value)) != NULL){
561 if(dot_output != NULL){
562 if(initial_state_liveness->prev_pair != 0 && initial_state_liveness->prev_pair != current_pair->num){
563 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", initial_state_liveness->prev_pair, current_pair->num, initial_state_liveness->prev_req);
564 xbt_free(initial_state_liveness->prev_req);
566 initial_state_liveness->prev_pair = current_pair->num;
570 /* Debug information */
571 if(XBT_LOG_ISENABLED(mc_liveness, xbt_log_priority_debug)){
572 req_str = MC_request_to_string(req, value);
573 XBT_DEBUG("Execute: %s", req_str);
578 if(dot_output != NULL){
579 initial_state_liveness->prev_req = MC_request_get_dot_output(req, value);
580 if(current_pair->search_cycle)
581 fprintf(dot_output, "%d [shape=doublecircle];\n", current_pair->num);
585 MC_state_set_executed_request(current_pair->graph_state, req, value);
586 mc_stats->executed_transitions++;
588 /* Answer the request */
589 SIMIX_simcall_pre(req, value);
591 /* Wait for requests (schedules processes) */
592 MC_wait_for_requests();
595 prop_values = get_atomic_propositions_values();
598 /* Evaluate enabled transition according to atomic propositions values */
600 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
602 res = MC_automaton_evaluate_label(transition_succ->label, prop_values);
604 if(res == 1){ // enabled transition in automaton
608 next_pair = MC_pair_new();
609 next_pair->graph_state = MC_state_new();
610 next_pair->automaton_state = transition_succ->dst;
611 next_pair->atomic_propositions = get_atomic_propositions_values();
613 /* Get enabled process and insert it in the interleave set of the next graph_state */
614 xbt_swag_foreach(process, simix_global->process_list){
615 if(MC_process_is_enabled(process)){
616 MC_state_interleave_process(next_pair->graph_state, process);
620 next_pair->requests = MC_state_interleave_size(next_pair->graph_state);
622 if(next_pair->automaton_state->type == 1 || next_pair->automaton_state->type == 2 || current_pair->search_cycle)
623 next_pair->search_cycle = 1;
625 xbt_fifo_unshift(mc_stack_liveness, next_pair);
627 if(mc_stats->expanded_pairs%1000000 == 0)
628 XBT_INFO("Expanded pairs : %lu", mc_stats->expanded_pairs);
638 /* Then, evaluate true transitions (always true, whatever atomic propositions values) */
640 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
642 res = MC_automaton_evaluate_label(transition_succ->label, prop_values);
644 if(res == 2){ // true transition in automaton
648 next_pair = MC_pair_new();
649 next_pair->graph_state = MC_state_new();
650 next_pair->automaton_state = transition_succ->dst;
651 next_pair->atomic_propositions = get_atomic_propositions_values();
653 /* Get enabled process and insert it in the interleave set of the next graph_state */
654 xbt_swag_foreach(process, simix_global->process_list){
655 if(MC_process_is_enabled(process)){
656 MC_state_interleave_process(next_pair->graph_state, process);
660 next_pair->requests = MC_state_interleave_size(next_pair->graph_state);
662 if(next_pair->automaton_state->type == 1 || next_pair->automaton_state->type == 2 || current_pair->search_cycle)
663 next_pair->search_cycle = 1;
665 xbt_fifo_unshift(mc_stack_liveness, next_pair);
667 if(mc_stats->expanded_pairs%1000000 == 0)
668 XBT_INFO("Expanded pairs : %lu", mc_stats->expanded_pairs);
678 if(MC_state_interleave_size(current_pair->graph_state) > 0){
679 XBT_DEBUG("Backtracking to depth %d", xbt_fifo_size(mc_stack_liveness));
680 MC_replay_liveness(mc_stack_liveness, 0);
689 mc_stats->executed_transitions++;
691 XBT_DEBUG("No request to execute in this state, search evolution in Büchi Automaton.");
693 if(current_pair->search_cycle){
695 if((current_pair->automaton_state->type == 1) || (current_pair->automaton_state->type == 2)){
697 if((reached_num = is_reached_acceptance_pair(current_pair)) != -1){
699 XBT_INFO("Pair %d already reached (equal to pair %d) !", current_pair->num, reached_num);
702 xbt_fifo_shift(mc_stack_liveness);
705 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
706 XBT_INFO("| ACCEPTANCE CYCLE |");
707 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
708 XBT_INFO("Counter-example that violates formula :");
709 MC_show_stack_liveness(mc_stack_liveness);
710 MC_dump_stack_liveness(mc_stack_liveness);
711 MC_print_statistics(mc_stats);
718 if((visited_num = is_visited_pair(current_pair)) != -1){
720 XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", current_pair->num, visited_num);
725 prop_values = get_atomic_propositions_values();
728 /* Evaluate enabled transition according to atomic propositions values */
730 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
732 res = MC_automaton_evaluate_label(transition_succ->label, prop_values);
734 if(res == 1){ // enabled transition in automaton
738 next_pair = MC_pair_new();
739 next_pair->graph_state = MC_state_new();
740 next_pair->automaton_state = transition_succ->dst;
741 next_pair->atomic_propositions = get_atomic_propositions_values();
742 next_pair->requests = MC_state_interleave_size(next_pair->graph_state);
744 if(next_pair->automaton_state->type == 1 || next_pair->automaton_state->type == 2 || current_pair->search_cycle)
745 next_pair->search_cycle = 1;
747 xbt_fifo_unshift(mc_stack_liveness, next_pair);
749 if(mc_stats->expanded_pairs%1000 == 0)
750 XBT_INFO("Expanded pairs : %lu", mc_stats->expanded_pairs);
752 if(dot_output != NULL)
753 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", current_pair->num, next_pair->num, "");
763 /* Then, evaluate true transitions (always true, whatever atomic propositions values) */
765 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
767 res = MC_automaton_evaluate_label(transition_succ->label, prop_values);
769 if(res == 2){ // true transition in automaton
773 next_pair = MC_pair_new();
774 next_pair->graph_state = MC_state_new();
775 next_pair->automaton_state = transition_succ->dst;
776 next_pair->atomic_propositions = get_atomic_propositions_values();
777 next_pair->requests = MC_state_interleave_size(next_pair->graph_state);
779 if(next_pair->automaton_state->type == 1 || next_pair->automaton_state->type == 2 || current_pair->search_cycle)
780 next_pair->search_cycle = 1;
782 xbt_fifo_unshift(mc_stack_liveness, next_pair);
784 if(mc_stats->expanded_pairs%1000 == 0)
785 XBT_INFO("Expanded pairs : %lu", mc_stats->expanded_pairs);
787 if(dot_output != NULL)
788 fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", current_pair->num, next_pair->num, "");
802 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
803 if(MC_state_interleave_size(current_pair->graph_state) > 0){
804 XBT_WARN("/!\\ But, there are still processes to interleave. Model-checker will not be able to ensure the soundness of the verification from now. /!\\ ");
805 if(_sg_mc_max_depth == 1000)
806 XBT_WARN("Notice : the default value of max depth is 1000 but you can change it with cfg=model-check/max_depth:value.");
811 if(xbt_fifo_size(mc_stack_liveness) == _sg_mc_max_depth ){
812 XBT_DEBUG("Pair %d (depth = %d) shifted in stack, maximum depth reached", current_pair->num, xbt_fifo_size(mc_stack_liveness) );
814 XBT_DEBUG("Pair %d (depth = %d) shifted in stack", current_pair->num, xbt_fifo_size(mc_stack_liveness) );
819 xbt_dynar_free(&prop_values);
820 current_pair = xbt_fifo_shift(mc_stack_liveness);
821 current_pair->stack_removed = 1;
822 if(current_pair->search_cycle){
823 remove_acceptance_pair(current_pair);
825 if(_sg_mc_visited == 0)
826 MC_pair_delete(current_pair);
827 else if(current_pair->visited_removed)
828 MC_pair_delete(current_pair);