Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
cea9e12596f0886a0d98135a42498ee07c8e0dad
[simgrid.git] / src / mc / mc_compare.c
1 /* Copyright (c) 2012-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 <inttypes.h>
8
9 #include "mc_private.h"
10
11 #include "xbt/mmalloc.h"
12
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_compare, mc,
14                                 "Logging specific to mc_compare");
15
16 typedef struct s_pointers_pair{
17   void *p1;
18   void *p2;
19 }s_pointers_pair_t, *pointers_pair_t;
20
21 __thread xbt_dynar_t compared_pointers;
22
23 /************************** Free functions ****************************/
24 /********************************************************************/
25
26 static void stack_region_free(stack_region_t s){
27   if(s){
28     xbt_free(s->process_name);
29     xbt_free(s);
30   }
31 }
32
33 static void stack_region_free_voidp(void *s){
34   stack_region_free((stack_region_t) * (void **) s);
35 }
36
37 static void pointers_pair_free(pointers_pair_t p){
38   xbt_free(p);
39 }
40
41 static void pointers_pair_free_voidp(void *p){
42   pointers_pair_free((pointers_pair_t) * (void **)p);
43 }
44
45 /************************** Snapshot comparison *******************************/
46 /******************************************************************************/
47
48 /** \brief Try to add a pair a compared pointers to the set of compared pointers
49  *
50  *  \result !=0 if the pointers were added (they were not in the set),
51  *      0 otherwise (they were already in the set)
52  */
53 static int add_compared_pointers(void *p1, void *p2){
54
55   pointers_pair_t new_pair = xbt_new0(s_pointers_pair_t, 1);
56   new_pair->p1 = p1;
57   new_pair->p2 = p2;
58   
59   if(xbt_dynar_is_empty(compared_pointers)){
60     xbt_dynar_push(compared_pointers, &new_pair);
61     return 1;
62   }
63
64   unsigned int cursor = 0;
65   int start = 0;
66   int end = xbt_dynar_length(compared_pointers) - 1;
67   pointers_pair_t pair = NULL;
68
69   pointers_pair_t* p = (pointers_pair_t*) xbt_dynar_get_ptr(compared_pointers, 0);
70
71   while(start <= end){
72     cursor = (start + end) / 2;
73     pair = p[cursor];
74     if(pair->p1 < p1){
75       start = cursor + 1;
76     } else if(pair->p1 > p1) {
77       end = cursor - 1 ;
78     } else if(pair->p2 < p2){
79       start = cursor + 1;
80     } else if(pair->p2 > p2) {
81       end = cursor - 1 ;
82     } else {
83       pointers_pair_free(new_pair);
84       return 0;
85     }
86   }
87
88   if(pair->p1 < p1)
89     xbt_dynar_insert_at(compared_pointers, cursor + 1, &new_pair);
90   else if(pair->p1 > p1)
91     xbt_dynar_insert_at(compared_pointers, cursor, &new_pair);
92   else if(pair->p2 < p2)
93     xbt_dynar_insert_at(compared_pointers, cursor + 1, &new_pair);
94   else if(pair->p2 > p2)
95     xbt_dynar_insert_at(compared_pointers, cursor, &new_pair);
96   else
97     xbt_die("Unrecheable");
98
99   return 1;
100 }
101
102 static int compare_areas_with_type(void *area1, void *area2, mc_object_info_t info, mc_object_info_t other_info, dw_type_t type, int region_size, int region_type, void *start_data, int pointer_level){
103
104   unsigned int cursor = 0;
105   dw_type_t member, subtype, subsubtype;
106   int elm_size, i, res, switch_types = 0;
107   void *addr_pointed1, *addr_pointed2;
108
109   switch(type->type){
110   case DW_TAG_base_type:
111   case DW_TAG_enumeration_type:
112   case DW_TAG_union_type:
113     return (memcmp(area1, area2, type->byte_size) != 0);
114     break;
115   case DW_TAG_typedef:
116   case DW_TAG_volatile_type:
117   case DW_TAG_const_type:
118     return compare_areas_with_type(area1, area2, info, other_info, type->subtype, region_size, region_type, start_data, pointer_level);
119     break;
120   case DW_TAG_array_type:
121     subtype = type->subtype;
122     switch(subtype->type){
123     case DW_TAG_base_type:
124     case DW_TAG_enumeration_type:
125     case DW_TAG_pointer_type:
126     case DW_TAG_reference_type:
127     case DW_TAG_rvalue_reference_type:
128     case DW_TAG_structure_type:
129     case DW_TAG_union_type:
130       if(subtype->byte_size == 0){ /*declaration of the type, need the complete description */
131           subtype = subtype->other_object_same_type;
132           switch_types = 1;
133       }
134       elm_size = subtype->byte_size;
135       break;
136     case DW_TAG_const_type:
137     case DW_TAG_typedef:
138     case DW_TAG_volatile_type:
139       subsubtype = subtype->subtype;
140       if(subsubtype->byte_size == 0){ /*declaration of the type, need the complete description */
141           subsubtype = subsubtype->other_object_same_type;
142           switch_types = 1;
143       }
144       elm_size = subsubtype->byte_size;
145       break;
146     default : 
147       return 0;
148       break;
149     }
150     for(i=0; i<type->element_count; i++){
151       if(switch_types)
152         res = compare_areas_with_type((char *)area1 + (i*elm_size), (char *)area2 + (i*elm_size), other_info, info, type->subtype, region_size, region_type, start_data, pointer_level);
153       else
154         res = compare_areas_with_type((char *)area1 + (i*elm_size), (char *)area2 + (i*elm_size), info, other_info, type->subtype, region_size, region_type, start_data, pointer_level);
155       if(res == 1)
156         return res;
157     }
158     break;
159   case DW_TAG_pointer_type:
160   case DW_TAG_reference_type:
161   case DW_TAG_rvalue_reference_type:
162     if(type->subtype && type->subtype->type == DW_TAG_subroutine_type){
163       addr_pointed1 = *((void **)(area1)); 
164       addr_pointed2 = *((void **)(area2));
165       return (addr_pointed1 != addr_pointed2);
166     }else{
167       addr_pointed1 = *((void **)(area1)); 
168       addr_pointed2 = *((void **)(area2));
169       
170       if(addr_pointed1 == NULL && addr_pointed2 == NULL)
171         return 0;
172       if(!add_compared_pointers(addr_pointed1, addr_pointed2))
173         return 0;
174
175       pointer_level++;
176       
177       // Some cases are not handled here:
178       // * the pointers lead to different areas (one to the heap, the other to the RW segment ...);
179       // * a pointer leads to the read-only segment of the current object;
180       // * a pointer lead to a different ELF object.
181
182       // The pointers are both in the heap:
183       if(addr_pointed1 > std_heap && (char *)addr_pointed1 < (char*) std_heap + STD_HEAP_SIZE){
184         if(!(addr_pointed2 > std_heap && (char *)addr_pointed2 < (char*) std_heap + STD_HEAP_SIZE))
185           return 1;
186         return compare_heap_area(addr_pointed1, addr_pointed2, NULL, info, other_info, type->dw_type_id, pointer_level);
187       }
188
189       // The pointers are both in the current object R/W segment:
190       else if(addr_pointed1 > start_data && (char*)addr_pointed1 <= (char *)start_data + region_size){
191         if(!(addr_pointed2 > start_data && (char*)addr_pointed2 <= (char *)start_data + region_size))
192           return 1;
193         if(type->dw_type_id == NULL)
194           return  (addr_pointed1 != addr_pointed2);
195         else
196           return  compare_areas_with_type(addr_pointed1, addr_pointed2, info, other_info, type->subtype, region_size, region_type, start_data, pointer_level);
197       }
198
199       else{
200         return (addr_pointed1 != addr_pointed2);
201       }
202     }
203     break;
204   case DW_TAG_structure_type:
205     xbt_dynar_foreach(type->members, cursor, member){
206       XBT_DEBUG("Compare member %s", member->name);
207       res = compare_areas_with_type((char *)area1 + member->offset, (char *)area2 + member->offset, info, other_info, member->subtype, region_size, region_type, start_data, pointer_level);
208       if(res == 1)
209         return res;
210     }
211     break;
212   case DW_TAG_subroutine_type:
213     return -1;
214     break;
215   default:
216     XBT_VERB("Unknown case : %d", type->type);
217     break;
218   }
219   
220   return 0;
221 }
222
223 static int compare_global_variables(int region_type, mc_mem_region_t r1, mc_mem_region_t r2){
224
225   if(!compared_pointers){
226     compared_pointers = xbt_dynar_new(sizeof(pointers_pair_t), pointers_pair_free_voidp);
227   }else{
228     xbt_dynar_reset(compared_pointers);
229   }
230
231   xbt_dynar_t variables;
232   int res;
233   unsigned int cursor = 0;
234   dw_variable_t current_var;
235   size_t offset;
236   void *start_data;
237   void* start_data_binary = mc_binary_info->start_rw;
238   void* start_data_libsimgrid = mc_libsimgrid_info->start_rw;
239
240   mc_object_info_t object_info = NULL;
241   mc_object_info_t other_object_info = NULL;
242   if(region_type == 2){
243     object_info = mc_binary_info;
244     other_object_info = mc_libsimgrid_info;
245     start_data = start_data_binary;
246   }else{
247     object_info = mc_libsimgrid_info;
248     other_object_info = mc_binary_info;
249     start_data = start_data_libsimgrid;
250   }
251   variables = object_info->global_variables;
252
253   xbt_dynar_foreach(variables, cursor, current_var){
254
255     // If the variable is not in this object, skip it:
256     // We do not expect to find a pointer to something which is not reachable
257     // by the global variables.
258     if((char*) current_var->address < (char*) object_info->start_rw
259       || (char*) current_var->address > (char*) object_info->end_rw)
260        continue;
261
262     offset = (char *)current_var->address - (char *)object_info->start_rw;
263
264     dw_type_t bvariable_type = current_var->type;
265     res = compare_areas_with_type((char *)r1->data + offset, (char *)r2->data + offset, object_info, other_object_info, bvariable_type, r1->size, region_type, start_data, 0);
266     if(res == 1){
267       XBT_VERB("Global variable %s (%p - %p) is different between snapshots", current_var->name, (char *)r1->data + offset, (char *)r2->data + offset);
268       xbt_dynar_free(&compared_pointers);
269       compared_pointers = NULL;
270       return 1;
271     }
272
273   }
274
275   xbt_dynar_free(&compared_pointers);
276   compared_pointers = NULL;
277
278   return 0;
279
280 }
281
282 static int compare_local_variables(mc_snapshot_stack_t stack1, mc_snapshot_stack_t stack2, void *heap1, void *heap2){
283   void* start_data_binary = mc_binary_info->start_rw;
284   void* start_data_libsimgrid = mc_libsimgrid_info->start_rw;
285
286   if(!compared_pointers){
287     compared_pointers = xbt_dynar_new(sizeof(pointers_pair_t), pointers_pair_free_voidp);
288   }else{
289     xbt_dynar_reset(compared_pointers);
290   }
291
292   if(xbt_dynar_length(stack1->local_variables) != xbt_dynar_length(stack2->local_variables)){
293     XBT_VERB("Different number of local variables");
294     xbt_dynar_free(&compared_pointers);
295     compared_pointers = NULL;
296     return 1;
297   }else{
298     unsigned int cursor = 0;
299     local_variable_t current_var1, current_var2;
300     int offset1, offset2, res;
301     while(cursor < xbt_dynar_length(stack1->local_variables)){
302       current_var1 = (local_variable_t)xbt_dynar_get_as(stack1->local_variables, cursor, local_variable_t);
303       current_var2 = (local_variable_t)xbt_dynar_get_as(stack2->local_variables, cursor, local_variable_t);
304       if(strcmp(current_var1->name, current_var2->name) != 0 || strcmp(current_var1->frame, current_var2->frame) != 0 || current_var1->ip != current_var2->ip){
305         xbt_dynar_free(&compared_pointers);
306         XBT_VERB("Different name of variable (%s - %s) or frame (%s - %s) or ip (%lu - %lu)", current_var1->name, current_var2->name, current_var1->frame, current_var2->frame, current_var1->ip, current_var2->ip);
307         return 1;
308       }
309       offset1 = (char *)current_var1->address - (char *)std_heap;
310       offset2 = (char *)current_var2->address - (char *)std_heap;
311       XBT_DEBUG("Compare local variable %s of frame %s", current_var1->name, current_var1->frame);
312
313
314       if(current_var1->region == 1) {
315         dw_type_t subtype = current_var1->type;
316         res = compare_areas_with_type( (char *)heap1 + offset1, (char *)heap2 + offset2, mc_libsimgrid_info, mc_binary_info, subtype, 0, 1, start_data_libsimgrid, 0);
317       } else {
318         dw_type_t subtype = current_var2->type;
319         res = compare_areas_with_type( (char *)heap1 + offset1, (char *)heap2 + offset2, mc_binary_info, mc_libsimgrid_info, subtype, 0, 2, start_data_binary, 0);
320       }
321       if(res == 1){
322         XBT_VERB("Local variable %s (%p - %p) in frame %s  is different between snapshots", current_var1->name,(char *)heap1 + offset1, (char *)heap2 + offset2, current_var1->frame);
323         xbt_dynar_free(&compared_pointers);
324         compared_pointers = NULL;
325         return res;
326       }
327       cursor++;
328     }
329     xbt_dynar_free(&compared_pointers);
330     compared_pointers = NULL;
331     return 0;
332   }
333 }
334
335 int snapshot_compare(void *state1, void *state2){
336
337   mc_snapshot_t s1, s2;
338   int num1, num2;
339   
340   if(_sg_mc_property_file && _sg_mc_property_file[0] != '\0'){ /* Liveness MC */
341     s1 = ((mc_visited_pair_t)state1)->graph_state->system_state;
342     s2 = ((mc_visited_pair_t)state2)->graph_state->system_state;
343     num1 = ((mc_visited_pair_t)state1)->num;
344     num2 =  ((mc_visited_pair_t)state2)->num;
345     /* Firstly compare automaton state */
346     /*if(xbt_automaton_state_compare(((mc_pair_t)state1)->automaton_state, ((mc_pair_t)state2)->automaton_state) != 0)
347       return 1;
348     if(xbt_automaton_propositional_symbols_compare_value(((mc_pair_t)state1)->atomic_propositions, ((mc_pair_t)state2)->atomic_propositions) != 0)
349     return 1;*/
350   }else{ /* Safety MC */
351     s1 = ((mc_visited_state_t)state1)->system_state;
352     s2 = ((mc_visited_state_t)state2)->system_state;
353     num1 = ((mc_visited_state_t)state1)->num;
354     num2 = ((mc_visited_state_t)state2)->num;
355   }
356
357   int errors = 0;
358   int res_init;
359
360   xbt_os_timer_t global_timer = xbt_os_timer_new();
361   xbt_os_timer_t timer = xbt_os_timer_new();
362
363   xbt_os_walltimer_start(global_timer);
364
365   #ifdef MC_DEBUG
366     xbt_os_walltimer_start(timer);
367   #endif
368
369   int hash_result = 0;
370   if(_sg_mc_hash) {
371     hash_result = (s1->hash != s2->hash);
372     if(hash_result) {
373       XBT_VERB("(%d - %d) Different hash : 0x%" PRIx64 "--0x%" PRIx64, num1, num2, s1->hash, s2->hash);
374 #ifndef MC_DEBUG
375       return 1;
376 #endif
377     } else {
378       XBT_VERB("(%d - %d) Same hash : 0x%" PRIx64, num1, num2, s1->hash);
379     }
380   }
381
382   int i = 0;
383   size_t size_used1, size_used2;
384   int is_diff = 0;
385
386
387   /* Compare size of stacks */
388   while(i < xbt_dynar_length(s1->stacks)){
389     size_used1 = s1->stack_sizes[i];
390     size_used2 = s2->stack_sizes[i];
391     if(size_used1 != size_used2){
392     #ifdef MC_DEBUG
393       if(is_diff == 0){
394         xbt_os_walltimer_stop(timer);
395         mc_comp_times->stacks_sizes_comparison_time = xbt_os_timer_elapsed(timer);
396       }
397       XBT_DEBUG("(%d - %d) Different size used in stacks : %zu - %zu", num1, num2, size_used1, size_used2);
398       errors++;
399       is_diff = 1;
400     #else
401       #ifdef MC_VERBOSE
402       XBT_VERB("(%d - %d) Different size used in stacks : %zu - %zu", num1, num2, size_used1, size_used2);
403       #endif
404
405       xbt_os_walltimer_stop(timer);
406       xbt_os_timer_free(timer);
407       xbt_os_walltimer_stop(global_timer);
408       mc_snapshot_comparison_time = xbt_os_timer_elapsed(global_timer);
409       xbt_os_timer_free(global_timer);
410
411       return 1;
412     #endif  
413     }
414     i++;
415   }
416
417   #ifdef MC_DEBUG
418     if(is_diff == 0)
419       xbt_os_walltimer_stop(timer);
420     xbt_os_walltimer_start(timer);
421   #endif
422
423   /* Init heap information used in heap comparison algorithm */
424   res_init = init_heap_information((xbt_mheap_t)s1->regions[0]->data, (xbt_mheap_t)s2->regions[0]->data, s1->to_ignore, s2->to_ignore);
425   if(res_init == -1){
426      #ifdef MC_DEBUG
427     XBT_DEBUG("(%d - %d) Different heap information", num1, num2); 
428         errors++; 
429       #else
430         #ifdef MC_VERBOSE
431         XBT_VERB("(%d - %d) Different heap information", num1, num2); 
432         #endif
433
434         xbt_os_walltimer_stop(global_timer);
435         mc_snapshot_comparison_time = xbt_os_timer_elapsed(global_timer);
436         xbt_os_timer_free(global_timer);
437
438         return 1;
439       #endif
440   }
441
442   #ifdef MC_DEBUG
443     xbt_os_walltimer_start(timer);
444   #endif
445
446   /* Stacks comparison */
447   unsigned int  cursor = 0;
448   int diff_local = 0;
449   is_diff = 0;
450   mc_snapshot_stack_t stack1, stack2;
451     
452   while(cursor < xbt_dynar_length(s1->stacks)){
453     stack1 = (mc_snapshot_stack_t)xbt_dynar_get_as(s1->stacks, cursor, mc_snapshot_stack_t);
454     stack2 = (mc_snapshot_stack_t)xbt_dynar_get_as(s2->stacks, cursor, mc_snapshot_stack_t);
455     diff_local = compare_local_variables(stack1, stack2, s1->regions[0]->data, s2->regions[0]->data);
456     if(diff_local > 0){
457       #ifdef MC_DEBUG
458         if(is_diff == 0){
459           xbt_os_walltimer_stop(timer);
460           mc_comp_times->stacks_comparison_time = xbt_os_timer_elapsed(timer);
461         }
462         XBT_DEBUG("(%d - %d) Different local variables between stacks %d", num1, num2, cursor + 1);
463         errors++;
464         is_diff = 1;
465       #else
466         
467         #ifdef MC_VERBOSE
468         XBT_VERB("(%d - %d) Different local variables between stacks %d", num1, num2, cursor + 1);
469         #endif
470           
471         reset_heap_information();
472         xbt_os_walltimer_stop(timer);
473         xbt_os_timer_free(timer);
474         xbt_os_walltimer_stop(global_timer);
475         mc_snapshot_comparison_time = xbt_os_timer_elapsed(global_timer);
476         xbt_os_timer_free(global_timer);
477  
478         return 1;
479       #endif
480     }
481     cursor++;
482   }
483
484
485
486  const char* names[3] = { "?", "libsimgrid", "binary" };
487 #ifdef MC_DEBUG
488  double *times[3] = {
489    NULL,
490    &mc_comp_times->libsimgrid_global_variables_comparison_time,
491    &mc_comp_times->binary_global_variables_comparison_time
492  };
493 #endif
494
495  int k=0;
496  for(k=2; k!=0; --k) {
497     #ifdef MC_DEBUG
498       if(is_diff == 0)
499         xbt_os_walltimer_stop(timer);
500       xbt_os_walltimer_start(timer);
501     #endif
502
503   /* Compare global variables */
504   is_diff = compare_global_variables(k, s1->regions[k], s2->regions[k]);
505   if(is_diff != 0){
506     #ifdef MC_DEBUG
507       xbt_os_walltimer_stop(timer);
508       *times[k] = xbt_os_timer_elapsed(timer);
509       XBT_DEBUG("(%d - %d) Different global variables in %s", num1, num2, names[k]);
510       errors++;
511     #else
512       #ifdef MC_VERBOSE
513       XBT_VERB("(%d - %d) Different global variables in %s", num1, num2, names[k]);
514       #endif
515
516       reset_heap_information();
517       xbt_os_walltimer_stop(timer);
518       xbt_os_timer_free(timer);
519       xbt_os_walltimer_stop(global_timer);
520       mc_snapshot_comparison_time = xbt_os_timer_elapsed(global_timer);
521       xbt_os_timer_free(global_timer);
522
523       return 1;
524     #endif
525   }
526  }
527
528   #ifdef MC_DEBUG
529     xbt_os_walltimer_start(timer);
530   #endif
531
532   /* Compare heap */
533     if(mmalloc_compare_heap((xbt_mheap_t)s1->regions[0]->data,
534                             (xbt_mheap_t)s2->regions[0]->data,
535                             mc_libsimgrid_info,
536                             mc_binary_info) > 0){
537
538     #ifdef MC_DEBUG
539       xbt_os_walltimer_stop(timer);
540       mc_comp_times->heap_comparison_time = xbt_os_timer_elapsed(timer); 
541       XBT_DEBUG("(%d - %d) Different heap (mmalloc_compare)", num1, num2);
542       errors++;
543     #else
544  
545       #ifdef MC_VERBOSE
546       XBT_VERB("(%d - %d) Different heap (mmalloc_compare)", num1, num2);
547       #endif
548        
549       reset_heap_information();
550       xbt_os_walltimer_stop(timer);
551       xbt_os_timer_free(timer);
552       xbt_os_walltimer_stop(global_timer);
553       mc_snapshot_comparison_time = xbt_os_timer_elapsed(global_timer);
554       xbt_os_timer_free(global_timer);
555
556       return 1;
557     #endif
558   }else{
559     #ifdef MC_DEBUG
560       xbt_os_walltimer_stop(timer);
561     #endif
562   }
563
564   reset_heap_information();
565   
566   xbt_os_walltimer_stop(timer);
567   xbt_os_timer_free(timer);
568
569   #ifdef MC_VERBOSE
570     xbt_os_walltimer_stop(global_timer);
571     mc_snapshot_comparison_time = xbt_os_timer_elapsed(global_timer);
572   #endif
573
574   xbt_os_timer_free(global_timer);
575
576   #ifdef MC_DEBUG
577     print_comparison_times();
578   #endif
579
580 #ifdef MC_VERBOSE
581    if(errors || hash_result)
582      XBT_VERB("(%d - %d) Difference found", num1, num2);
583    else
584      XBT_VERB("(%d - %d) No difference found", num1, num2);
585 #endif
586
587 #if defined(MC_DEBUG) && defined(MC_VERBOSE)
588    if(_sg_mc_hash) {
589      // * false positive SHOULD be avoided.
590      // * There MUST not be any false negative.
591
592      XBT_VERB("(%d - %d) State equality hash test is %s %s", num1, num2,
593        (hash_result!=0) == (errors!=0) ? "true" : "false",
594        !hash_result ? "positive" : "negative");
595    }
596 #endif
597
598    return errors > 0 || hash_result;
599   
600 }
601
602 /***************************** Statistics *****************************/
603 /*******************************************************************/
604
605 void print_comparison_times(){
606   XBT_DEBUG("*** Comparison times ***");
607   XBT_DEBUG("- Nb processes : %f", mc_comp_times->nb_processes_comparison_time);
608   XBT_DEBUG("- Nb bytes used : %f", mc_comp_times->bytes_used_comparison_time);
609   XBT_DEBUG("- Stacks sizes : %f", mc_comp_times->stacks_sizes_comparison_time);
610   XBT_DEBUG("- Binary global variables : %f", mc_comp_times->binary_global_variables_comparison_time);
611   XBT_DEBUG("- Libsimgrid global variables : %f", mc_comp_times->libsimgrid_global_variables_comparison_time);
612   XBT_DEBUG("- Heap : %f", mc_comp_times->heap_comparison_time);
613   XBT_DEBUG("- Stacks : %f", mc_comp_times->stacks_comparison_time);
614 }
615
616 /**************************** MC snapshot compare simcall **************************/
617 /***********************************************************************************/
618
619 int SIMIX_pre_mc_compare_snapshots(smx_simcall_t simcall,
620                                    mc_snapshot_t s1, mc_snapshot_t s2){
621   return snapshot_compare(s1, s2);
622 }
623
624 int MC_compare_snapshots(void *s1, void *s2){
625
626   return simcall_mc_compare_snapshots(s1, s2);
627
628 }