Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
model-checker : application alert for state equality detection
[simgrid.git] / src / mc / mc_global.c
1 /* Copyright (c) 2008-2012 Da SimGrid Team. All rights reserved.            */
2
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. */
5
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <sys/time.h>
10
11 #include "../surf/surf_private.h"
12 #include "../simix/smx_private.h"
13 #include "xbt/fifo.h"
14 #include "mc_private.h"
15 #include "xbt/automaton.h"
16
17 XBT_LOG_NEW_CATEGORY(mc, "All MC categories");
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_global, mc,
19                                 "Logging specific to MC (global)");
20
21 /* Configuration support */
22 e_mc_reduce_t mc_reduce_kind=e_mc_reduce_unset;
23
24 extern int _surf_init_status;
25 void _mc_cfg_cb_reduce(const char *name, int pos) {
26   if (_surf_init_status && !_surf_do_model_check) {
27     xbt_die("You are specifying a reduction strategy after the initialization (through MSG_config?), but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
28   }
29   char *val= xbt_cfg_get_string(_surf_cfg_set, name);
30   if (!strcasecmp(val,"none")) {
31     mc_reduce_kind = e_mc_reduce_none;
32   } else if (!strcasecmp(val,"dpor")) {
33     mc_reduce_kind = e_mc_reduce_dpor;
34   } else {
35     xbt_die("configuration option %s can only take 'none' or 'dpor' as a value",name);
36   }
37   xbt_cfg_set_int(_surf_cfg_set,"model-check",1);
38 }
39
40 void _mc_cfg_cb_checkpoint(const char *name, int pos) {
41   if (_surf_init_status && !_surf_do_model_check) {
42     xbt_die("You are specifying a checkpointing value after the initialization (through MSG_config?), but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
43   }
44   _surf_mc_checkpoint = xbt_cfg_get_int(_surf_cfg_set, name);
45   xbt_cfg_set_int(_surf_cfg_set,"model-check",1);
46 }
47 void _mc_cfg_cb_property(const char *name, int pos) {
48   if (_surf_init_status && !_surf_do_model_check) {
49     xbt_die("You are specifying a property after the initialization (through MSG_config?), but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
50   }
51   _surf_mc_property_file= xbt_cfg_get_string(_surf_cfg_set, name);
52   xbt_cfg_set_int(_surf_cfg_set,"model-check",1);
53 }
54
55
56 /* MC global data structures */
57
58 mc_state_t mc_current_state = NULL;
59 char mc_replay_mode = FALSE;
60 double *mc_time = NULL;
61 mc_snapshot_t initial_snapshot = NULL;
62 int raw_mem_set;
63
64 /* Safety */
65
66 xbt_fifo_t mc_stack_safety = NULL;
67 mc_stats_t mc_stats = NULL;
68
69 /* Liveness */
70
71 mc_stats_pair_t mc_stats_pair = NULL;
72 xbt_fifo_t mc_stack_liveness = NULL;
73 mc_snapshot_t initial_snapshot_liveness = NULL;
74 int compare;
75
76 xbt_automaton_t _mc_property_automaton = NULL;
77
78 static void MC_assert_pair(int prop);
79
80 void MC_do_the_modelcheck_for_real() {
81   if (!_surf_mc_property_file || _surf_mc_property_file[0]=='\0') {
82     if (mc_reduce_kind==e_mc_reduce_unset)
83       mc_reduce_kind=e_mc_reduce_dpor;
84
85     XBT_INFO("Check a safety property");
86     MC_modelcheck();
87
88   } else  {
89
90     if (mc_reduce_kind==e_mc_reduce_unset)
91       mc_reduce_kind=e_mc_reduce_none;
92
93     XBT_INFO("Check the liveness property %s",_surf_mc_property_file);
94     MC_automaton_load(_surf_mc_property_file);
95     MC_modelcheck_liveness();
96   }
97 }
98
99 /**
100  *  \brief Initialize the model-checker data structures
101  */
102 void MC_init_safety(void)
103 {
104
105   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
106
107   /* Check if MC is already initialized */
108   if (initial_snapshot)
109     return;
110
111   mc_time = xbt_new0(double, simix_process_maxpid);
112
113   /* Initialize the data structures that must be persistent across every
114      iteration of the model-checker (in RAW memory) */
115   
116   MC_SET_RAW_MEM;
117
118   /* Initialize statistics */
119   mc_stats = xbt_new0(s_mc_stats_t, 1);
120   mc_stats->state_size = 1;
121
122   /* Create exploration stack */
123   mc_stack_safety = xbt_fifo_new();
124
125   MC_UNSET_RAW_MEM;
126
127   MC_dpor_init();
128
129   MC_SET_RAW_MEM;
130   /* Save the initial state */
131   initial_snapshot = xbt_new0(s_mc_snapshot_t, 1);
132   MC_take_snapshot(initial_snapshot);
133   MC_UNSET_RAW_MEM;
134
135
136   if(raw_mem_set)
137     MC_SET_RAW_MEM;
138   else
139     MC_UNSET_RAW_MEM;
140   
141 }
142
143 void MC_compare(void){
144   compare = 1;
145 }
146
147
148 void MC_modelcheck(void)
149 {
150   MC_init_safety();
151   MC_dpor();
152   MC_exit();
153 }
154
155 void MC_modelcheck_liveness(){
156
157   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
158
159   /* init stuff */
160   XBT_DEBUG("Start init mc");
161   
162   mc_time = xbt_new0(double, simix_process_maxpid);
163
164   compare = 0;
165
166   /* Initialize the data structures that must be persistent across every
167      iteration of the model-checker (in RAW memory) */
168
169   MC_SET_RAW_MEM;
170
171   /* Initialize statistics */
172   mc_stats_pair = xbt_new0(s_mc_stats_pair_t, 1);
173
174   XBT_DEBUG("Creating stack");
175
176   /* Create exploration stack */
177   mc_stack_liveness = xbt_fifo_new();
178
179   MC_UNSET_RAW_MEM;
180
181
182   MC_ddfs_init();
183
184   /* We're done */
185   MC_print_statistics_pairs(mc_stats_pair);
186   xbt_free(mc_time);
187   MC_memory_exit();
188   exit(0);
189 }
190
191
192 void MC_exit(void)
193 {
194   MC_print_statistics(mc_stats);
195   xbt_free(mc_time);
196   MC_memory_exit();
197 }
198
199
200 int MC_random(int min, int max)
201 {
202   /*FIXME: return mc_current_state->executed_transition->random.value;*/
203   return 0;
204 }
205
206 /**
207  * \brief Schedules all the process that are ready to run
208  */
209 void MC_wait_for_requests(void)
210 {
211   smx_process_t process;
212   smx_simcall_t req;
213   unsigned int iter;
214
215   while (!xbt_dynar_is_empty(simix_global->process_to_run)) {
216     SIMIX_process_runall();
217     xbt_dynar_foreach(simix_global->process_that_ran, iter, process) {
218       req = &process->simcall;
219       if (req->call != SIMCALL_NONE && !MC_request_is_visible(req))
220         SIMIX_simcall_pre(req, 0);
221     }
222   }
223 }
224
225 int MC_deadlock_check()
226 {
227   int deadlock = FALSE;
228   smx_process_t process;
229   if(xbt_swag_size(simix_global->process_list)){
230     deadlock = TRUE;
231     xbt_swag_foreach(process, simix_global->process_list){
232       if(process->simcall.call != SIMCALL_NONE
233          && MC_request_is_enabled(&process->simcall)){
234         deadlock = FALSE;
235         break;
236       }
237     }
238   }
239   return deadlock;
240 }
241
242 /**
243  * \brief Re-executes from the state at position start all the transitions indicated by
244  *        a given model-checker stack.
245  * \param stack The stack with the transitions to execute.
246  * \param start Start index to begin the re-execution.
247  */
248 void MC_replay(xbt_fifo_t stack, int start)
249 {
250   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
251
252   int value, i = 1;
253   char *req_str;
254   smx_simcall_t req = NULL, saved_req = NULL;
255   xbt_fifo_item_t item, start_item;
256   mc_state_t state;
257
258   XBT_DEBUG("**** Begin Replay ****");
259
260   if(start == -1){
261     /* Restore the initial state */
262     MC_restore_snapshot(initial_snapshot);
263     /* At the moment of taking the snapshot the raw heap was set, so restoring
264      * it will set it back again, we have to unset it to continue  */
265     MC_UNSET_RAW_MEM;
266   }
267
268   start_item = xbt_fifo_get_last_item(stack);
269   if(start != -1){
270     while (i != start){
271       start_item = xbt_fifo_get_prev_item(start_item);
272       i++;
273     }
274   }
275
276   /* Traverse the stack from the state at position start and re-execute the transitions */
277   for (item = start_item;
278        item != xbt_fifo_get_first_item(stack);
279        item = xbt_fifo_get_prev_item(item)) {
280
281     state = (mc_state_t) xbt_fifo_get_item_content(item);
282     saved_req = MC_state_get_executed_request(state, &value);
283    
284     if(saved_req){
285       /* because we got a copy of the executed request, we have to fetch the  
286          real one, pointed by the request field of the issuer process */
287       req = &saved_req->issuer->simcall;
288
289       /* Debug information */
290       if(XBT_LOG_ISENABLED(mc_global, xbt_log_priority_debug)){
291         req_str = MC_request_to_string(req, value);
292         XBT_DEBUG("Replay: %s (%p)", req_str, state);
293         xbt_free(req_str);
294       }
295     }
296          
297     SIMIX_simcall_pre(req, value);
298     MC_wait_for_requests();
299          
300     /* Update statistics */
301     mc_stats->visited_states++;
302     mc_stats->executed_transitions++;
303   }
304   XBT_DEBUG("**** End Replay ****");
305
306   if(raw_mem_set)
307     MC_SET_RAW_MEM;
308   else
309     MC_UNSET_RAW_MEM;
310   
311
312 }
313
314 void MC_replay_liveness(xbt_fifo_t stack, int all_stack)
315 {
316
317   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
318
319   int value;
320   char *req_str;
321   smx_simcall_t req = NULL, saved_req = NULL;
322   xbt_fifo_item_t item;
323   mc_state_t state;
324   mc_pair_stateless_t pair;
325   int depth = 1;
326
327   XBT_DEBUG("**** Begin Replay ****");
328
329   /* Restore the initial state */
330   MC_restore_snapshot(initial_snapshot_liveness);
331   /* At the moment of taking the snapshot the raw heap was set, so restoring
332    * it will set it back again, we have to unset it to continue  */
333   MC_UNSET_RAW_MEM;
334
335   if(all_stack){
336
337     item = xbt_fifo_get_last_item(stack);
338
339     while(depth <= xbt_fifo_size(stack)){
340
341       pair = (mc_pair_stateless_t) xbt_fifo_get_item_content(item);
342       state = (mc_state_t) pair->graph_state;
343
344       if(pair->requests > 0){
345    
346         saved_req = MC_state_get_executed_request(state, &value);
347         //XBT_DEBUG("SavedReq->call %u", saved_req->call);
348       
349         if(saved_req != NULL){
350           /* because we got a copy of the executed request, we have to fetch the  
351              real one, pointed by the request field of the issuer process */
352           req = &saved_req->issuer->simcall;
353           //XBT_DEBUG("Req->call %u", req->call);
354   
355           /* Debug information */
356           if(XBT_LOG_ISENABLED(mc_global, xbt_log_priority_debug)){
357             req_str = MC_request_to_string(req, value);
358             XBT_DEBUG("Replay (depth = %d) : %s (%p)", depth, req_str, state);
359             xbt_free(req_str);
360           }
361   
362         }
363  
364         SIMIX_simcall_pre(req, value);
365         MC_wait_for_requests();
366       }
367
368       depth++;
369     
370       /* Update statistics */
371       mc_stats_pair->visited_pairs++;
372
373       item = xbt_fifo_get_prev_item(item);
374     }
375
376   }else{
377
378     /* Traverse the stack from the initial state and re-execute the transitions */
379     for (item = xbt_fifo_get_last_item(stack);
380          item != xbt_fifo_get_first_item(stack);
381          item = xbt_fifo_get_prev_item(item)) {
382
383       pair = (mc_pair_stateless_t) xbt_fifo_get_item_content(item);
384       state = (mc_state_t) pair->graph_state;
385
386       if(pair->requests > 0){
387    
388         saved_req = MC_state_get_executed_request(state, &value);
389         //XBT_DEBUG("SavedReq->call %u", saved_req->call);
390       
391         if(saved_req != NULL){
392           /* because we got a copy of the executed request, we have to fetch the  
393              real one, pointed by the request field of the issuer process */
394           req = &saved_req->issuer->simcall;
395           //XBT_DEBUG("Req->call %u", req->call);
396   
397           /* Debug information */
398           if(XBT_LOG_ISENABLED(mc_global, xbt_log_priority_debug)){
399             req_str = MC_request_to_string(req, value);
400             XBT_DEBUG("Replay (depth = %d) : %s (%p)", depth, req_str, state);
401             xbt_free(req_str);
402           }
403   
404         }
405  
406         SIMIX_simcall_pre(req, value);
407         MC_wait_for_requests();
408       }
409
410       depth++;
411     
412       /* Update statistics */
413       mc_stats_pair->visited_pairs++;
414     }
415   }  
416
417   XBT_DEBUG("**** End Replay ****");
418
419   if(raw_mem_set)
420     MC_SET_RAW_MEM;
421   else
422     MC_UNSET_RAW_MEM;
423   
424 }
425
426 /**
427  * \brief Dumps the contents of a model-checker's stack and shows the actual
428  *        execution trace
429  * \param stack The stack to dump
430  */
431 void MC_dump_stack_safety(xbt_fifo_t stack)
432 {
433   
434   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
435
436   MC_show_stack_safety(stack);
437
438   if(!_surf_mc_checkpoint){
439
440     mc_state_t state;
441
442     MC_SET_RAW_MEM;
443     while ((state = (mc_state_t) xbt_fifo_pop(stack)) != NULL)
444       MC_state_delete(state);
445     MC_UNSET_RAW_MEM;
446
447   }
448
449   if(raw_mem_set)
450     MC_SET_RAW_MEM;
451   else
452     MC_UNSET_RAW_MEM;
453   
454 }
455
456
457 void MC_show_stack_safety(xbt_fifo_t stack)
458 {
459   int value;
460   mc_state_t state;
461   xbt_fifo_item_t item;
462   smx_simcall_t req;
463   char *req_str = NULL;
464   
465   for (item = xbt_fifo_get_last_item(stack);
466        (item ? (state = (mc_state_t) (xbt_fifo_get_item_content(item)))
467         : (NULL)); item = xbt_fifo_get_prev_item(item)) {
468     req = MC_state_get_executed_request(state, &value);
469     if(req){
470       req_str = MC_request_to_string(req, value);
471       XBT_INFO("%s", req_str);
472       xbt_free(req_str);
473     }
474   }
475 }
476
477 void MC_show_deadlock(smx_simcall_t req)
478 {
479   /*char *req_str = NULL;*/
480   XBT_INFO("**************************");
481   XBT_INFO("*** DEAD-LOCK DETECTED ***");
482   XBT_INFO("**************************");
483   XBT_INFO("Locked request:");
484   /*req_str = MC_request_to_string(req);
485     XBT_INFO("%s", req_str);
486     xbt_free(req_str);*/
487   XBT_INFO("Counter-example execution trace:");
488   MC_dump_stack_safety(mc_stack_safety);
489 }
490
491
492 void MC_show_stack_liveness(xbt_fifo_t stack){
493   int value;
494   mc_pair_stateless_t pair;
495   xbt_fifo_item_t item;
496   smx_simcall_t req;
497   char *req_str = NULL;
498   
499   for (item = xbt_fifo_get_last_item(stack);
500        (item ? (pair = (mc_pair_stateless_t) (xbt_fifo_get_item_content(item)))
501         : (NULL)); item = xbt_fifo_get_prev_item(item)) {
502     req = MC_state_get_executed_request(pair->graph_state, &value);
503     if(req){
504       if(pair->requests>0){
505         req_str = MC_request_to_string(req, value);
506         XBT_INFO("%s", req_str);
507         xbt_free(req_str);
508       }else{
509         XBT_INFO("End of system requests but evolution in B├╝chi automaton");
510       }
511     }
512   }
513 }
514
515 void MC_dump_stack_liveness(xbt_fifo_t stack){
516
517   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
518
519   mc_pair_stateless_t pair;
520
521   MC_SET_RAW_MEM;
522   while ((pair = (mc_pair_stateless_t) xbt_fifo_pop(stack)) != NULL)
523     MC_pair_stateless_delete(pair);
524   MC_UNSET_RAW_MEM;
525
526   if(raw_mem_set)
527     MC_SET_RAW_MEM;
528   else
529     MC_UNSET_RAW_MEM;
530
531 }
532
533
534 void MC_print_statistics(mc_stats_t stats)
535 {
536   //XBT_INFO("State space size ~= %lu", stats->state_size);
537   XBT_INFO("Expanded states = %lu", stats->expanded_states);
538   XBT_INFO("Visited states = %lu", stats->visited_states);
539   XBT_INFO("Executed transitions = %lu", stats->executed_transitions);
540   XBT_INFO("Expanded / Visited = %lf",
541            (double) stats->visited_states / stats->expanded_states);
542   /*XBT_INFO("Exploration coverage = %lf",
543     (double)stats->expanded_states / stats->state_size); */
544 }
545
546 void MC_print_statistics_pairs(mc_stats_pair_t stats)
547 {
548   XBT_INFO("Expanded pairs = %lu", stats->expanded_pairs);
549   XBT_INFO("Visited pairs = %lu", stats->visited_pairs);
550   //XBT_INFO("Executed transitions = %lu", stats->executed_transitions);
551   XBT_INFO("Expanded / Visited = %lf",
552            (double) stats->visited_pairs / stats->expanded_pairs);
553   /*XBT_INFO("Exploration coverage = %lf",
554     (double)stats->expanded_states / stats->state_size); */
555 }
556
557 void MC_assert(int prop)
558 {
559   if (MC_IS_ENABLED && !prop){
560     XBT_INFO("**************************");
561     XBT_INFO("*** PROPERTY NOT VALID ***");
562     XBT_INFO("**************************");
563     XBT_INFO("Counter-example execution trace:");
564     MC_dump_stack_safety(mc_stack_safety);
565     MC_print_statistics(mc_stats);
566     xbt_abort();
567   }
568 }
569
570 static void MC_assert_pair(int prop){
571   if (MC_IS_ENABLED && !prop) {
572     XBT_INFO("**************************");
573     XBT_INFO("*** PROPERTY NOT VALID ***");
574     XBT_INFO("**************************");
575     //XBT_INFO("Counter-example execution trace:");
576     MC_show_stack_liveness(mc_stack_liveness);
577     //MC_dump_snapshot_stack(mc_snapshot_stack);
578     MC_print_statistics_pairs(mc_stats_pair);
579     xbt_abort();
580   }
581 }
582
583 void MC_process_clock_add(smx_process_t process, double amount)
584 {
585   mc_time[process->pid] += amount;
586 }
587
588 double MC_process_clock_get(smx_process_t process)
589 {
590   if(mc_time)
591     return mc_time[process->pid];
592   else
593     return 0;
594 }
595
596 void MC_diff(void){
597
598   mc_snapshot_t sn = xbt_new0(s_mc_snapshot_t, 1);
599   MC_take_snapshot_liveness(sn);
600
601   int i;
602
603   XBT_INFO("Number of regions : %u", sn->num_reg);
604
605   for(i=0; i<sn->num_reg; i++){
606     
607     switch(sn->regions[i]->type){
608     case 0: /* heap */
609       XBT_INFO("Size of heap : %zu", sn->regions[i]->size);
610       break;
611     case 1 : /* libsimgrid */
612       XBT_INFO("Size of libsimgrid : %zu", sn->regions[i]->size);
613       break;
614     case 2 : /* data program */
615       XBT_INFO("Size of data program : %zu", sn->regions[i]->size);
616       break;
617     case 3 : /* stack */
618       XBT_INFO("Size of stack : %zu", sn->regions[i]->size);
619       XBT_INFO("Start addr of stack : %p", sn->regions[i]->start_addr);
620       break;
621     }
622
623   }
624
625 }
626
627 void MC_automaton_load(const char *file){
628
629   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
630
631   MC_SET_RAW_MEM;
632
633   if (_mc_property_automaton == NULL)
634     _mc_property_automaton = xbt_automaton_new();
635   
636   xbt_automaton_load(_mc_property_automaton,file);
637
638   MC_UNSET_RAW_MEM;
639
640   if(raw_mem_set)
641     MC_SET_RAW_MEM;
642   else
643     MC_UNSET_RAW_MEM;
644
645 }
646
647 void MC_automaton_new_propositional_symbol(const char* id, void* fct) {
648
649   raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
650
651   MC_SET_RAW_MEM;
652
653   if (_mc_property_automaton == NULL)
654     _mc_property_automaton = xbt_automaton_new();
655
656   xbt_new_propositional_symbol(_mc_property_automaton,id,fct);
657
658   MC_UNSET_RAW_MEM;
659
660   if(raw_mem_set)
661     MC_SET_RAW_MEM;
662   else
663     MC_UNSET_RAW_MEM;
664   
665 }