Logo AND Algorithmique Numérique Distribuée

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