Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
model-checker : DPOR (independant transitions) algorithm for liveness properties
[simgrid.git] / src / mc / mc_dpor.c
1 /* Copyright (c) 2008 Martin Quinson, Cristian Rosa.
2    All rights reserved.                                          */
3
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. */
6
7 #include "private.h"
8
9 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dpor, mc,
10                                 "Logging specific to MC DPOR exploration");
11
12 /**
13  *  \brief Initialize the DPOR exploration algorithm
14  */
15 void MC_dpor_init()
16 {
17   mc_state_t initial_state = NULL;
18   smx_process_t process;
19   
20   /* Create the initial state and push it into the exploration stack */
21   MC_SET_RAW_MEM;
22   initial_state = MC_state_new();
23   xbt_fifo_unshift(mc_stack, initial_state);
24   MC_UNSET_RAW_MEM;
25
26   XBT_DEBUG("**************************************************");
27   XBT_DEBUG("Initial state");
28
29   /* Wait for requests (schedules processes) */
30   MC_wait_for_requests();
31
32   MC_SET_RAW_MEM;
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);
37       break;
38     }
39   }
40   MC_UNSET_RAW_MEM;
41     
42   /* FIXME: Update Statistics 
43   mc_stats->state_size +=
44       xbt_setset_set_size(initial_state->enabled_transitions); */
45 }
46
47
48 /**
49  *      \brief Perform the model-checking operation using a depth-first search exploration
50  *         with Dynamic Partial Order Reductions
51  */
52 void MC_dpor(void)
53 {
54   char *req_str;
55   int value;
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;
60
61   while (xbt_fifo_size(mc_stack) > 0) {
62
63     /* Get current state */
64     state = (mc_state_t) 
65       xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
66
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));
71
72     /* Update statistics */
73     mc_stats->visited_states++;
74
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))) {
79
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);
84         xbt_free(req_str);
85       }
86
87       MC_state_set_executed_request(state, req, value);
88       mc_stats->executed_transitions++;
89
90       /* Answer the request */
91       SIMIX_request_pre(req, value); /* After this call req is no longer usefull */
92
93       /* Wait for requests (schedules processes) */
94       MC_wait_for_requests();
95
96       /* Create the new expanded state */
97       MC_SET_RAW_MEM;
98       next_state = MC_state_new();
99       xbt_fifo_unshift(mc_stack, next_state);
100
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);
105           break;
106         }
107       }
108       MC_UNSET_RAW_MEM;
109
110       /* FIXME: Update Statistics
111       mc_stats->state_size +=
112           xbt_setset_set_size(next_state->enabled_transitions);*/
113
114       /* Let's loop again */
115
116       /* The interleave set is empty or the maximum depth is reached, let's back-track */
117     } else {
118       XBT_DEBUG("There are no more processes to interleave.");
119
120       /* Trash the current state, no longer needed */
121       MC_SET_RAW_MEM;
122       xbt_fifo_shift(mc_stack);
123       MC_state_delete(state);
124       MC_UNSET_RAW_MEM;
125
126       /* Check for deadlocks */
127       if(MC_deadlock_check()){
128         MC_show_deadlock(NULL);
129         return;
130       }
131
132       MC_SET_RAW_MEM;
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);
148               xbt_free(req_str);
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);
152               xbt_free(req_str);              
153             }
154
155             if(!MC_state_process_is_done(prev_state, req->issuer))
156               MC_state_interleave_process(prev_state, req->issuer);
157             else
158               XBT_DEBUG("Process %p is in done set", req->issuer);
159
160             break;
161           }
162         }
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));
167           MC_UNSET_RAW_MEM;
168           MC_replay(mc_stack);
169           break;
170         } else {
171           MC_state_delete(state);
172         }
173       }
174       MC_UNSET_RAW_MEM;
175     }
176   }
177   MC_UNSET_RAW_MEM;
178   return;
179 }
180
181
182 /********************* DPOR without replay *********************/
183
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;
189   return sws;
190 }
191
192 void MC_dpor_with_restore_snapshot_init(){
193
194   XBT_DEBUG("**************************************************");
195   XBT_DEBUG("DPOR (with restore snapshot) init");
196   XBT_DEBUG("**************************************************");
197
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 ;
202   
203   MC_wait_for_requests();
204
205   MC_SET_RAW_MEM;
206
207   initial_system_snapshot = xbt_new0(s_mc_snapshot_t, 1);
208
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);
213       break;
214     }
215   }
216
217   MC_take_snapshot(initial_system_snapshot);
218
219   initial_state = new_state_ws(initial_system_snapshot, initial_graph_state);
220   xbt_fifo_unshift(mc_snapshot_stack, initial_state);
221
222   MC_UNSET_RAW_MEM;
223           
224   MC_dpor_with_restore_snapshot();
225
226 }
227
228 void MC_dpor_with_restore_snapshot(){
229
230   smx_process_t process = NULL;
231   
232   if(xbt_fifo_size(mc_snapshot_stack) == 0)
233     return;
234
235   int value;
236   mc_state_t next_graph_state = NULL;
237   smx_req_t req = NULL, prev_req = NULL;
238   char *req_str;
239   xbt_fifo_item_t item = NULL;
240
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;
245  
246   while(xbt_fifo_size(mc_snapshot_stack) > 0){
247
248     current_state = (mc_state_ws_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_snapshot_stack));
249
250     
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));
253     
254
255     if((xbt_fifo_size(mc_snapshot_stack) < MAX_DEPTH) && (req = MC_state_get_request(current_state->graph_state, &value))){
256
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);
261         xbt_free(req_str);
262       }
263
264       MC_state_set_executed_request(current_state->graph_state, req, value);
265
266       /* Answer the request */
267       SIMIX_request_pre(req, value);
268       
269       /* Wait for requests (schedules processes) */
270       MC_wait_for_requests();
271       
272       /* Create the new expanded graph_state */
273       MC_SET_RAW_MEM;
274       
275       next_graph_state = MC_state_new();
276       
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);
281           break;
282         }
283       }
284
285       next_snapshot = xbt_new0(s_mc_snapshot_t, 1);
286       MC_take_snapshot(next_snapshot);
287
288       next_state = new_state_ws(next_snapshot, next_graph_state);
289       xbt_fifo_unshift(mc_snapshot_stack, next_state);
290       
291       MC_UNSET_RAW_MEM;
292
293     }else{
294       XBT_DEBUG("There are no more processes to interleave.");
295       
296       /* Trash the current state, no longer needed */
297       MC_SET_RAW_MEM;
298       xbt_fifo_shift(mc_snapshot_stack);
299       MC_UNSET_RAW_MEM;
300
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);
310               xbt_free(req_str);
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);
314               xbt_free(req_str);              
315             }
316
317             if(!MC_state_process_is_done(prev_state->graph_state, req->issuer)){
318               MC_state_interleave_process(prev_state->graph_state, req->issuer);
319               
320             } else {
321               XBT_DEBUG("Process %p is in done set", req->issuer);
322             }
323
324             break;
325           }
326         }
327
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));
332           MC_UNSET_RAW_MEM;
333           break;
334         }
335       }
336
337       MC_UNSET_RAW_MEM;
338
339     } 
340   }
341   MC_UNSET_RAW_MEM;
342   return;
343 }
344
345
346
347 /************ DPOR 2 (invisible and independant transitions) ************/
348
349
350 void MC_dpor2_init(xbt_automaton_t a)
351 {
352   mc_pair_t initial_pair = NULL;
353   mc_state_t initial_graph_state = NULL;
354   mc_snapshot_t initial_system_state = NULL;
355   xbt_state_t initial_automaton_state = NULL;
356   smx_process_t process;
357   
358
359   MC_SET_RAW_MEM;
360   initial_graph_state = MC_state_new();
361   MC_UNSET_RAW_MEM;
362
363   /* Wait for requests (schedules processes) */
364   MC_wait_for_requests();
365
366   MC_SET_RAW_MEM;
367   xbt_swag_foreach(process, simix_global->process_list){
368     if(MC_process_is_enabled(process)){
369       MC_state_interleave_process(initial_graph_state, process);
370       break;
371     }
372   }
373   MC_UNSET_RAW_MEM;
374
375   unsigned int cursor = 0;
376   unsigned int cursor2 = 0;
377   xbt_state_t automaton_state = NULL;
378   int res;
379   xbt_transition_t transition_succ;
380
381   xbt_dynar_foreach(a->states, cursor, automaton_state){
382     if(automaton_state->type == -1){
383       xbt_dynar_foreach(automaton_state->out, cursor2, transition_succ){
384         res = MC_automaton_evaluate_label(a, transition_succ->label);
385         if((res == 1) || (res == 2)){
386           initial_automaton_state = transition_succ->dst;
387           break;
388         }
389       }
390     }
391
392     if(xbt_fifo_size(mc_snapshot_stack) > 0)
393       break;
394   }
395
396   if(xbt_fifo_size(mc_snapshot_stack) == 0){
397     cursor = 0;
398     xbt_dynar_foreach(a->states, cursor, automaton_state){
399       if(automaton_state->type == -1){
400         initial_automaton_state = automaton_state;
401         break;
402       }
403     }
404   }
405
406   MC_SET_RAW_MEM;
407   initial_system_state = xbt_new0(s_mc_snapshot_t, 1);
408   MC_take_snapshot(initial_system_state);
409   initial_pair = new_pair(initial_system_state, initial_graph_state, initial_automaton_state);
410   xbt_fifo_unshift(mc_snapshot_stack, initial_pair);
411   MC_UNSET_RAW_MEM;
412
413   XBT_DEBUG("**************************************************");
414   XBT_DEBUG("Initial pair");
415
416   MC_dpor2(a, 0);
417     
418 }
419
420
421 void MC_dpor2(xbt_automaton_t a, int search_cycle)
422 {
423   char *req_str;
424   int value;
425   smx_req_t req = NULL, prev_req = NULL;
426   mc_state_t next_graph_state = NULL;
427   mc_snapshot_t next_system_state = NULL;
428   xbt_state_t next_automaton_state = NULL;
429   xbt_transition_t transition_succ;
430   unsigned int cursor;
431   int res;
432   mc_pair_t pair = NULL, next_pair = NULL, prev_pair = NULL;
433   smx_process_t process = NULL;
434   xbt_fifo_item_t item = NULL;
435
436   while (xbt_fifo_size(mc_snapshot_stack) > 0) {
437
438     /* Get current pair */
439     pair = (mc_pair_t) 
440       xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_snapshot_stack));
441
442     XBT_DEBUG("**************************************************");
443     XBT_DEBUG("Exploration depth=%d (pair=%p)(%u interleave)",
444            xbt_fifo_size(mc_snapshot_stack), pair,
445            MC_state_interleave_size(pair->graph_state));
446
447     /* Update statistics */
448     mc_stats_pair->visited_pairs++;
449
450     /* Test acceptance pair and acceptance cycle*/
451
452     if(pair->automaton_state->type == 1){
453       if(search_cycle == 0){
454         set_pair_reached(pair);
455         XBT_DEBUG("Acceptance pair : graph=%p, automaton=%p(%s)", pair->graph_state, pair->automaton_state, pair->automaton_state->id);
456       }else{
457         if(reached(pair) == 1){
458           XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
459           XBT_INFO("|             ACCEPTANCE CYCLE            |");
460           XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
461           XBT_INFO("Counter-example that violates formula :");
462           MC_show_snapshot_stack(mc_snapshot_stack);
463           MC_dump_snapshot_stack(mc_snapshot_stack);
464           MC_print_statistics_pairs(mc_stats_pair);
465           exit(0);
466         }
467       }
468     }
469
470     /* If there are processes to interleave and the maximum depth has not been reached
471        then perform one step of the exploration algorithm */
472     if (xbt_fifo_size(mc_snapshot_stack) < MAX_DEPTH &&
473         (req = MC_state_get_request(pair->graph_state, &value))) {
474
475       /* Debug information */
476       if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
477         req_str = MC_request_to_string(req, value);
478         XBT_DEBUG("Execute: %s", req_str);
479         xbt_free(req_str);
480       }
481
482       MC_state_set_executed_request(pair->graph_state, req, value);
483       //mc_stats_pairs->executed_transitions++;
484
485       /* Answer the request */
486       SIMIX_request_pre(req, value); /* After this call req is no longer usefull */
487
488       /* Wait for requests (schedules processes) */
489       MC_wait_for_requests();
490
491       /* Create the new expanded state */
492       MC_SET_RAW_MEM;
493       next_graph_state = MC_state_new();
494
495       /* Get an enabled process and insert it in the interleave set of the next state */
496       xbt_swag_foreach(process, simix_global->process_list){
497         if(MC_process_is_enabled(process)){
498           MC_state_interleave_process(next_graph_state, process);
499           break;
500         }
501       }
502
503       next_system_state = xbt_new0(s_mc_snapshot_t, 1);
504       MC_take_snapshot(next_system_state);
505       MC_UNSET_RAW_MEM;
506
507       cursor = 0;
508       xbt_dynar_foreach(pair->automaton_state->out, cursor, transition_succ){
509         res = MC_automaton_evaluate_label(a, transition_succ->label);   
510         if((res == 1) || (res == 2)){ // enabled transition in automaton
511           next_automaton_state = transition_succ->dst;
512           break;
513         }
514       }
515
516       if(next_automaton_state == NULL){
517         next_automaton_state = pair->automaton_state;
518       }
519       
520       MC_SET_RAW_MEM;
521       next_pair = new_pair(next_system_state, next_graph_state, next_automaton_state);
522       xbt_fifo_unshift(mc_snapshot_stack, next_pair);
523       MC_UNSET_RAW_MEM;
524
525       /* Let's loop again */
526
527       /* The interleave set is empty or the maximum depth is reached, let's back-track */
528     } else {
529       XBT_DEBUG("There are no more processes to interleave.");
530
531       /* Trash the current state, no longer needed */
532       MC_SET_RAW_MEM;
533       xbt_fifo_shift(mc_snapshot_stack);
534       //MC_state_delete(state);
535       MC_UNSET_RAW_MEM;
536
537       /* Check for deadlocks */
538       if(MC_deadlock_check()){
539         MC_show_deadlock(NULL);
540         return;
541       }
542
543       MC_SET_RAW_MEM;
544       /* Traverse the stack backwards until a state with a non empty interleave
545          set is found, deleting all the states that have it empty in the way.
546          For each deleted state, check if the request that has generated it 
547          (from it's predecesor state), depends on any other previous request 
548          executed before it. If it does then add it to the interleave set of the
549          state that executed that previous request. */
550       while ((pair = xbt_fifo_shift(mc_snapshot_stack)) != NULL) {
551         req = MC_state_get_internal_request(pair->graph_state);
552         xbt_fifo_foreach(mc_snapshot_stack, item, prev_pair, mc_pair_t) {
553           if(MC_request_depend(req, MC_state_get_internal_request(prev_pair->graph_state))){
554             if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
555               XBT_DEBUG("Dependent Transitions:");
556               prev_req = MC_state_get_executed_request(prev_pair->graph_state, &value);
557               req_str = MC_request_to_string(prev_req, value);
558               XBT_DEBUG("%s (pair=%p)", req_str, prev_pair);
559               xbt_free(req_str);
560               prev_req = MC_state_get_executed_request(pair->graph_state, &value);
561               req_str = MC_request_to_string(prev_req, value);
562               XBT_DEBUG("%s (pair=%p)", req_str, pair);
563               xbt_free(req_str);              
564             }
565
566             if(!MC_state_process_is_done(prev_pair->graph_state, req->issuer))
567               MC_state_interleave_process(prev_pair->graph_state, req->issuer);
568             else
569               XBT_DEBUG("Process %p is in done set", req->issuer);
570
571             break;
572           }
573         }
574         if (MC_state_interleave_size(pair->graph_state)) {
575           /* We found a back-tracking point, let's loop */
576           MC_restore_snapshot(pair->system_state);
577           xbt_fifo_unshift(mc_snapshot_stack, pair);
578           XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_snapshot_stack));
579           MC_UNSET_RAW_MEM;
580           break;
581         } else {
582           //MC_state_delete(state);
583         }
584       }
585       MC_UNSET_RAW_MEM;
586     }
587   }
588   MC_UNSET_RAW_MEM;
589   return;
590 }