Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Do not use linkage_name as a name
[simgrid.git] / src / mc / mc_dpor.c
1 /* Copyright (c) 2008-2013. 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 "mc_private.h"
8
9 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dpor, mc,
10                                 "Logging specific to MC DPOR exploration");
11
12 /********** Global variables **********/
13
14 xbt_dynar_t visited_states;
15 xbt_dict_t first_enabled_state;
16 xbt_dynar_t initial_communications_pattern;
17 xbt_dynar_t communications_pattern;
18 int nb_comm_pattern;
19
20 /********** Static functions ***********/
21
22 static void comm_pattern_free(mc_comm_pattern_t p){
23   xbt_free(p->rdv);
24   xbt_free(p->data);
25   xbt_free(p);
26   p = NULL;
27 }
28
29 static void comm_pattern_free_voidp( void *p){
30   comm_pattern_free((mc_comm_pattern_t) * (void **)p);
31 }
32
33 static mc_comm_pattern_t get_comm_pattern_from_idx(xbt_dynar_t pattern, unsigned int *idx, e_smx_comm_type_t type, unsigned long proc){
34   mc_comm_pattern_t current_comm;
35   while(*idx < xbt_dynar_length(pattern)){
36     current_comm = (mc_comm_pattern_t)xbt_dynar_get_as(pattern, *idx, mc_comm_pattern_t);
37     if(current_comm->type == type && type == SIMIX_COMM_SEND){
38       if(current_comm->src_proc == proc)
39         return current_comm;
40     }else if(current_comm->type == type && type == SIMIX_COMM_RECEIVE){
41       if(current_comm->dst_proc == proc)
42         return current_comm;
43     }
44     (*idx)++;
45   }
46   return NULL;
47 }
48
49 static int compare_comm_pattern(mc_comm_pattern_t comm1, mc_comm_pattern_t comm2){
50   if(strcmp(comm1->rdv, comm2->rdv) != 0)
51     return 1;
52   if(comm1->src_proc != comm2->src_proc)
53     return 1;
54   if(comm1->dst_proc != comm2->dst_proc)
55     return 1;
56   if(comm1->data_size != comm2->data_size)
57     return 1;
58   if(memcmp(comm1->data, comm2->data, comm1->data_size) != 0)
59     return 1;
60   return 0;
61 }
62
63 static void deterministic_pattern(xbt_dynar_t initial_pattern, xbt_dynar_t pattern){
64   unsigned int cursor = 0, send_index = 0, recv_index = 0;
65   mc_comm_pattern_t comm1, comm2;
66   int comm_comparison = 0;
67   int current_process = 0;
68   while(current_process < simix_process_maxpid){
69     while(cursor < xbt_dynar_length(initial_pattern)){
70       comm1 = (mc_comm_pattern_t)xbt_dynar_get_as(initial_pattern, cursor, mc_comm_pattern_t);
71       if(comm1->type == SIMIX_COMM_SEND && comm1->src_proc == current_process){
72         comm2 = get_comm_pattern_from_idx(pattern, &send_index, comm1->type, current_process);
73         comm_comparison = compare_comm_pattern(comm1, comm2);
74         if(comm_comparison == 1){
75           initial_state_safety->send_deterministic = 0;
76           initial_state_safety->comm_deterministic = 0;
77           return;
78         }
79         send_index++;
80       }else if(comm1->type == SIMIX_COMM_RECEIVE && comm1->dst_proc == current_process){
81         comm2 = get_comm_pattern_from_idx(pattern, &recv_index, comm1->type, current_process);
82         comm_comparison = compare_comm_pattern(comm1, comm2);
83         if(comm_comparison == 1){
84           initial_state_safety->comm_deterministic = 0;
85         }
86         recv_index++;
87       }
88       cursor++;
89     }
90     cursor = 0;
91     send_index = 0;
92     recv_index = 0;
93     current_process++;
94   }
95   // XBT_DEBUG("Communication-deterministic : %d, Send-deterministic : %d", initial_state_safety->comm_deterministic, initial_state_safety->send_deterministic);
96 }
97
98 static int complete_comm_pattern(xbt_dynar_t list, mc_comm_pattern_t pattern){
99   mc_comm_pattern_t current_pattern;
100   unsigned int cursor = 0;
101   xbt_dynar_foreach(list, cursor, current_pattern){
102     if(current_pattern->comm == pattern->comm){
103       if(!current_pattern->completed){
104         current_pattern->src_proc = pattern->comm->comm.src_proc->pid;
105         current_pattern->dst_proc = pattern->comm->comm.dst_proc->pid;
106         current_pattern->data_size = pattern->comm->comm.src_buff_size;
107         current_pattern->data = xbt_malloc0(current_pattern->data_size);
108         current_pattern->matched_comm = pattern->num;
109         memcpy(current_pattern->data, current_pattern->comm->comm.src_buff, current_pattern->data_size);
110         current_pattern->completed = 1;
111         return current_pattern->num;
112       }
113     }
114   }
115   return -1;
116 }
117
118 void get_comm_pattern(xbt_dynar_t list, smx_simcall_t request, int call){
119   mc_comm_pattern_t pattern = NULL;
120   pattern = xbt_new0(s_mc_comm_pattern_t, 1);
121   pattern->num = ++nb_comm_pattern;
122   pattern->completed = 0;
123   if(call == 1){ // ISEND
124     pattern->comm = simcall_comm_isend__get__result(request);
125     pattern->type = SIMIX_COMM_SEND;
126     if(pattern->comm->comm.dst_proc != NULL){
127  
128       pattern->matched_comm = complete_comm_pattern(list, pattern);
129       pattern->dst_proc = pattern->comm->comm.dst_proc->pid;
130       pattern->completed = 1;
131     }
132     pattern->src_proc = pattern->comm->comm.src_proc->pid;
133     pattern->data_size = pattern->comm->comm.src_buff_size;
134     pattern->data=xbt_malloc0(pattern->data_size);
135     memcpy(pattern->data, pattern->comm->comm.src_buff, pattern->data_size);
136   }else{ // IRECV
137     pattern->comm = simcall_comm_irecv__get__result(request);
138     pattern->type = SIMIX_COMM_RECEIVE;
139     if(pattern->comm->comm.src_proc != NULL){
140       pattern->matched_comm = complete_comm_pattern(list, pattern);
141       pattern->src_proc = pattern->comm->comm.src_proc->pid;
142       pattern->completed = 1;
143       pattern->data_size = pattern->comm->comm.src_buff_size;
144       pattern->data=xbt_malloc0(pattern->data_size);
145       memcpy(pattern->data, pattern->comm->comm.src_buff, pattern->data_size);
146     }
147     pattern->dst_proc = pattern->comm->comm.dst_proc->pid;
148   }
149   if(pattern->comm->comm.rdv != NULL)
150     pattern->rdv = strdup(pattern->comm->comm.rdv->name);
151   else
152     pattern->rdv = strdup(pattern->comm->comm.rdv_cpy->name);
153   xbt_dynar_push(list, &pattern);
154 }
155
156 static void print_communications_pattern(xbt_dynar_t comms_pattern){
157   unsigned int cursor = 0;
158   mc_comm_pattern_t current_comm;
159   xbt_dynar_foreach(comms_pattern, cursor, current_comm){
160     // fprintf(stderr, "%s (%d - comm %p, src : %lu, dst %lu, rdv name %s, data %p, matched with %d)\n", current_comm->type == SIMIX_COMM_SEND ? "iSend" : "iRecv", current_comm->num, current_comm->comm, current_comm->src_proc, current_comm->dst_proc, current_comm->rdv, current_comm->data, current_comm->matched_comm);
161   }
162 }
163
164 static void visited_state_free(mc_visited_state_t state){
165   if(state){
166     MC_free_snapshot(state->system_state);
167     xbt_free(state);
168   }
169 }
170
171 static void visited_state_free_voidp(void *s){
172   visited_state_free((mc_visited_state_t) * (void **) s);
173 }
174
175 /** \brief Save the current state
176  *
177  *  \return Snapshot of the current state.
178  */
179 static mc_visited_state_t visited_state_new(){
180
181   mc_visited_state_t new_state = NULL;
182   new_state = xbt_new0(s_mc_visited_state_t, 1);
183   new_state->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
184   new_state->nb_processes = xbt_swag_size(simix_global->process_list);
185   new_state->system_state = MC_take_snapshot(mc_stats->expanded_states);
186   new_state->num = mc_stats->expanded_states;
187   new_state->other_num = -1;
188
189   return new_state;
190   
191 }
192
193 /** \brief Find a suitable subrange of candidate duplicates for a given state
194  *
195  *  \param all_ pairs dynamic array of states with candidate duplicates of the current state;
196  *  \param pair current state;
197  *  \param min (output) index of the beginning of the the subrange
198  *  \param max (output) index of the enf of the subrange
199  *
200  *  Given a suitably ordered array of state, this function extracts a subrange
201  *  (with index *min <= i <= *max) with candidate duplicates of the given state.
202  *  This function uses only fast discriminating criterions and does not use the
203  *  full state comparison algorithms.
204  *
205  *  The states in all_pairs MUST be ordered using a (given) weak order
206  *  (based on nb_processes and heap_bytes_used).
207  *  The subrange is the subrange of "equivalence" of the given state.
208  */
209 static int get_search_interval(xbt_dynar_t all_states, mc_visited_state_t state, int *min, int *max){
210
211   int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
212
213   MC_SET_RAW_MEM;
214
215   int cursor = 0, previous_cursor, next_cursor;
216   mc_visited_state_t state_test;
217   int start = 0;
218   int end = xbt_dynar_length(all_states) - 1;
219   
220   while(start <= end){
221     cursor = (start + end) / 2;
222     state_test = (mc_visited_state_t)xbt_dynar_get_as(all_states, cursor, mc_visited_state_t);
223     if(state_test->nb_processes < state->nb_processes){
224       start = cursor + 1;
225     }else if(state_test->nb_processes > state->nb_processes){
226       end = cursor - 1;
227     }else{
228       if(state_test->heap_bytes_used < state->heap_bytes_used){
229         start = cursor +1;
230       }else if(state_test->heap_bytes_used > state->heap_bytes_used){
231         end = cursor - 1;
232       }else{
233         *min = *max = cursor;
234         previous_cursor = cursor - 1;
235         while(previous_cursor >= 0){
236           state_test = (mc_visited_state_t)xbt_dynar_get_as(all_states, previous_cursor, mc_visited_state_t);
237           if(state_test->nb_processes != state->nb_processes || state_test->heap_bytes_used != state->heap_bytes_used)
238             break;
239           *min = previous_cursor;
240           previous_cursor--;
241         }
242         next_cursor = cursor + 1;
243         while(next_cursor < xbt_dynar_length(all_states)){
244           state_test = (mc_visited_state_t)xbt_dynar_get_as(all_states, next_cursor, mc_visited_state_t);
245           if(state_test->nb_processes != state->nb_processes || state_test->heap_bytes_used != state->heap_bytes_used)
246             break;
247           *max = next_cursor;
248           next_cursor++;
249         }
250         if(!raw_mem_set)
251           MC_UNSET_RAW_MEM;
252         return -1;
253       }
254      }
255   }
256
257   if(!raw_mem_set)
258     MC_UNSET_RAW_MEM;
259
260   return cursor;
261 }
262
263 /** \brief Take a snapshot the current state and process it.
264  *
265  *  \return number of the duplicate state or -1 (not visited)
266  */
267 static int is_visited_state(){
268
269   if(_sg_mc_visited == 0)
270     return -1;
271
272   int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
273
274   MC_SET_RAW_MEM;
275
276   mc_visited_state_t new_state = visited_state_new();
277   
278   if(xbt_dynar_is_empty(visited_states)){
279
280     xbt_dynar_push(visited_states, &new_state); 
281
282     if(!raw_mem_set)
283       MC_UNSET_RAW_MEM;
284
285     return -1;
286
287   }else{
288
289     int min = -1, max = -1, index;
290     //int res;
291     mc_visited_state_t state_test;
292     int cursor;
293
294     index = get_search_interval(visited_states, new_state, &min, &max);
295
296     if(min != -1 && max != -1){
297
298       // Parallell implementation
299       /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state);
300       if(res != -1){
301         state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t);
302         if(state_test->other_num == -1)
303           new_state->other_num = state_test->num;
304         else
305           new_state->other_num = state_test->other_num;
306         if(dot_output == NULL)
307           XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
308         else
309           XBT_DEBUG("State %d already visited ! (equal to state %d (state %d in dot_output))", new_state->num, state_test->num, new_state->other_num);
310         xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL);
311         xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state);
312         if(!raw_mem_set)
313           MC_UNSET_RAW_MEM;
314         return new_state->other_num;
315         }*/
316
317       cursor = min;
318       while(cursor <= max){
319         state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, cursor, mc_visited_state_t);
320         if(snapshot_compare(state_test, new_state) == 0){
321           // The state has been visited:
322
323           if(state_test->other_num == -1)
324             new_state->other_num = state_test->num;
325           else
326             new_state->other_num = state_test->other_num;
327           if(dot_output == NULL)
328             XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
329           else
330             XBT_DEBUG("State %d already visited ! (equal to state %d (state %d in dot_output))", new_state->num, state_test->num, new_state->other_num);
331
332           // Replace the old state with the new one (why?):
333           xbt_dynar_remove_at(visited_states, cursor, NULL);
334           xbt_dynar_insert_at(visited_states, cursor, &new_state);
335
336           if(!raw_mem_set)
337             MC_UNSET_RAW_MEM;
338           return new_state->other_num;
339         }
340         cursor++;
341       }
342
343       // The state has not been visited, add it to the list:
344       xbt_dynar_insert_at(visited_states, min, &new_state);
345
346     }else{
347
348       // The state has not been visited: insert the state in the dynamic array.
349       state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, index, mc_visited_state_t);
350       if(state_test->nb_processes < new_state->nb_processes){
351         xbt_dynar_insert_at(visited_states, index+1, &new_state);
352       }else{
353         if(state_test->heap_bytes_used < new_state->heap_bytes_used)
354           xbt_dynar_insert_at(visited_states, index + 1, &new_state);
355         else
356           xbt_dynar_insert_at(visited_states, index, &new_state);
357       }
358
359     }
360
361     // We have reached the maximum number of stored states;
362     if(xbt_dynar_length(visited_states) > _sg_mc_visited){
363
364       // Find the (index of the) older state:
365       int min2 = mc_stats->expanded_states;
366       unsigned int cursor2 = 0;
367       unsigned int index2 = 0;
368       xbt_dynar_foreach(visited_states, cursor2, state_test){
369         if(state_test->num < min2){
370           index2 = cursor2;
371           min2 = state_test->num;
372         }
373       }
374
375       // and drop it:
376       xbt_dynar_remove_at(visited_states, index2, NULL);
377     }
378
379     if(!raw_mem_set)
380       MC_UNSET_RAW_MEM;
381     
382     return -1;
383     
384   }
385 }
386
387 /**
388  *  \brief Initialize the DPOR exploration algorithm
389  */
390 void MC_dpor_init()
391 {
392   
393   int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
394
395   mc_state_t initial_state = NULL;
396   smx_process_t process;
397   
398   /* Create the initial state and push it into the exploration stack */
399   MC_SET_RAW_MEM;
400
401   if(_sg_mc_visited > 0)
402     visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
403
404   first_enabled_state = xbt_dict_new_homogeneous(&xbt_free_f);
405
406   initial_communications_pattern = xbt_dynar_new(sizeof(mc_comm_pattern_t), comm_pattern_free_voidp);
407   communications_pattern = xbt_dynar_new(sizeof(mc_comm_pattern_t), comm_pattern_free_voidp);
408   nb_comm_pattern = 0;
409
410   initial_state = MC_state_new();
411
412   MC_UNSET_RAW_MEM;
413
414   XBT_DEBUG("**************************************************");
415   XBT_DEBUG("Initial state");
416
417   /* Wait for requests (schedules processes) */
418   MC_wait_for_requests();
419
420   MC_ignore_heap(simix_global->process_to_run->data, 0);
421   MC_ignore_heap(simix_global->process_that_ran->data, 0);
422
423   MC_SET_RAW_MEM;
424  
425   /* Get an enabled process and insert it in the interleave set of the initial state */
426   xbt_swag_foreach(process, simix_global->process_list){
427     if(MC_process_is_enabled(process)){
428       MC_state_interleave_process(initial_state, process);
429       if(mc_reduce_kind != e_mc_reduce_none)
430         break;
431     }
432   }
433
434   xbt_fifo_unshift(mc_stack_safety, initial_state);
435
436   /* To ensure the soundness of DPOR, we have to keep a list of 
437      processes which are still enabled at each step of the exploration. 
438      If max depth is reached, we interleave them in the state in which they have 
439      been enabled for the first time. */
440   xbt_swag_foreach(process, simix_global->process_list){
441     if(MC_process_is_enabled(process)){
442       char *key = bprintf("%lu", process->pid);
443       char *data = bprintf("%d", xbt_fifo_size(mc_stack_safety));
444       xbt_dict_set(first_enabled_state, key, data, NULL);
445       xbt_free(key);
446     }
447   }
448
449   MC_UNSET_RAW_MEM;
450
451   if(raw_mem_set)
452     MC_SET_RAW_MEM;
453   else
454     MC_UNSET_RAW_MEM;
455   
456 }
457
458
459 /** \brief Model-check the application using a DFS exploration
460  *         with DPOR (Dynamic Partial Order Reductions)
461  */
462 void MC_dpor(void)
463 {
464
465   char *req_str = NULL;
466   int value;
467   smx_simcall_t req = NULL, prev_req = NULL;
468   mc_state_t state = NULL, prev_state = NULL, next_state = NULL, restore_state=NULL;
469   smx_process_t process = NULL;
470   xbt_fifo_item_t item = NULL;
471   mc_state_t state_test = NULL;
472   int pos;
473   int visited_state = -1;
474   int enabled = 0;
475   int comm_pattern = 0;
476   int interleave_size = 0;
477
478   while (xbt_fifo_size(mc_stack_safety) > 0) {
479
480     /* Get current state */
481     state = (mc_state_t) 
482       xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_safety));
483
484     XBT_DEBUG("**************************************************");
485     XBT_DEBUG("Exploration depth=%d (state=%p, num %d)(%u interleave, user_max_depth %d, first_enabled_state size : %d)",
486               xbt_fifo_size(mc_stack_safety), state, state->num,
487               MC_state_interleave_size(state), user_max_depth_reached, xbt_dict_size(first_enabled_state));
488       
489     interleave_size = MC_state_interleave_size(state);
490
491     /* Update statistics */
492     mc_stats->visited_states++;
493
494     /* If there are processes to interleave and the maximum depth has not been reached
495        then perform one step of the exploration algorithm */
496     if (xbt_fifo_size(mc_stack_safety) <= _sg_mc_max_depth && !user_max_depth_reached &&
497         (req = MC_state_get_request(state, &value)) && visited_state == -1) {
498
499       /* Debug information */
500       if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
501         req_str = MC_request_to_string(req, value);
502         XBT_DEBUG("Execute: %s", req_str);
503         xbt_free(req_str);
504       }
505       
506       MC_SET_RAW_MEM;
507       if(dot_output != NULL)
508         req_str = MC_request_get_dot_output(req, value);
509       MC_UNSET_RAW_MEM;
510
511       MC_state_set_executed_request(state, req, value);
512       mc_stats->executed_transitions++;
513
514       MC_SET_RAW_MEM;
515       char *key = bprintf("%lu", req->issuer->pid);
516       xbt_dict_remove(first_enabled_state, key); 
517       xbt_free(key);
518       MC_UNSET_RAW_MEM;
519
520       if(req->call == SIMCALL_COMM_ISEND)
521         comm_pattern = 1;
522       else if(req->call == SIMCALL_COMM_IRECV)
523         comm_pattern = 2;
524
525       /* Answer the request */
526       SIMIX_simcall_pre(req, value); /* After this call req is no longer usefull */
527
528       MC_SET_RAW_MEM;
529       if(comm_pattern != 0){
530         if(!initial_state_safety->initial_communications_pattern_done)
531           get_comm_pattern(initial_communications_pattern, req, comm_pattern);
532         else
533           get_comm_pattern(communications_pattern, req, comm_pattern);
534       }
535       MC_UNSET_RAW_MEM;
536
537       comm_pattern = 0;
538
539       /* Wait for requests (schedules processes) */
540       MC_wait_for_requests();
541
542       /* Create the new expanded state */
543       MC_SET_RAW_MEM;
544
545       next_state = MC_state_new();
546
547       if((visited_state = is_visited_state()) == -1){
548      
549         /* Get an enabled process and insert it in the interleave set of the next state */
550         xbt_swag_foreach(process, simix_global->process_list){
551           if(MC_process_is_enabled(process)){
552             MC_state_interleave_process(next_state, process);
553             if(mc_reduce_kind != e_mc_reduce_none)
554               break;
555           }
556         }
557
558         if(_sg_mc_checkpoint && ((xbt_fifo_size(mc_stack_safety) + 1) % _sg_mc_checkpoint == 0)){
559           next_state->system_state = MC_take_snapshot(next_state->num);
560         }
561
562         if(dot_output != NULL)
563           fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, next_state->num, req_str);
564
565       }else{
566
567         if(dot_output != NULL)
568           fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, visited_state, req_str);
569
570       }
571
572       xbt_fifo_unshift(mc_stack_safety, next_state);
573
574       /* Insert in dict all enabled processes, if not included yet */
575       xbt_swag_foreach(process, simix_global->process_list){
576         if(MC_process_is_enabled(process)){
577           char *key = bprintf("%lu", process->pid);
578           if(xbt_dict_get_or_null(first_enabled_state, key) == NULL){
579             char *data = bprintf("%d", xbt_fifo_size(mc_stack_safety));
580             xbt_dict_set(first_enabled_state, key, data, NULL); 
581           }
582           xbt_free(key);
583         }
584       }
585       
586       if(dot_output != NULL)
587         xbt_free(req_str);
588
589       MC_UNSET_RAW_MEM;
590
591       /* Let's loop again */
592
593       /* The interleave set is empty or the maximum depth is reached, let's back-track */
594     } else {
595
596       if((xbt_fifo_size(mc_stack_safety) > _sg_mc_max_depth) || user_max_depth_reached || visited_state != -1){  
597
598         if(user_max_depth_reached && visited_state == -1)
599           XBT_DEBUG("User max depth reached !");
600         else if(visited_state == -1)
601           XBT_WARN("/!\\ Max depth reached ! /!\\ ");
602
603         visited_state = -1;
604
605         /* Interleave enabled processes in the state in which they have been enabled for the first time */
606         xbt_swag_foreach(process, simix_global->process_list){
607           if(MC_process_is_enabled(process)){
608             char *key = bprintf("%lu", process->pid);
609             enabled = (int)strtoul(xbt_dict_get_or_null(first_enabled_state, key), 0, 10);
610             xbt_free(key);
611             int cursor = xbt_fifo_size(mc_stack_safety);
612             xbt_fifo_foreach(mc_stack_safety, item, state_test, mc_state_t){
613               if(cursor-- == enabled){ 
614                 if(!MC_state_process_is_done(state_test, process) && state_test->num != state->num){ 
615                   XBT_DEBUG("Interleave process %lu in state %d", process->pid, state_test->num);
616                   MC_state_interleave_process(state_test, process);
617                   break;
618                 }
619               }
620             }
621           }
622         }
623
624       }else{
625
626         XBT_DEBUG("There are no more processes to interleave. (depth %d)", xbt_fifo_size(mc_stack_safety) + 1);
627
628       }
629
630       MC_SET_RAW_MEM;
631       if(0) {
632       if(!initial_state_safety->initial_communications_pattern_done){
633         print_communications_pattern(initial_communications_pattern);
634       }else{
635         if(interleave_size == 0){ /* if (interleave_size > 0), process interleaved but not enabled => "incorrect" path, determinism not evaluated */
636           print_communications_pattern(communications_pattern);
637           deterministic_pattern(initial_communications_pattern, communications_pattern);
638         }
639       }
640       initial_state_safety->initial_communications_pattern_done = 1;
641       }
642       MC_UNSET_RAW_MEM;
643
644       /* Trash the current state, no longer needed */
645       MC_SET_RAW_MEM;
646       xbt_fifo_shift(mc_stack_safety);
647       MC_state_delete(state);
648       XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack_safety) + 1);
649       MC_UNSET_RAW_MEM;        
650       
651       /* Check for deadlocks */
652       if(MC_deadlock_check()){
653         MC_show_deadlock(NULL);
654         return;
655       }
656
657       MC_SET_RAW_MEM;
658       /* Traverse the stack backwards until a state with a non empty interleave
659          set is found, deleting all the states that have it empty in the way.
660          For each deleted state, check if the request that has generated it 
661          (from it's predecesor state), depends on any other previous request 
662          executed before it. If it does then add it to the interleave set of the
663          state that executed that previous request. */
664       
665       while ((state = xbt_fifo_shift(mc_stack_safety)) != NULL) {
666         if(mc_reduce_kind != e_mc_reduce_none){
667           req = MC_state_get_internal_request(state);
668           xbt_fifo_foreach(mc_stack_safety, item, prev_state, mc_state_t) {
669             if(MC_request_depend(req, MC_state_get_internal_request(prev_state))){
670               if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
671                 XBT_DEBUG("Dependent Transitions:");
672                 prev_req = MC_state_get_executed_request(prev_state, &value);
673                 req_str = MC_request_to_string(prev_req, value);
674                 XBT_DEBUG("%s (state=%d)", req_str, prev_state->num);
675                 xbt_free(req_str);
676                 prev_req = MC_state_get_executed_request(state, &value);
677                 req_str = MC_request_to_string(prev_req, value);
678                 XBT_DEBUG("%s (state=%d)", req_str, state->num);
679                 xbt_free(req_str);              
680               }
681
682               if(!MC_state_process_is_done(prev_state, req->issuer))
683                 MC_state_interleave_process(prev_state, req->issuer);
684               else
685                 XBT_DEBUG("Process %p is in done set", req->issuer);
686
687               break;
688
689             }else if(req->issuer == MC_state_get_internal_request(prev_state)->issuer){
690
691               XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
692               break;
693
694             }else{
695
696               XBT_DEBUG("Simcall %d, process %lu (state %d) and simcall %d, process %lu (state %d) are independant", req->call, req->issuer->pid, state->num, MC_state_get_internal_request(prev_state)->call, MC_state_get_internal_request(prev_state)->issuer->pid, prev_state->num);
697
698             }
699           }
700         }
701              
702         if (MC_state_interleave_size(state) && xbt_fifo_size(mc_stack_safety) < _sg_mc_max_depth) {
703           /* We found a back-tracking point, let's loop */
704           XBT_DEBUG("Back-tracking to state %d at depth %d", state->num, xbt_fifo_size(mc_stack_safety) + 1);
705           if(_sg_mc_checkpoint){
706             if(state->system_state != NULL){
707               MC_restore_snapshot(state->system_state);
708               xbt_fifo_unshift(mc_stack_safety, state);
709               MC_UNSET_RAW_MEM;
710             }else{
711               pos = xbt_fifo_size(mc_stack_safety);
712               item = xbt_fifo_get_first_item(mc_stack_safety);
713               while(pos>0){
714                 restore_state = (mc_state_t) xbt_fifo_get_item_content(item);
715                 if(restore_state->system_state != NULL){
716                   break;
717                 }else{
718                   item = xbt_fifo_get_next_item(item);
719                   pos--;
720                 }
721               }
722               MC_restore_snapshot(restore_state->system_state);
723               xbt_fifo_unshift(mc_stack_safety, state);
724               MC_UNSET_RAW_MEM;
725               MC_replay(mc_stack_safety, pos);
726             }
727           }else{
728             xbt_fifo_unshift(mc_stack_safety, state);
729             MC_UNSET_RAW_MEM;
730             MC_replay(mc_stack_safety, -1);
731           }
732           XBT_DEBUG("Back-tracking to state %d at depth %d done", state->num, xbt_fifo_size(mc_stack_safety));
733           break;
734         } else {
735           req = MC_state_get_internal_request(state);
736           if(req->call == SIMCALL_COMM_ISEND || req->call == SIMCALL_COMM_IRECV){
737             // fprintf(stderr, "Remove state with isend or irecv\n");
738             if(!xbt_dynar_is_empty(communications_pattern))
739               xbt_dynar_remove_at(communications_pattern, xbt_dynar_length(communications_pattern) - 1, NULL);
740           }
741           XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack_safety) + 1); 
742           MC_state_delete(state);
743         }
744       }
745       MC_UNSET_RAW_MEM;
746     }
747   }
748   MC_print_statistics(mc_stats);
749   MC_UNSET_RAW_MEM;  
750
751   return;
752 }
753
754
755
756