1 /* Copyright (c) 2008 Martin Quinson, Cristian Rosa.
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. */
9 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dpor, mc,
10 "Logging specific to MC DPOR exploration");
13 * \brief Initialize the DPOR exploration algorithm
17 mc_state_t initial_state = NULL;
18 smx_process_t process;
20 /* Create the initial state and push it into the exploration stack */
22 initial_state = MC_state_new();
23 xbt_fifo_unshift(mc_stack, initial_state);
26 XBT_DEBUG("**************************************************");
27 XBT_DEBUG("Initial state");
29 /* Wait for requests (schedules processes) */
30 MC_wait_for_requests();
33 /* Get an enabled process and insert it in the interleave set of the initial state */
34 xbt_swag_foreach(process, simix_global->process_list){
35 if(MC_process_is_enabled(process)){
36 MC_state_interleave_process(initial_state, process);
42 /* FIXME: Update Statistics
43 mc_stats->state_size +=
44 xbt_setset_set_size(initial_state->enabled_transitions); */
49 * \brief Perform the model-checking operation using a depth-first search exploration
50 * with Dynamic Partial Order Reductions
56 smx_req_t req = NULL, prev_req = NULL;
57 mc_state_t state = NULL, prev_state = NULL, next_state = NULL;
58 smx_process_t process = NULL;
59 xbt_fifo_item_t item = NULL;
61 while (xbt_fifo_size(mc_stack) > 0) {
63 /* Get current state */
65 xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
67 XBT_DEBUG("**************************************************");
68 XBT_DEBUG("Exploration depth=%d (state=%p)(%u interleave)",
69 xbt_fifo_size(mc_stack), state,
70 MC_state_interleave_size(state));
72 /* Update statistics */
73 mc_stats->visited_states++;
75 /* If there are processes to interleave and the maximum depth has not been reached
76 then perform one step of the exploration algorithm */
77 if (xbt_fifo_size(mc_stack) < MAX_DEPTH &&
78 (req = MC_state_get_request(state, &value))) {
80 /* Debug information */
81 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
82 req_str = MC_request_to_string(req, value);
83 XBT_DEBUG("Execute: %s", req_str);
87 MC_state_set_executed_request(state, req, value);
88 mc_stats->executed_transitions++;
90 /* Answer the request */
91 SIMIX_request_pre(req, value); /* After this call req is no longer usefull */
93 /* Wait for requests (schedules processes) */
94 MC_wait_for_requests();
96 /* Create the new expanded state */
98 next_state = MC_state_new();
99 xbt_fifo_unshift(mc_stack, next_state);
101 /* Get an enabled process and insert it in the interleave set of the next state */
102 xbt_swag_foreach(process, simix_global->process_list){
103 if(MC_process_is_enabled(process)){
104 MC_state_interleave_process(next_state, process);
110 /* FIXME: Update Statistics
111 mc_stats->state_size +=
112 xbt_setset_set_size(next_state->enabled_transitions);*/
114 /* Let's loop again */
116 /* The interleave set is empty or the maximum depth is reached, let's back-track */
118 XBT_DEBUG("There are no more processes to interleave.");
120 /* Trash the current state, no longer needed */
122 xbt_fifo_shift(mc_stack);
123 MC_state_delete(state);
126 /* Check for deadlocks */
127 if(MC_deadlock_check()){
128 MC_show_deadlock(NULL);
133 /* Traverse the stack backwards until a state with a non empty interleave
134 set is found, deleting all the states that have it empty in the way.
135 For each deleted state, check if the request that has generated it
136 (from it's predecesor state), depends on any other previous request
137 executed before it. If it does then add it to the interleave set of the
138 state that executed that previous request. */
139 while ((state = xbt_fifo_shift(mc_stack)) != NULL) {
140 req = MC_state_get_internal_request(state);
141 xbt_fifo_foreach(mc_stack, item, prev_state, mc_state_t) {
142 if(MC_request_depend(req, MC_state_get_internal_request(prev_state))){
143 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
144 XBT_DEBUG("Dependent Transitions:");
145 prev_req = MC_state_get_executed_request(prev_state, &value);
146 req_str = MC_request_to_string(prev_req, value);
147 XBT_DEBUG("%s (state=%p)", req_str, prev_state);
149 prev_req = MC_state_get_executed_request(state, &value);
150 req_str = MC_request_to_string(prev_req, value);
151 XBT_DEBUG("%s (state=%p)", req_str, state);
155 if(!MC_state_process_is_done(prev_state, req->issuer))
156 MC_state_interleave_process(prev_state, req->issuer);
158 XBT_DEBUG("Process %p is in done set", req->issuer);
163 if (MC_state_interleave_size(state)) {
164 /* We found a back-tracking point, let's loop */
165 xbt_fifo_unshift(mc_stack, state);
166 XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_stack));
171 MC_state_delete(state);
182 /********************* DPOR without replay *********************/
184 mc_state_ws_t new_state_ws(mc_snapshot_t s, mc_state_t gs){
185 mc_state_ws_t sws = NULL;
186 sws = xbt_new0(s_mc_state_ws_t, 1);
187 sws->system_state = s;
188 sws->graph_state = gs;
192 void MC_dpor_with_restore_snapshot_init(){
194 XBT_DEBUG("**************************************************");
195 XBT_DEBUG("DPOR (with restore snapshot) init");
196 XBT_DEBUG("**************************************************");
198 mc_state_t initial_graph_state;
199 smx_process_t process;
200 mc_snapshot_t initial_system_snapshot;
201 mc_state_ws_t initial_state ;
203 MC_wait_for_requests();
207 initial_system_snapshot = xbt_new0(s_mc_snapshot_t, 1);
209 initial_graph_state = MC_state_new();
210 xbt_swag_foreach(process, simix_global->process_list){
211 if(MC_process_is_enabled(process)){
212 MC_state_interleave_process(initial_graph_state, process);
217 MC_take_snapshot(initial_system_snapshot);
219 initial_state = new_state_ws(initial_system_snapshot, initial_graph_state);
220 xbt_fifo_unshift(mc_snapshot_stack, initial_state);
224 MC_dpor_with_restore_snapshot();
228 void MC_dpor_with_restore_snapshot(){
230 smx_process_t process = NULL;
232 if(xbt_fifo_size(mc_snapshot_stack) == 0)
236 mc_state_t next_graph_state = NULL;
237 smx_req_t req = NULL, prev_req = NULL;
239 xbt_fifo_item_t item = NULL;
241 mc_snapshot_t next_snapshot;
242 mc_state_ws_t current_state;
243 mc_state_ws_t prev_state;
244 mc_state_ws_t next_state;
246 while(xbt_fifo_size(mc_snapshot_stack) > 0){
248 current_state = (mc_state_ws_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_snapshot_stack));
251 XBT_DEBUG("**************************************************");
252 XBT_DEBUG("Depth : %d, State : %p , %u interleave", xbt_fifo_size(mc_snapshot_stack),current_state, MC_state_interleave_size(current_state->graph_state));
255 if((xbt_fifo_size(mc_snapshot_stack) < MAX_DEPTH) && (req = MC_state_get_request(current_state->graph_state, &value))){
257 /* Debug information */
258 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
259 req_str = MC_request_to_string(req, value);
260 XBT_DEBUG("Execute: %s", req_str);
264 MC_state_set_executed_request(current_state->graph_state, req, value);
266 /* Answer the request */
267 SIMIX_request_pre(req, value);
269 /* Wait for requests (schedules processes) */
270 MC_wait_for_requests();
272 /* Create the new expanded graph_state */
275 next_graph_state = MC_state_new();
277 /* Get an enabled process and insert it in the interleave set of the next graph_state */
278 xbt_swag_foreach(process, simix_global->process_list){
279 if(MC_process_is_enabled(process)){
280 MC_state_interleave_process(next_graph_state, process);
285 next_snapshot = xbt_new0(s_mc_snapshot_t, 1);
286 MC_take_snapshot(next_snapshot);
288 next_state = new_state_ws(next_snapshot, next_graph_state);
289 xbt_fifo_unshift(mc_snapshot_stack, next_state);
294 XBT_DEBUG("There are no more processes to interleave.");
296 /* Trash the current state, no longer needed */
298 xbt_fifo_shift(mc_snapshot_stack);
301 while((current_state = xbt_fifo_shift(mc_snapshot_stack)) != NULL){
302 req = MC_state_get_internal_request(current_state->graph_state);
303 xbt_fifo_foreach(mc_snapshot_stack, item, prev_state, mc_state_ws_t) {
304 if(MC_request_depend(req, MC_state_get_internal_request(prev_state->graph_state))){
305 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
306 XBT_DEBUG("Dependent Transitions:");
307 prev_req = MC_state_get_executed_request(prev_state->graph_state, &value);
308 req_str = MC_request_to_string(prev_req, value);
309 XBT_DEBUG("%s (state=%p)", req_str, prev_state->graph_state);
311 prev_req = MC_state_get_executed_request(current_state->graph_state, &value);
312 req_str = MC_request_to_string(prev_req, value);
313 XBT_DEBUG("%s (state=%p)", req_str, current_state->graph_state);
317 if(!MC_state_process_is_done(prev_state->graph_state, req->issuer)){
318 MC_state_interleave_process(prev_state->graph_state, req->issuer);
321 XBT_DEBUG("Process %p is in done set", req->issuer);
328 if(MC_state_interleave_size(current_state->graph_state)){
329 MC_restore_snapshot(current_state->system_state);
330 xbt_fifo_unshift(mc_snapshot_stack, current_state);
331 XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_snapshot_stack));
347 /************ DPOR 2 (invisible and independant transitions) ************/
349 xbt_dynar_t reached_pairs_prop;
350 xbt_dynar_t visible_transitions;
351 xbt_dynar_t enabled_processes;
353 mc_prop_ato_t new_proposition(char* id, int value){
354 mc_prop_ato_t prop = NULL;
355 prop = xbt_new0(s_mc_prop_ato_t, 1);
356 prop->id = strdup(id);
361 mc_pair_prop_t new_pair_prop(mc_snapshot_t sn, mc_state_t sg, xbt_state_t st){
362 mc_pair_prop_t pair = NULL;
363 pair = xbt_new0(s_mc_pair_prop_t, 1);
364 pair->system_state = sn;
365 pair->automaton_state = st;
366 pair->graph_state = sg;
367 pair->propositions = xbt_dynar_new(sizeof(mc_prop_ato_t), NULL);
368 pair->fully_expanded = 0;
369 pair->interleave = 0;
370 mc_stats_pair->expanded_pairs++;
374 int reached_prop(mc_pair_prop_t pair){
376 char* hash_reached = malloc(sizeof(char)*160);
380 char *hash = malloc(sizeof(char)*160);
381 xbt_sha((char *)&pair, hash);
382 xbt_dynar_foreach(reached_pairs_prop, c, hash_reached){
383 if(strcmp(hash, hash_reached) == 0){
393 void set_pair_prop_reached(mc_pair_prop_t pair){
395 if(reached_prop(pair) == 0){
397 char *hash = malloc(sizeof(char)*160) ;
398 xbt_sha((char *)&pair, hash);
399 xbt_dynar_push(reached_pairs_prop, &hash);
405 int invisible(mc_pair_prop_t p, mc_pair_prop_t np){
409 for(i=0;i<xbt_dynar_length(p->propositions); i++){
410 prop1 = xbt_dynar_get_as(p->propositions, i, mc_prop_ato_t);
411 prop2 = xbt_dynar_get_as(np->propositions, i, mc_prop_ato_t);
412 //XBT_DEBUG("test invisible : prop 1 = %s : %d / prop 2 = %s : %d", prop1->id, prop1->value, prop2->id, prop2->value);
413 if(prop1->value != prop2->value)
420 void set_fully_expanded(mc_pair_prop_t pair){
421 pair->fully_expanded = 1;
424 void MC_dpor2_init(xbt_automaton_t a)
426 mc_pair_prop_t initial_pair = NULL;
427 mc_state_t initial_graph_state = NULL;
428 mc_snapshot_t initial_system_state = NULL;
429 xbt_state_t initial_automaton_state = NULL;
433 initial_graph_state = MC_state_new();
436 /* Wait for requests (schedules processes) */
437 MC_wait_for_requests();
439 unsigned int cursor = 0;
440 unsigned int cursor2 = 0;
441 xbt_state_t automaton_state = NULL;
443 xbt_transition_t transition_succ;
445 xbt_dynar_foreach(a->states, cursor, automaton_state){
446 if(automaton_state->type == -1){
447 xbt_dynar_foreach(automaton_state->out, cursor2, transition_succ){
448 res = MC_automaton_evaluate_label(a, transition_succ->label);
449 if((res == 1) || (res == 2)){
450 initial_automaton_state = transition_succ->dst;
456 if(xbt_fifo_size(mc_snapshot_stack) > 0)
460 if(xbt_fifo_size(mc_snapshot_stack) == 0){
462 xbt_dynar_foreach(a->states, cursor, automaton_state){
463 if(automaton_state->type == -1){
464 initial_automaton_state = automaton_state;
470 reached_pairs_prop = xbt_dynar_new(sizeof(char *), NULL);
471 visible_transitions = xbt_dynar_new(sizeof(s_smx_req_t), NULL);
472 enabled_processes = xbt_dynar_new(sizeof(smx_process_t), NULL);
475 initial_system_state = xbt_new0(s_mc_snapshot_t, 1);
476 MC_take_snapshot(initial_system_state);
477 initial_pair = new_pair_prop(initial_system_state, initial_graph_state, initial_automaton_state);
479 xbt_propositional_symbol_t ps;
480 xbt_dynar_foreach(a->propositional_symbols, cursor, ps){
481 int (*f)() = ps->function;
483 mc_prop_ato_t pa = new_proposition(ps->pred, val);
484 xbt_dynar_push(initial_pair->propositions, &pa);
486 xbt_fifo_unshift(mc_snapshot_stack, initial_pair);
490 XBT_DEBUG("**************************************************");
491 XBT_DEBUG("Initial pair");
498 void MC_dpor2(xbt_automaton_t a, int search_cycle)
502 smx_req_t req = NULL, prev_req = NULL;
503 mc_state_t next_graph_state = NULL;
504 mc_snapshot_t next_system_state = NULL;
505 xbt_state_t next_automaton_state = NULL;
506 xbt_transition_t transition_succ;
509 mc_pair_prop_t pair = NULL, next_pair = NULL, prev_pair = NULL;
510 smx_process_t process = NULL;
511 xbt_fifo_item_t item = NULL;
515 while (xbt_fifo_size(mc_snapshot_stack) > 0) {
517 /* Get current pair */
518 pair = (mc_pair_prop_t)
519 xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_snapshot_stack));
521 XBT_DEBUG("**************************************************");
522 XBT_DEBUG("Exploration depth=%d (pair=%p) (%d interleave)",
523 xbt_fifo_size(mc_snapshot_stack), pair, MC_state_interleave_size(pair->graph_state));
525 if(MC_state_interleave_size(pair->graph_state) == 0){
527 xbt_dynar_reset(enabled_processes);
531 xbt_swag_foreach(process, simix_global->process_list){
532 if(MC_process_is_enabled(process)){
533 xbt_dynar_push(enabled_processes, &process);
534 //XBT_DEBUG("Process : pid=%lu",process->pid);
538 XBT_DEBUG("Enabled processes before pop : %lu", xbt_dynar_length(enabled_processes));
540 XBT_DEBUG("Processes already interleaved : %d", pair->interleave);
542 if(xbt_dynar_length(enabled_processes) > 0){
543 for(d=0;d<pair->interleave;d++){
544 xbt_dynar_shift(enabled_processes, NULL);
548 XBT_DEBUG("Enabled processes after pop : %lu", xbt_dynar_length(enabled_processes));
550 if(pair->fully_expanded == 0){
551 if(xbt_dynar_length(enabled_processes) > 0){
552 MC_state_interleave_process(pair->graph_state, xbt_dynar_get_as(enabled_processes, 0, smx_process_t));
553 //XBT_DEBUG("Interleave process");
562 /* Update statistics */
563 mc_stats_pair->visited_pairs++;
568 xbt_dynar_foreach(pair->propositions, cursor, pato){
569 XBT_DEBUG("%s : %d", pato->id, pato->value);
572 /* Test acceptance pair and acceptance cycle*/
574 if(pair->automaton_state->type == 1){
575 if(search_cycle == 0){
576 set_pair_prop_reached(pair);
577 XBT_DEBUG("Acceptance pair : graph=%p, automaton=%p(%s)", pair->graph_state, pair->automaton_state, pair->automaton_state->id);
579 if(reached_prop(pair) == 1){
580 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
581 XBT_INFO("| ACCEPTANCE CYCLE |");
582 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
583 XBT_INFO("Counter-example that violates formula :");
584 MC_show_snapshot_stack(mc_snapshot_stack);
585 MC_dump_snapshot_stack(mc_snapshot_stack);
586 MC_print_statistics_pairs(mc_stats_pair);
592 /* If there are processes to interleave and the maximum depth has not been reached
593 then perform one step of the exploration algorithm */
594 if (xbt_fifo_size(mc_snapshot_stack) < MAX_DEPTH &&
595 (req = MC_state_get_request(pair->graph_state, &value))) {
597 /* Debug information */
598 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
599 req_str = MC_request_to_string(req, value);
600 XBT_DEBUG("Execute: %s", req_str);
604 MC_state_set_executed_request(pair->graph_state, req, value);
605 //mc_stats_pairs->executed_transitions++;
607 /* Answer the request */
608 SIMIX_request_pre(req, value); /* After this call req is no longer usefull */
610 /* Wait for requests (schedules processes) */
611 MC_wait_for_requests();
613 /* Create the new expanded state */
617 //XBT_DEBUG("Process interleaved in pair %p : %u", pair, MC_state_interleave_size(pair->graph_state));
618 //xbt_dynar_pop(enabled_processes, NULL);
620 next_graph_state = MC_state_new();
622 next_system_state = xbt_new0(s_mc_snapshot_t, 1);
623 MC_take_snapshot(next_system_state);
627 xbt_dynar_foreach(pair->automaton_state->out, cursor, transition_succ){
628 res = MC_automaton_evaluate_label(a, transition_succ->label);
629 if((res == 1) || (res == 2)){ // enabled transition in automaton
630 next_automaton_state = transition_succ->dst;
635 if(next_automaton_state == NULL){
636 next_automaton_state = pair->automaton_state;
641 next_pair = new_pair_prop(next_system_state, next_graph_state, next_automaton_state);
643 xbt_propositional_symbol_t ps;
644 xbt_dynar_foreach(a->propositional_symbols, cursor, ps){
645 int (*f)() = ps->function;
647 mc_prop_ato_t pa = new_proposition(ps->pred, val);
648 xbt_dynar_push(next_pair->propositions, &pa);
649 //XBT_DEBUG("%s : %d", pa->id, pa->value);
651 xbt_fifo_unshift(mc_snapshot_stack, next_pair);
654 if((invisible(pair, next_pair) == 0) && (pair->fully_expanded == 0)){
655 set_fully_expanded(pair);
656 if(xbt_dynar_length(enabled_processes) > 1){ // Si 1 seul process activé, déjà exécuté juste avant donc état complètement étudié
657 xbt_dynar_foreach(enabled_processes, cursor, process){
658 MC_state_interleave_process(pair->graph_state, process);
661 XBT_DEBUG("Pair %p fully expanded (%u interleave)", pair, MC_state_interleave_size(pair->graph_state));
667 /* Let's loop again */
669 /* The interleave set is empty or the maximum depth is reached, let's back-track */
671 XBT_DEBUG("There are no more processes to interleave.");
673 /* Trash the current state, no longer needed */
675 xbt_fifo_shift(mc_snapshot_stack);
676 //MC_state_delete(state);
679 /* Check for deadlocks */
680 if(MC_deadlock_check()){
681 MC_show_deadlock(NULL);
686 /* Traverse the stack backwards until a state with a non empty interleave
687 set is found, deleting all the states that have it empty in the way.
688 For each deleted state, check if the request that has generated it
689 (from it's predecesor state), depends on any other previous request
690 executed before it. If it does then add it to the interleave set of the
691 state that executed that previous request. */
692 while ((pair = xbt_fifo_shift(mc_snapshot_stack)) != NULL) {
693 req = MC_state_get_internal_request(pair->graph_state);
694 xbt_fifo_foreach(mc_snapshot_stack, item, prev_pair, mc_pair_prop_t) {
695 if(MC_request_depend(req, MC_state_get_internal_request(prev_pair->graph_state))){
696 if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
697 XBT_DEBUG("Dependent Transitions:");
698 prev_req = MC_state_get_executed_request(prev_pair->graph_state, &value);
699 req_str = MC_request_to_string(prev_req, value);
700 XBT_DEBUG("%s (pair=%p)", req_str, prev_pair);
702 prev_req = MC_state_get_executed_request(pair->graph_state, &value);
703 req_str = MC_request_to_string(prev_req, value);
704 XBT_DEBUG("%s (pair=%p)", req_str, pair);
708 if(prev_pair->fully_expanded == 0){
709 if(!MC_state_process_is_done(prev_pair->graph_state, req->issuer)){
710 MC_state_interleave_process(prev_pair->graph_state, req->issuer);
711 XBT_DEBUG("Process %p (%lu) interleaved in pair %p", req->issuer, req->issuer->pid, prev_pair);
713 XBT_DEBUG("Process %p (%lu) is in done set", req->issuer, req->issuer->pid);
722 if (MC_state_interleave_size(pair->graph_state) > 0) {
723 /* We found a back-tracking point, let's loop */
724 MC_restore_snapshot(pair->system_state);
725 xbt_fifo_unshift(mc_snapshot_stack, pair);
726 XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_snapshot_stack));
730 //MC_state_delete(state);