Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'mc-fastsnapshot' into mc
authorGabriel Corona <gabriel.corona@loria.fr>
Fri, 27 Jun 2014 08:20:15 +0000 (10:20 +0200)
committerGabriel Corona <gabriel.corona@loria.fr>
Fri, 27 Jun 2014 08:20:15 +0000 (10:20 +0200)
Conflicts:
src/mc/mc_visited.c

1  2 
src/mc/mc_global.c
src/mc/mc_private.h
src/mc/mc_visited.c

diff --combined src/mc/mc_global.c
@@@ -29,6 -29,8 +29,8 @@@ e_mc_reduce_t mc_reduce_kind = e_mc_red
  
  int _sg_do_model_check = 0;
  int _sg_mc_checkpoint = 0;
+ int _sg_mc_sparse_checkpoint = 0;
+ int _sg_mc_soft_dirty = 1;
  char *_sg_mc_property_file = NULL;
  int _sg_mc_timeout = 0;
  int _sg_mc_hash = 0;
@@@ -68,6 -70,20 +70,20 @@@ void _mc_cfg_cb_checkpoint(const char *
    _sg_mc_checkpoint = xbt_cfg_get_int(_sg_cfg_set, name);
  }
  
+ void _mc_cfg_cb_sparse_checkpoint(const char *name, int pos) {
+   if (_sg_cfg_init_status && !_sg_do_model_check) {
+     xbt_die("You are specifying a checkpointing value after the initialization (through MSG_config?), but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
+   }
+   _sg_mc_sparse_checkpoint = xbt_cfg_get_boolean(_sg_cfg_set, name);
+ }
+ void _mc_cfg_cb_soft_dirty(const char *name, int pos) {
+   if (_sg_cfg_init_status && !_sg_do_model_check) {
+     xbt_die("You are specifying a soft dirty value after the initialization (through MSG_config?), but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
+   }
+   _sg_mc_soft_dirty = xbt_cfg_get_boolean(_sg_cfg_set, name);
+ }
  void _mc_cfg_cb_property(const char *name, int pos)
  {
    if (_sg_cfg_init_status && !_sg_do_model_check) {
@@@ -129,7 -145,6 +145,7 @@@ void _mc_cfg_cb_comms_determinism(cons
          ("You are specifying a value to enable/disable the detection of determinism in the communications schemes after the initialization (through MSG_config?), but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
    }
    _sg_mc_comms_determinism = xbt_cfg_get_boolean(_sg_cfg_set, name);
 +  mc_reduce_kind = e_mc_reduce_none;
  }
  
  void _mc_cfg_cb_send_determinism(const char *name, int pos)
          ("You are specifying a value to enable/disable the detection of send-determinism in the communications schemes after the initialization (through MSG_config?), but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
    }
    _sg_mc_send_determinism = xbt_cfg_get_boolean(_sg_cfg_set, name);
 +  mc_reduce_kind = e_mc_reduce_none;
  }
  
  /* MC global data structures */
@@@ -222,9 -236,10 +238,10 @@@ static void MC_init_debug_info(void
  }
  
  
+ mc_model_checker_t mc_model_checker = NULL;
  void MC_init()
  {
    int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
  
    mc_time = xbt_new0(double, simix_process_maxpid);
  
    MC_SET_MC_HEAP;
  
+   mc_model_checker = xbt_new0(s_mc_model_checker_t, 1);
+   mc_model_checker->pages = mc_pages_store_new();
+   mc_model_checker->fd_clear_refs = -1;
+   mc_model_checker->fd_pagemap = -1;
    mc_comp_times = xbt_new0(s_mc_comparison_times_t, 1);
  
    /* Initialize statistics */
      MC_ignore_local_variable("ctx", "*");
  
      MC_ignore_local_variable("self", "simcall_BODY_mc_snapshot");
-     MC_ignore_local_variable("next_context", "smx_ctx_sysv_suspend_serial");
+     MC_ignore_local_variable("next_cont"
+       "ext", "smx_ctx_sysv_suspend_serial");
      MC_ignore_local_variable("i", "smx_ctx_sysv_suspend_serial");
  
      /* Ignore local variable about time used for tracing */
      MC_ignore_local_variable("start_time", "*");
  
+     MC_ignore_global_variable("mc_model_checker");
+     // Mot of those things could be moved into mc_model_checker:
      MC_ignore_global_variable("compared_pointers");
      MC_ignore_global_variable("mc_comp_times");
      MC_ignore_global_variable("mc_snapshot_comparison_time");
      MC_ignore_global_variable("maestro_stack_start");
      MC_ignore_global_variable("maestro_stack_end");
      MC_ignore_global_variable("smx_total_comms");
 +    MC_ignore_global_variable("communications_pattern");
 +    MC_ignore_global_variable("initial_communications_pattern");
 +    MC_ignore_global_variable("incomplete_communications_pattern");
  
+     if (MC_is_active()) {
+       MC_ignore_global_variable("mc_diff_info");
+     }
      MC_ignore_heap(mc_time, simix_process_maxpid * sizeof(double));
  
      smx_process_t process;
@@@ -483,12 -508,13 +513,12 @@@ void MC_replay(xbt_fifo_t stack, int st
  {
    int raw_mem = (mmalloc_get_current_heap() == mc_heap);
  
 -  int value, i = 1, count = 1;
 +  int value, i = 1, count = 1, call = 0, j;
    char *req_str;
    smx_simcall_t req = NULL, saved_req = NULL;
    xbt_fifo_item_t item, start_item;
    mc_state_t state;
    smx_process_t process = NULL;
 -  int comm_pattern = 0;
    smx_action_t current_comm;
  
    XBT_DEBUG("**** Begin Replay ****");
  
    MC_SET_MC_HEAP;
  
 -  if ((mc_reduce_kind == e_mc_reduce_dpor) && !_sg_mc_comms_determinism && !_sg_mc_send_determinism) {
 +  if (mc_reduce_kind == e_mc_reduce_dpor) {
      xbt_dict_reset(first_enabled_state);
      xbt_swag_foreach(process, simix_global->process_list) {
        if (MC_process_is_enabled(process)) {
    }
  
    if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
 -    xbt_dynar_reset(communications_pattern);
 -    xbt_dynar_reset(incomplete_communications_pattern);
 +    for (j=0; j<simix_process_maxpid; j++) {
 +      xbt_dynar_reset((xbt_dynar_t)xbt_dynar_get_as(communications_pattern, j, xbt_dynar_t));
 +    }
 +    for (j=0; j<simix_process_maxpid; j++) {
 +      xbt_dynar_reset((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, j, xbt_dynar_t));
 +    }
    }
  
    MC_SET_STD_HEAP;
      state = (mc_state_t) xbt_fifo_get_item_content(item);
      saved_req = MC_state_get_executed_request(state, &value);
  
 -    if ((mc_reduce_kind == e_mc_reduce_dpor) && !_sg_mc_comms_determinism && !_sg_mc_send_determinism) {
 +    if (mc_reduce_kind == e_mc_reduce_dpor) {
        MC_SET_MC_HEAP;
        char *key = bprintf("%lu", saved_req->issuer->pid);
        xbt_dict_remove(first_enabled_state, key);
        /* TODO : handle test and testany simcalls */
        if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
          if (req->call == SIMCALL_COMM_ISEND)
 -          comm_pattern = 1;
 +          call = 1;
          else if (req->call == SIMCALL_COMM_IRECV)
 -          comm_pattern = 2;
 +          call = 2;
          else if (req->call == SIMCALL_COMM_WAIT)
 -          comm_pattern = 3;
 +          call = 3;
          else if (req->call == SIMCALL_COMM_WAITANY)
 -          comm_pattern = 4;
 +          call = 4;
        }
  
        SIMIX_simcall_pre(req, value);
  
        if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
          MC_SET_MC_HEAP;
 -        if (comm_pattern == 1 || comm_pattern == 2) {
 -          get_comm_pattern(communications_pattern, req, comm_pattern);
 -        } else if (comm_pattern == 3 /* || comm_pattern == 4 */ ) {
 +        if (call == 1) { /* Send */
 +          get_comm_pattern(communications_pattern, req, call);
 +        } else if (call == 2) { /* Recv */
 +          get_comm_pattern(communications_pattern, req, call);
 +        } else if (call == 3) { /* Wait */
            current_comm = simcall_comm_wait__get__comm(req);
 -          if (current_comm->comm.refcount == 1) {       /* First wait only must be considered */
 +          if (current_comm->comm.refcount == 1)  /* First wait only must be considered */
              complete_comm_pattern(communications_pattern, current_comm);
 -          }
 -        } else if (comm_pattern == 4 /* || comm_pattern == 4 */ ) {
 -          current_comm =
 -              xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), value,
 -                               smx_action_t);
 -          if (current_comm->comm.refcount == 1) {       /* First wait only must be considered */
 +        } else if (call == 4) { /* WaitAny */
 +          current_comm = xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), value, smx_action_t);
 +          if (current_comm->comm.refcount == 1) /* First wait only must be considered */
              complete_comm_pattern(communications_pattern, current_comm);
 -          }
          }
          MC_SET_STD_HEAP;
 -        comm_pattern = 0;
 +        call = 0;
        }
  
  
  
        count++;
  
 -      if ((mc_reduce_kind == e_mc_reduce_dpor) && !_sg_mc_comms_determinism && !_sg_mc_send_determinism) {
 +      if (mc_reduce_kind == e_mc_reduce_dpor) {
          MC_SET_MC_HEAP;
          /* Insert in dict all enabled processes */
          xbt_swag_foreach(process, simix_global->process_list) {
diff --combined src/mc/mc_private.h
@@@ -9,6 -9,7 +9,7 @@@
  
  #include "simgrid_config.h"
  #include <stdio.h>
+ #include <stdbool.h>
  #ifndef WIN32
  #include <sys/mman.h>
  #endif
  #include "msg/datatypes.h"
  #include "xbt/strbuff.h"
  #include "xbt/parmap.h"
+ #include "mc_mmu.h"
+ #include "mc_page_store.h"
+ SG_BEGIN_DECL()
  
  typedef struct s_dw_frame s_dw_frame_t, *dw_frame_t;
  typedef struct s_mc_function_index_item s_mc_function_index_item_t, *mc_function_index_item_t;
@@@ -43,8 -48,17 +48,17 @@@ typedef struct s_mc_mem_region
    void *data;
    // Size of the data region:
    size_t size;
+   // For per-page snapshots, this is an array to the number of
+   size_t* page_numbers;
  } s_mc_mem_region_t, *mc_mem_region_t;
  
+ static inline  __attribute__ ((always_inline))
+ bool mc_region_contain(mc_mem_region_t region, void* p)
+ {
+   return p >= region->start_addr &&
+     p < (void*)((char*) region->start_addr + region->size);
+ }
  /** Ignored data
   *
   *  Some parts of the snapshot are ignored by zeroing them out: the real
@@@ -69,6 -83,17 +83,17 @@@ typedef struct s_mc_snapshot
    xbt_dynar_t ignored_data;
  } s_mc_snapshot_t, *mc_snapshot_t;
  
+ mc_mem_region_t mc_get_snapshot_region(void* addr, mc_snapshot_t snapshot);
+ static inline __attribute__ ((always_inline))
+ mc_mem_region_t mc_get_region_hinted(void* addr, mc_snapshot_t snapshot, mc_mem_region_t region)
+ {
+   if (mc_region_contain(region, addr))
+     return region;
+   else
+     return mc_get_snapshot_region(addr, snapshot);
+ }
  /** Information about a given stack frame
   *
   */
@@@ -85,8 -110,6 +110,6 @@@ typedef struct s_mc_stack_frame 
  
  typedef struct s_mc_snapshot_stack{
    xbt_dynar_t local_variables;
-   void *stack_pointer;
-   void *real_address;
    xbt_dynar_t stack_frames; // mc_stack_frame_t
  }s_mc_snapshot_stack_t, *mc_snapshot_stack_t;
  
@@@ -105,42 -128,56 +128,56 @@@ typedef struct s_mc_checkpoint_ignore_r
    size_t size;
  }s_mc_checkpoint_ignore_region_t, *mc_checkpoint_ignore_region_t;
  
- inline static void* mc_snapshot_get_heap_end(mc_snapshot_t snapshot) {
-   if(snapshot==NULL)
-     xbt_die("snapshot is NULL");
-   xbt_mheap_t heap = (xbt_mheap_t)snapshot->regions[0]->data;
-   return heap->breakval;
- }
+ static void* mc_snapshot_get_heap_end(mc_snapshot_t snapshot);
  
  mc_snapshot_t SIMIX_pre_mc_snapshot(smx_simcall_t simcall);
  mc_snapshot_t MC_take_snapshot(int num_state);
  void MC_restore_snapshot(mc_snapshot_t);
  void MC_free_snapshot(mc_snapshot_t);
  
- /** \brief Translate a pointer from process address space to snapshot address space
-  *
-  *  The address space contains snapshot of the main/application memory:
-  *  this function finds the address in a given snaphot for a given
-  *  real/application address.
-  *
-  *  For read only memory regions and other regions which are not int the
-  *  snapshot, the address is not changed.
-  *
-  *  \param addr     Application address
-  *  \param snapshot The snapshot of interest (if NULL no translation is done)
-  *  \return         Translated address in the snapshot address space
-  * */
- void* mc_translate_address(uintptr_t addr, mc_snapshot_t snapshot);
+ int mc_important_snapshot(mc_snapshot_t snapshot);
  
- /** \brief Translate a pointer from the snapshot address space to the application address space
-  *
-  *  This is the inverse of mc_translate_address.
+ size_t* mc_take_page_snapshot_region(void* data, size_t page_count, uint64_t* pagemap, size_t* reference_pages);
+ void mc_free_page_snapshot_region(size_t* pagenos, size_t page_count);
+ void mc_restore_page_snapshot_region(mc_mem_region_t region, size_t page_count, uint64_t* pagemap, mc_mem_region_t reference_region);
+ mc_mem_region_t mc_region_new_sparse(int type, void *start_addr, size_t size, mc_mem_region_t ref_reg);
+ void mc_region_restore_sparse(mc_mem_region_t reg, mc_mem_region_t ref_reg);
+ void mc_softdirty_reset();
+ static inline __attribute__((always_inline))
+ bool mc_snapshot_region_linear(mc_mem_region_t region) {
+   return !region || !region->data;
+ }
+ void* mc_snapshot_read_fragmented(void* addr, mc_mem_region_t region, void* target, size_t size);
+ void* mc_snapshot_read(void* addr, mc_snapshot_t snapshot, void* target, size_t size);
+ int mc_snapshot_region_memcp(
+   void* addr1, mc_mem_region_t region1,
+   void* addr2, mc_mem_region_t region2, size_t size);
+ int mc_snapshot_memcp(
+   void* addr1, mc_snapshot_t snapshot1,
+   void* addr2, mc_snapshot_t snapshot2, size_t size);
+ static void* mc_snapshot_read_pointer(void* addr, mc_snapshot_t snapshot);
+ /** @brief State of the model-checker (global variables for the model checker)
   *
-  * \param addr    Address in the snapshot address space
-  * \param snapsot Snapshot of interest (if NULL no translation is done)
-  * \return        Translated address in the application address space
+  *  Each part of the state of the model chercker represented as a global
+  *  variable prevents some sharing between snapshots and must be ignored.
+  *  By moving as much state as possible in this structure allocated
+  *  on the model-chercker heap, we avoid those issues.
   */
- uintptr_t mc_untranslate_address(void* addr, mc_snapshot_t snapshot);
+ typedef struct s_mc_model_checker {
+   // This is the parent snapshot of the current state:
+   mc_snapshot_t parent_snapshot;
+   mc_pages_store_t pages;
+   int fd_clear_refs;
+   int fd_pagemap;
+ } s_mc_model_checker_t, *mc_model_checker_t;
+ extern mc_model_checker_t mc_model_checker;
  
  extern xbt_dynar_t mc_checkpoint_ignore;
  
@@@ -342,7 -379,7 +379,7 @@@ typedef struct s_mc_visited_state
  }s_mc_visited_state_t, *mc_visited_state_t;
  
  extern xbt_dynar_t visited_states;
 -int is_visited_state(void);
 +mc_visited_state_t is_visited_state(void);
  void visited_state_free(mc_visited_state_t state);
  void visited_state_free_voidp(void *s);
  
@@@ -477,7 -514,6 +514,6 @@@ struct s_dw_type
  };
  
  void* mc_member_resolve(const void* base, dw_type_t type, dw_type_t member, mc_snapshot_t snapshot);
- void* mc_member_snapshot_resolve(const void* base, dw_type_t type, dw_type_t member, mc_snapshot_t snapshot);
  
  typedef struct s_dw_variable{
    Dwarf_Off dwarf_offset; /* Global offset of the field. */
@@@ -592,7 -628,6 +628,7 @@@ typedef struct s_mc_comm_pattern
    void *data;
  }s_mc_comm_pattern_t, *mc_comm_pattern_t;
  
 +extern xbt_dynar_t initial_communications_pattern;
  extern xbt_dynar_t communications_pattern;
  extern xbt_dynar_t incomplete_communications_pattern;
  
@@@ -619,5 -654,118 +655,118 @@@ bool mc_address_test(mc_address_set_t p
   * */
  uint64_t mc_hash_processes_state(int num_state, xbt_dynar_t stacks);
  
+ /* *********** Snapshot *********** */
+ static inline __attribute__((always_inline))
+ void* mc_translate_address_region(uintptr_t addr, mc_mem_region_t region)
+ {
+     size_t pageno = mc_page_number(region->start_addr, (void*) addr);
+     size_t snapshot_pageno = region->page_numbers[pageno];
+     const void* snapshot_page = mc_page_store_get_page(mc_model_checker->pages, snapshot_pageno);
+     return (char*) snapshot_page + mc_page_offset((void*) addr);
+ }
+ /** \brief Translate a pointer from process address space to snapshot address space
+  *
+  *  The address space contains snapshot of the main/application memory:
+  *  this function finds the address in a given snaphot for a given
+  *  real/application address.
+  *
+  *  For read only memory regions and other regions which are not int the
+  *  snapshot, the address is not changed.
+  *
+  *  \param addr     Application address
+  *  \param snapshot The snapshot of interest (if NULL no translation is done)
+  *  \return         Translated address in the snapshot address space
+  * */
+ static inline __attribute__((always_inline))
+ void* mc_translate_address(uintptr_t addr, mc_snapshot_t snapshot)
+ {
+   // If not in a process state/clone:
+   if (!snapshot) {
+     return (uintptr_t *) addr;
+   }
+   mc_mem_region_t region = mc_get_snapshot_region((void*) addr, snapshot);
+   xbt_assert(mc_region_contain(region, (void*) addr), "Trying to read out of the region boundary.");
+   if (!region) {
+     return (void *) addr;
+   }
+   // Flat snapshot:
+   else if (region->data) {
+     uintptr_t offset = addr - (uintptr_t) region->start_addr;
+     return (void *) ((uintptr_t) region->data + offset);
+   }
+   // Per-page snapshot:
+   else if (region->page_numbers) {
+     return mc_translate_address_region(addr, region);
+   }
+   else {
+     xbt_die("No data for this memory region");
+   }
+ }
+ static inline __attribute__ ((always_inline))
+   void* mc_snapshot_get_heap_end(mc_snapshot_t snapshot) {
+   if(snapshot==NULL)
+       xbt_die("snapshot is NULL");
+   void** addr = &((xbt_mheap_t)std_heap)->breakval;
+   return mc_snapshot_read_pointer(addr, snapshot);
+ }
+ static inline __attribute__ ((always_inline))
+ void* mc_snapshot_read_pointer(void* addr, mc_snapshot_t snapshot)
+ {
+   void* res;
+   return *(void**) mc_snapshot_read(addr, snapshot, &res, sizeof(void*));
+ }
+ /** @brief Read memory from a snapshot region
+  *
+  *  @param addr    Process (non-snapshot) address of the data
+  *  @param region  Snapshot memory region where the data is located
+  *  @param target  Buffer to store the value
+  *  @param size    Size of the data to read in bytes
+  *  @return Pointer where the data is located (target buffer of original location)
+  */
+ static inline __attribute__((always_inline))
+ void* mc_snapshot_read_region(void* addr, mc_mem_region_t region, void* target, size_t size)
+ {
+   uintptr_t offset = (uintptr_t) addr - (uintptr_t) region->start_addr;
+   xbt_assert(addr >= region->start_addr && (char*) addr+size < (char*)region->start_addr+region->size,
+     "Trying to read out of the region boundary.");
+   // Linear memory region:
+   if (region->data) {
+     return (void*) ((uintptr_t) region->data + offset);
+   }
+   // Fragmented memory region:
+   else if (region->page_numbers) {
+     void* end = (char*) addr + size - 1;
+     if( mc_same_page(addr, end) ) {
+       // The memory is contained in a single page:
+       return mc_translate_address_region((uintptr_t) addr, region);
+     } else {
+       // The memory spans several pages:
+       return mc_snapshot_read_fragmented(addr, region, target, size);
+     }
+   }
+   else {
+     xbt_die("No data available for this region");
+   }
+ }
+ SG_END_DECL()
  #endif
  
diff --combined src/mc/mc_visited.c
@@@ -104,12 -104,14 +104,12 @@@ int get_search_interval(xbt_dynar_t lis
    int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
    void *ref_test;
  
 -  if (_sg_mc_safety) {
 -    nb_processes = ((mc_visited_state_t) ref)->nb_processes;
 -    heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
 -  } else if (_sg_mc_liveness) {
 +  if (_sg_mc_liveness) {
      nb_processes = ((mc_visited_pair_t) ref)->nb_processes;
      heap_bytes_used = ((mc_visited_pair_t) ref)->heap_bytes_used;
    } else {
 -    xbt_die("Both liveness and safety are disabled.");
 +    nb_processes = ((mc_visited_state_t) ref)->nb_processes;
 +    heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
    }
  
    int start = 0;
  
    while (start <= end) {
      cursor = (start + end) / 2;
 -    if (_sg_mc_safety) {
 +    if (_sg_mc_liveness) {
        ref_test =
 -          (mc_visited_state_t) xbt_dynar_get_as(list, cursor,
 -                                                mc_visited_state_t);
 -      nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
 -      heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
 -    } else if (_sg_mc_liveness) {
 -      ref_test =
 -          (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
 +        (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
        nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
        heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
      } else {
 -      nb_processes_test = 0;
 -      heap_bytes_used_test = 0;
 -      xbt_die("Both liveness and safety are disabled.");
 +      ref_test =
 +        (mc_visited_state_t) xbt_dynar_get_as(list, cursor,
 +                                              mc_visited_state_t);
 +      nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
 +      heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
      }
      if (nb_processes_test < nb_processes) {
        start = cursor + 1;
          *min = *max = cursor;
          previous_cursor = cursor - 1;
          while (previous_cursor >= 0) {
 -          if (_sg_mc_safety) {
 +          if (_sg_mc_liveness) {
 +            ref_test =
 +              (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor,
 +                                                   mc_visited_pair_t);
 +            nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
 +            heap_bytes_used_test =
 +              ((mc_visited_pair_t) ref_test)->heap_bytes_used;
 +          } else {
              ref_test =
                  (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor,
                                                        mc_visited_state_t);
              nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
              heap_bytes_used_test =
                  ((mc_visited_state_t) ref_test)->heap_bytes_used;
 -          } else if (_sg_mc_liveness) {
 -            ref_test =
 -                (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor,
 -                                                     mc_visited_pair_t);
 -            nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
 -            heap_bytes_used_test =
 -                ((mc_visited_pair_t) ref_test)->heap_bytes_used;
            }
            if (nb_processes_test != nb_processes
                || heap_bytes_used_test != heap_bytes_used)
          }
          next_cursor = cursor + 1;
          while (next_cursor < xbt_dynar_length(list)) {
 -          if (_sg_mc_safety) {
 -            ref_test =
 -                (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor,
 -                                                      mc_visited_state_t);
 -            nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
 -            heap_bytes_used_test =
 -                ((mc_visited_state_t) ref_test)->heap_bytes_used;
 -          } else if (_sg_mc_liveness) {
 +          if (_sg_mc_liveness) {
              ref_test =
                  (mc_visited_pair_t) xbt_dynar_get_as(list, next_cursor,
                                                       mc_visited_pair_t);
              nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
              heap_bytes_used_test =
                  ((mc_visited_pair_t) ref_test)->heap_bytes_used;
 +          } else {
 +            ref_test =
 +              (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor,
 +                                                    mc_visited_state_t);
 +            nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
 +            heap_bytes_used_test =
 +              ((mc_visited_state_t) ref_test)->heap_bytes_used;
            }
            if (nb_processes_test != nb_processes
                || heap_bytes_used_test != heap_bytes_used)
  /**
   * \brief Checks whether a given state has already been visited by the algorithm.
   */
 -int is_visited_state()
 +
 +mc_visited_state_t is_visited_state()
  {
  
    if (_sg_mc_visited == 0)
 -    return -1;
 +    return NULL;
 +
 +  /* If comm determinism verification, we cannot stop the exploration if some 
 +     communications are not finished (at least, data are transfered). These communications 
 +     are incomplete and they cannot be analyzed and compared with the initial pattern */
 +  if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
 +    int current_process = 1;
 +    while (current_process < simix_process_maxpid) {
 +      if (!xbt_dynar_is_empty((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, current_process, xbt_dynar_t)))
 +        return NULL;
 +      current_process++;
 +    }
 +  }
  
    int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
  
      if (!mc_mem_set)
        MC_SET_STD_HEAP;
  
 -    return -1;
 +    return NULL;
  
    } else {
  
                  ("State %d already visited ! (equal to state %d (state %d in dot_output))",
                   new_state->num, state_test->num, new_state->other_num);
  
 -          // Replace the old state with the new one (why?):
 +          /* Replace the old state with the new one (with a bigger num) 
 +             (when the max number of visited states is reached,  the oldest 
 +             one is removed according to its number (= with the min number) */
            xbt_dynar_remove_at(visited_states, cursor, NULL);
            xbt_dynar_insert_at(visited_states, cursor, &new_state);
  
            if (!mc_mem_set)
              MC_SET_STD_HEAP;
 -          return new_state->other_num;
 +          return state_test;
          }
          cursor++;
        }
  
 -      // The state has not been visited, add it to the list:
 +      // The state has not been visited: insert the state in the dynamic array.
        xbt_dynar_insert_at(visited_states, min, &new_state);
  
      } else {
      // We have reached the maximum number of stored states;
      if (xbt_dynar_length(visited_states) > _sg_mc_visited) {
  
 -      // Find the (index of the) older state:
 +      // Find the (index of the) older state (with the smallest num):
        int min2 = mc_stats->expanded_states;
        unsigned int cursor2 = 0;
        unsigned int index2 = 0;
-       xbt_dynar_foreach(visited_states, cursor2, state_test) {
-         if (state_test->num < min2) {
+       xbt_dynar_foreach(visited_states, cursor2, state_test){
+         if (!mc_important_snapshot(state_test->system_state) && state_test->num < min2) {
            index2 = cursor2;
            min2 = state_test->num;
          }
      if (!mc_mem_set)
        MC_SET_STD_HEAP;
  
 -    return -1;
 +    return NULL;
  
    }
  }
@@@ -416,6 -407,7 +416,6 @@@ int is_visited_pair(mc_visited_pair_t p
          pair_test =
              (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, cursor,
                                                   mc_visited_pair_t);
 -        //if(pair_test->acceptance_pair == 0){ /* Acceptance pair have been already checked before */
          if (xbt_automaton_state_compare
              (pair_test->automaton_state, new_pair->automaton_state) == 0) {
            if (xbt_automaton_propositional_symbols_compare_value
                return new_pair->other_num;
              }
            }
 -          //}
          }
          cursor++;
        }
        unsigned int cursor2 = 0;
        unsigned int index2 = 0;
        xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
-         if (pair_test->num < min2) {
+         if (!mc_important_snapshot(pair_test->graph_state->system_state) && pair_test->num < min2) {
            index2 = cursor2;
            min2 = pair_test->num;
          }