Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
41be27f17626dfeb598996fc65277dc67ce2d140
[simgrid.git] / src / mc / mc_liveness.cpp
1 /* Copyright (c) 2011-2014. The SimGrid Team.
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 <unistd.h>
8 #include <sys/wait.h>
9
10 #include <xbt/dynar.h>
11 #include <xbt/automaton.h>
12
13 #include "mc_request.h"
14 #include "mc_liveness.h"
15 #include "mc_private.h"
16 #include "mc_record.h"
17 #include "mc_smx.h"
18 #include "mc_client.h"
19 #include "mc_replay.h"
20 #include "mc_safety.h"
21
22 extern "C" {
23
24 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc,
25                                 "Logging specific to algorithms for liveness properties verification");
26
27 /********* Global variables *********/
28
29 xbt_dynar_t acceptance_pairs;
30 xbt_parmap_t parmap;
31
32 /********* Static functions *********/
33
34 static xbt_dynar_t get_atomic_propositions_values()
35 {
36   unsigned int cursor = 0;
37   xbt_automaton_propositional_symbol_t ps = NULL;
38   xbt_dynar_t values = xbt_dynar_new(sizeof(int), NULL);
39   xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, ps) {
40     int res = xbt_automaton_propositional_symbol_evaluate(ps);
41     xbt_dynar_push_as(values, int, res);
42   }
43
44   return values;
45 }
46
47 static mc_visited_pair_t is_reached_acceptance_pair(mc_pair_t pair) {
48   xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
49
50   mc_visited_pair_t new_pair = NULL;
51   new_pair = MC_visited_pair_new(pair->num, pair->automaton_state, pair->atomic_propositions, pair->graph_state);
52   new_pair->acceptance_pair = 1;
53
54   if (xbt_dynar_is_empty(acceptance_pairs)) {
55
56     xbt_dynar_push(acceptance_pairs, &new_pair);
57
58   } else {
59
60     int min = -1, max = -1, index;
61     //int res;
62     mc_visited_pair_t pair_test;
63     int cursor;
64
65     index = get_search_interval(acceptance_pairs, new_pair, &min, &max);
66
67     if (min != -1 && max != -1) {       // Acceptance pair with same number of processes and same heap bytes used exists
68
69       // Parallell implementation
70       /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(acceptance_pairs, min), (max-min)+1, pair);
71          if(res != -1){
72          if(!raw_mem_set)
73          MC_SET_STD_HEAP;
74          return ((mc_pair_t)xbt_dynar_get_as(acceptance_pairs, (min+res)-1, mc_pair_t))->num;
75          } */
76
77       cursor = min;
78       if(pair->search_cycle == 1){
79         while (cursor <= max) {
80           pair_test = (mc_visited_pair_t) xbt_dynar_get_as(acceptance_pairs, cursor, mc_visited_pair_t);
81           if (xbt_automaton_state_compare(pair_test->automaton_state, new_pair->automaton_state) == 0) {
82             if (xbt_automaton_propositional_symbols_compare_value(pair_test->atomic_propositions, new_pair->atomic_propositions) == 0) {
83               if (snapshot_compare(pair_test, new_pair) == 0) {
84                 XBT_INFO("Pair %d already reached (equal to pair %d) !", new_pair->num, pair_test->num);
85                 xbt_fifo_shift(mc_stack);
86                 if (dot_output != NULL)
87                   fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", initial_global_state->prev_pair, pair_test->num, initial_global_state->prev_req);
88                 mmalloc_set_current_heap(heap);
89                 return NULL;
90               }
91             }
92           }
93           cursor++;
94         }
95       }
96       xbt_dynar_insert_at(acceptance_pairs, min, &new_pair);
97     } else {
98       pair_test = (mc_visited_pair_t) xbt_dynar_get_as(acceptance_pairs, index, mc_visited_pair_t);
99       if (pair_test->nb_processes < new_pair->nb_processes) {
100         xbt_dynar_insert_at(acceptance_pairs, index + 1, &new_pair);
101       } else {
102         if (pair_test->heap_bytes_used < new_pair->heap_bytes_used)
103           xbt_dynar_insert_at(acceptance_pairs, index + 1, &new_pair);
104         else
105           xbt_dynar_insert_at(acceptance_pairs, index, &new_pair);
106       }
107     }
108
109   }
110   mmalloc_set_current_heap(heap);
111   return new_pair;
112 }
113
114 static void remove_acceptance_pair(int pair_num)
115 {
116   xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
117
118   unsigned int cursor = 0;
119   mc_visited_pair_t pair_test = NULL;
120   int pair_found = 0;
121
122   xbt_dynar_foreach(acceptance_pairs, cursor, pair_test) {
123     if (pair_test->num == pair_num) {
124        pair_found = 1;
125       break;
126     }
127   }
128
129   if(pair_found == 1) {
130     xbt_dynar_remove_at(acceptance_pairs, cursor, &pair_test);
131
132     pair_test->acceptance_removed = 1;
133
134     if (_sg_mc_visited == 0 || pair_test->visited_removed == 1) 
135       MC_visited_pair_delete(pair_test);
136
137   }
138
139   mmalloc_set_current_heap(heap);
140 }
141
142
143 static int MC_automaton_evaluate_label(xbt_automaton_exp_label_t l,
144                                        xbt_dynar_t atomic_propositions_values)
145 {
146
147   switch (l->type) {
148   case 0:{
149       int left_res = MC_automaton_evaluate_label(l->u.or_and.left_exp, atomic_propositions_values);
150       int right_res = MC_automaton_evaluate_label(l->u.or_and.right_exp, atomic_propositions_values);
151       return (left_res || right_res);
152     }
153   case 1:{
154       int left_res = MC_automaton_evaluate_label(l->u.or_and.left_exp, atomic_propositions_values);
155       int right_res = MC_automaton_evaluate_label(l->u.or_and.right_exp, atomic_propositions_values);
156       return (left_res && right_res);
157     }
158   case 2:{
159       int res = MC_automaton_evaluate_label(l->u.exp_not, atomic_propositions_values);
160       return (!res);
161     }
162   case 3:{
163       unsigned int cursor = 0;
164       xbt_automaton_propositional_symbol_t p = NULL;
165       xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, p) {
166         if (strcmp(xbt_automaton_propositional_symbol_get_name(p), l->u.predicat) == 0)
167           return (int) xbt_dynar_get_as(atomic_propositions_values, cursor, int);
168       }
169       return -1;
170     }
171   case 4:{
172       return 2;
173     }
174   default:
175     return -1;
176   }
177 }
178
179 static void MC_modelcheck_liveness_main(void);
180
181 static void MC_pre_modelcheck_liveness(void)
182 {
183   initial_global_state->raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
184
185   mc_pair_t initial_pair = NULL;
186   smx_process_t process;
187
188   MC_wait_for_requests();
189
190   MC_SET_MC_HEAP;
191
192   acceptance_pairs = xbt_dynar_new(sizeof(mc_visited_pair_t), NULL);
193   if(_sg_mc_visited > 0)
194     visited_pairs = xbt_dynar_new(sizeof(mc_visited_pair_t), NULL);
195
196   initial_global_state->snapshot = MC_take_snapshot(0);
197   initial_global_state->prev_pair = 0;
198
199   unsigned int cursor = 0;
200   xbt_automaton_state_t automaton_state;
201   
202   xbt_dynar_foreach(_mc_property_automaton->states, cursor, automaton_state) {
203     if (automaton_state->type == -1) {  /* Initial automaton state */
204
205       initial_pair = MC_pair_new();
206       initial_pair->automaton_state = automaton_state;
207       initial_pair->graph_state = MC_state_new();
208       initial_pair->atomic_propositions = get_atomic_propositions_values();
209       initial_pair->depth = 1;
210
211       /* Get enabled processes and insert them in the interleave set of the graph_state */
212       MC_EACH_SIMIX_PROCESS(process,
213         if (MC_process_is_enabled(process)) {
214           MC_state_interleave_process(initial_pair->graph_state, process);
215         }
216       );
217
218       initial_pair->requests = MC_state_interleave_size(initial_pair->graph_state);
219       initial_pair->search_cycle = 0;
220
221       xbt_fifo_unshift(mc_stack, initial_pair);
222     }
223   }
224
225   MC_SET_STD_HEAP;
226   
227   MC_modelcheck_liveness_main();
228
229   if (initial_global_state->raw_mem_set)
230     MC_SET_MC_HEAP;
231 }
232
233 static void MC_modelcheck_liveness_main(void)
234 {
235   smx_process_t process = NULL;
236   mc_pair_t current_pair = NULL;
237   int value, res, visited_num = -1;
238   smx_simcall_t req = NULL;
239   xbt_automaton_transition_t transition_succ = NULL;
240   int cursor = 0;
241   mc_pair_t next_pair = NULL;
242   xbt_dynar_t prop_values = NULL;
243   mc_visited_pair_t reached_pair = NULL;
244   
245   while(xbt_fifo_size(mc_stack) > 0){
246
247     /* Get current pair */
248     current_pair = (mc_pair_t) xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
249
250     /* Update current state in buchi automaton */
251     _mc_property_automaton->current_state = current_pair->automaton_state;
252
253     XBT_DEBUG("********************* ( Depth = %d, search_cycle = %d, interleave size = %d, pair_num = %d, requests = %d)",
254        current_pair->depth, current_pair->search_cycle,
255        MC_state_interleave_size(current_pair->graph_state), current_pair->num,
256        current_pair->requests);
257
258     if (current_pair->requests > 0) {
259
260       if (current_pair->automaton_state->type == 1 && current_pair->exploration_started == 0) {
261         /* If new acceptance pair, return new pair */
262         if ((reached_pair = is_reached_acceptance_pair(current_pair)) == NULL) {
263           int counter_example_depth = current_pair->depth;
264           XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
265           XBT_INFO("|             ACCEPTANCE CYCLE            |");
266           XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
267           XBT_INFO("Counter-example that violates formula :");
268           MC_show_stack_liveness(mc_stack);
269           MC_dump_stack_liveness(mc_stack);
270           MC_print_statistics(mc_stats);
271           XBT_INFO("Counter-example depth : %d", counter_example_depth);
272           xbt_abort();
273         }
274       }
275
276       /* Pair already visited ? stop the exploration on the current path */
277       if ((current_pair->exploration_started == 0) && (visited_num = is_visited_pair(reached_pair, current_pair)) != -1) {
278
279         if (dot_output != NULL){
280           MC_SET_MC_HEAP;
281           fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", initial_global_state->prev_pair, visited_num, initial_global_state->prev_req);
282           fflush(dot_output);
283           MC_SET_STD_HEAP;
284         }
285
286         XBT_DEBUG("Pair already visited (equal to pair %d), exploration on the current path stopped.", visited_num);
287         MC_SET_MC_HEAP;
288         current_pair->requests = 0;
289         MC_SET_STD_HEAP;
290         goto backtracking;
291         
292       }else{
293
294         req = MC_state_get_request(current_pair->graph_state, &value);
295
296          if (dot_output != NULL) {
297            MC_SET_MC_HEAP;
298            if (initial_global_state->prev_pair != 0 && initial_global_state->prev_pair != current_pair->num) {
299              fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", initial_global_state->prev_pair, current_pair->num, initial_global_state->prev_req);
300              xbt_free(initial_global_state->prev_req);
301            }
302            initial_global_state->prev_pair = current_pair->num;
303            initial_global_state->prev_req = MC_request_get_dot_output(req, value);
304            if (current_pair->search_cycle)
305              fprintf(dot_output, "%d [shape=doublecircle];\n", current_pair->num);
306            fflush(dot_output);
307            MC_SET_STD_HEAP;
308          }
309
310          char* req_str = MC_request_to_string(req, value, MC_REQUEST_SIMIX); 
311          XBT_DEBUG("Execute: %s", req_str);
312          xbt_free(req_str);
313
314          /* Set request as executed */
315          MC_state_set_executed_request(current_pair->graph_state, req, value);
316
317          /* Update mc_stats */
318          mc_stats->executed_transitions++;
319          if(current_pair->exploration_started == 0)
320            mc_stats->visited_pairs++;
321
322          /* Answer the request */
323          MC_simcall_handle(req, value);
324          
325          /* Wait for requests (schedules processes) */
326          MC_wait_for_requests();
327
328          MC_SET_MC_HEAP;
329
330          current_pair->requests--;
331          current_pair->exploration_started = 1;
332
333          /* Get values of atomic propositions (variables used in the property formula) */ 
334          prop_values = get_atomic_propositions_values();
335
336          /* Evaluate enabled/true transitions in automaton according to atomic propositions values and create new pairs */
337          cursor = xbt_dynar_length(current_pair->automaton_state->out) - 1;
338          while (cursor >= 0) {
339            transition_succ = (xbt_automaton_transition_t)xbt_dynar_get_as(current_pair->automaton_state->out, cursor, xbt_automaton_transition_t);
340            res = MC_automaton_evaluate_label(transition_succ->label, prop_values);
341            if (res == 1 || res == 2) { /* 1 = True transition (always enabled), 2 = enabled transition according to atomic prop values */
342               next_pair = MC_pair_new();
343               next_pair->graph_state = MC_state_new();
344               next_pair->automaton_state = transition_succ->dst;
345               next_pair->atomic_propositions = get_atomic_propositions_values();
346               next_pair->depth = current_pair->depth + 1;
347               /* Get enabled processes and insert them in the interleave set of the next graph_state */
348               MC_EACH_SIMIX_PROCESS(process,
349                 if (MC_process_is_enabled(process)) {
350                   MC_state_interleave_process(next_pair->graph_state, process);
351                 }
352               );
353
354               next_pair->requests = MC_state_interleave_size(next_pair->graph_state);
355
356               /* FIXME : get search_cycle value for each acceptant state */
357               if (next_pair->automaton_state->type == 1 || current_pair->search_cycle)
358                 next_pair->search_cycle = 1;
359
360               /* Add new pair to the exploration stack */
361               xbt_fifo_unshift(mc_stack, next_pair);
362
363            }
364            cursor--;
365          }
366          
367          MC_SET_STD_HEAP;
368         
369       } /* End of visited_pair test */
370       
371     } else {
372
373     backtracking:
374       if(visited_num == -1)
375         XBT_DEBUG("No more request to execute. Looking for backtracking point.");
376     
377       MC_SET_MC_HEAP;
378     
379       xbt_dynar_free(&prop_values);
380     
381       /* Traverse the stack backwards until a pair with a non empty interleave
382          set is found, deleting all the pairs that have it empty in the way. */
383       while ((current_pair = (mc_pair_t) xbt_fifo_shift(mc_stack)) != NULL) {
384         if (current_pair->requests > 0) {
385           /* We found a backtracking point */
386           XBT_DEBUG("Backtracking to depth %d", current_pair->depth);
387           xbt_fifo_unshift(mc_stack, current_pair);
388           MC_SET_STD_HEAP;
389           MC_replay_liveness(mc_stack);
390           XBT_DEBUG("Backtracking done");
391           break;
392         }else{
393           /* Delete pair */
394           XBT_DEBUG("Delete pair %d at depth %d", current_pair->num, current_pair->depth);
395           if (current_pair->automaton_state->type == 1) 
396             remove_acceptance_pair(current_pair->num);
397           MC_pair_delete(current_pair);
398         }
399       }
400     
401       MC_SET_STD_HEAP;
402     } /* End of if (current_pair->requests > 0) else ... */
403     
404   } /* End of while(xbt_fifo_size(mc_stack) > 0) */
405   
406 }
407
408 void MC_modelcheck_liveness(void)
409 {
410   if (mc_reduce_kind == e_mc_reduce_unset)
411     mc_reduce_kind = e_mc_reduce_none;
412   XBT_INFO("Check the liveness property %s", _sg_mc_property_file);
413   MC_automaton_load(_sg_mc_property_file);
414   MC_wait_for_requests();
415
416   XBT_DEBUG("Starting the liveness algorithm");
417   _sg_mc_liveness = 1;
418
419   xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
420
421   /* Create exploration stack */
422   mc_stack = xbt_fifo_new();
423
424   /* Create the initial state */
425   initial_global_state = xbt_new0(s_mc_global_t, 1);
426
427   MC_SET_STD_HEAP;
428
429   MC_pre_modelcheck_liveness();
430
431   /* We're done */
432   MC_print_statistics(mc_stats);
433   xbt_free(mc_time);
434
435   mmalloc_set_current_heap(heap);
436
437 }
438
439 }