Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
model-checker : fix dpor with state equality reduction
[simgrid.git] / src / mc / mc_dpor.c
index 93e7d07..11cc06c 100644 (file)
-/* Copyright (c) 2008 Martin Quinson, Cristian Rosa.
-   All rights reserved.                                          */
+/* Copyright (c) 2008-2012. Da SimGrid Team. All rights reserved.           */
 
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
-#include "private.h"
+#include "mc_private.h"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dpor, mc,
                                 "Logging specific to MC DPOR exploration");
 
+xbt_dynar_t visited_states;
+
+static int is_visited_state(void);
+
+static int is_visited_state(){
+
+  if(_sg_mc_visited == 0)
+    return 0;
+
+  int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
+
+  MC_SET_RAW_MEM;
+
+  mc_snapshot_t new_state = NULL;
+  new_state = MC_take_snapshot();  
+
+  MC_UNSET_RAW_MEM;
+  
+  if(xbt_dynar_is_empty(visited_states)){
+
+    MC_SET_RAW_MEM;
+    xbt_dynar_push(visited_states, &new_state); 
+    MC_UNSET_RAW_MEM;
+
+    if(raw_mem_set)
+      MC_SET_RAW_MEM;
+    return 0;
+
+  }else{
+
+    MC_SET_RAW_MEM;
+    
+    unsigned int cursor = 0;
+    mc_snapshot_t state_test = NULL;
+     
+    xbt_dynar_foreach(visited_states, cursor, state_test){
+      if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug))
+        XBT_DEBUG("****** Pair visited #%d ******", cursor + 1);
+      if(snapshot_compare(new_state, state_test, NULL, NULL) == 0){
+        if(raw_mem_set)
+          MC_SET_RAW_MEM;
+        else
+          MC_UNSET_RAW_MEM;
+        
+        return 1;
+      }   
+    }
+
+    if(xbt_dynar_length(visited_states) == _sg_mc_visited){
+      mc_snapshot_t state_to_remove = NULL;
+      xbt_dynar_shift(visited_states, &state_to_remove);
+      MC_free_snapshot(state_to_remove);
+    }
+
+    xbt_dynar_push(visited_states, &new_state); 
+    
+    MC_UNSET_RAW_MEM;
+
+    if(raw_mem_set)
+      MC_SET_RAW_MEM;
+    
+    return 0;
+    
+  }
+}
+
 /**
  *  \brief Initialize the DPOR exploration algorithm
  */
 void MC_dpor_init()
 {
-  mc_state_t initial_state = NULL;
-  mc_transition_t trans, trans_tmp = NULL;
-  xbt_setset_cursor_t cursor = NULL;
+  
+  int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
 
+  mc_state_t initial_state = NULL;
+  smx_process_t process;
+  
   /* Create the initial state and push it into the exploration stack */
   MC_SET_RAW_MEM;
+
   initial_state = MC_state_new();
-  xbt_fifo_unshift(mc_stack, initial_state);
+  visited_states = xbt_dynar_new(sizeof(mc_snapshot_t), NULL);
+
   MC_UNSET_RAW_MEM;
 
-  /* Schedule all the processes to detect the transitions of the initial state */
-  DEBUG0("**************************************************");
-  DEBUG0("Initial state");
+  XBT_DEBUG("**************************************************");
+  XBT_DEBUG("Initial state");
 
-  while (xbt_swag_size(simix_global->process_to_run)) {
-    MC_schedule_enabled_processes();
-    MC_execute_surf_actions();
-  }
+  /* Wait for requests (schedules processes) */
+  MC_wait_for_requests();
 
   MC_SET_RAW_MEM;
-  MC_trans_compute_enabled(initial_state->enabled_transitions,
-                           initial_state->transitions);
-
-  /* Fill the interleave set of the initial state with an enabled process */
-  trans = xbt_setset_set_choose(initial_state->enabled_transitions);
-  if (trans) {
-    DEBUG1("Choosing process %s for next interleave",
-           trans->process->name);
-    xbt_setset_foreach(initial_state->enabled_transitions, cursor,
-                       trans_tmp) {
-      if (trans_tmp->process == trans->process)
-        xbt_setset_set_insert(initial_state->interleave, trans_tmp);
+  /* Get an enabled process and insert it in the interleave set of the initial state */
+  xbt_swag_foreach(process, simix_global->process_list){
+    if(MC_process_is_enabled(process)){
+      MC_state_interleave_process(initial_state, process);
+      XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
     }
   }
+
+  xbt_fifo_unshift(mc_stack_safety, initial_state);
+
   MC_UNSET_RAW_MEM;
 
-  /* Update Statistics */
-  mc_stats->state_size +=
-      xbt_setset_set_size(initial_state->enabled_transitions);
+  if(raw_mem_set)
+    MC_SET_RAW_MEM;
+  else
+    MC_UNSET_RAW_MEM;
+  
 }
 
 
 /**
- *     \brief Perform the model-checking operation using a depth-first search exploration
+ *   \brief Perform the model-checking operation using a depth-first search exploration
  *         with Dynamic Partial Order Reductions
  */
 void MC_dpor(void)
 {
-  mc_transition_t trans, trans_tmp = NULL;
-  mc_state_t next_state = NULL;
-  xbt_setset_cursor_t cursor = NULL;
 
-  while (xbt_fifo_size(mc_stack) > 0) {
+  char *req_str;
+  int value;
+  smx_simcall_t req = NULL, prev_req = NULL;
+  s_smx_simcall_t req2;
+  mc_state_t state = NULL, prev_state = NULL, next_state = NULL, restore_state=NULL;
+  smx_process_t process = NULL;
+  xbt_fifo_item_t item = NULL;
+  int pos, i;
+  int interleave_proc[simix_process_maxpid];
 
-    DEBUG0("**************************************************");
-
-    /* FIXME: Think about what happen if there are no transitions but there are
-       some actions on the models. (ex. all the processes do a sleep(0) in a round). */
+  while (xbt_fifo_size(mc_stack_safety) > 0) {
 
     /* Get current state */
-    mc_current_state = (mc_state_t)
-        xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack));
+    state = (mc_state_t) 
+      xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_safety));
 
-    /* If there are transitions to execute and the maximun depth has not been reached 
-       then perform one step of the exploration algorithm */
-    if (xbt_setset_set_size(mc_current_state->interleave) > 0
-        && xbt_fifo_size(mc_stack) < MAX_DEPTH) {
+    XBT_DEBUG("**************************************************");
+    XBT_DEBUG("Exploration depth=%d (state=%p)(%u interleave)",
+              xbt_fifo_size(mc_stack_safety), state,
+              MC_state_interleave_size(state));
 
-      DEBUG4("Exploration detph=%d (state=%p)(%d interleave) (%d enabled)",
-             xbt_fifo_size(mc_stack), mc_current_state,
-             xbt_setset_set_size(mc_current_state->interleave),
-             xbt_setset_set_size(mc_current_state->enabled_transitions));
+    /* Update statistics */
+    mc_stats->visited_states++;
 
-      /* Update statistics */
-      mc_stats->visited_states++;
+    /* If there are processes to interleave and the maximum depth has not been reached
+       then perform one step of the exploration algorithm */
+    if (xbt_fifo_size(mc_stack_safety) < _sg_mc_max_depth &&
+        (req = MC_state_get_request(state, &value))) {
+
+      /* Debug information */
+      if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
+        req_str = MC_request_to_string(req, value);
+        XBT_DEBUG("Execute: %s", req_str);
+        xbt_free(req_str);
+      }
+
+      MC_state_set_executed_request(state, req, value);
       mc_stats->executed_transitions++;
 
-      /* Choose a transition to execute from the interleave set of the current
-         state, and create the data structures for the new expanded state in the
-         exploration stack. */
-      MC_SET_RAW_MEM;
-      trans = xbt_setset_set_extract(mc_current_state->interleave);
+      /* Answer the request */
+      SIMIX_simcall_pre(req, value); /* After this call req is no longer usefull */
 
-      /* Add the transition in the done set of the current state */
-      xbt_setset_set_insert(mc_current_state->done, trans);
+      /* Wait for requests (schedules processes) */
+      MC_wait_for_requests();
 
-      next_state = MC_state_new();
-      xbt_fifo_unshift(mc_stack, next_state);
+      /* Create the new expanded state */
+      MC_SET_RAW_MEM;
 
-      /* Set it as the executed transition of the current state */
-      mc_current_state->executed_transition = trans;
-      MC_UNSET_RAW_MEM;
+      next_state = MC_state_new();
 
-      /* Execute the selected transition by scheduling it's associated process.
-         Then schedule every process that got ready to run due to the execution
-         of the transition */
-      DEBUG1("Executing transition %s", trans->name);
-      SIMIX_process_schedule(trans->process);
-      MC_execute_surf_actions();
+      if(!is_visited_state()){
+     
+        /* Get an enabled process and insert it in the interleave set of the next state */
+        xbt_swag_foreach(process, simix_global->process_list){
+          if(MC_process_is_enabled(process)){
+            MC_state_interleave_process(next_state, process);
+            XBT_DEBUG("Process %lu enabled with simcall %d", process->pid, process->simcall.call);
+          }
+        }
 
-      while (xbt_swag_size(simix_global->process_to_run)) {
-        MC_schedule_enabled_processes();
-        MC_execute_surf_actions();
-      }
+        if(_sg_mc_checkpoint && ((xbt_fifo_size(mc_stack_safety) + 1) % _sg_mc_checkpoint == 0)){
+          next_state->system_state = MC_take_snapshot();
+        }
 
-      /* Calculate the enabled transitions set of the next state */
-      MC_SET_RAW_MEM;
+      }else{
 
-      xbt_setset_foreach(mc_current_state->transitions, cursor, trans_tmp) {
-        if (trans_tmp->process != trans->process) {
-          xbt_setset_set_insert(next_state->transitions, trans_tmp);
-        }
+        XBT_DEBUG("State already visited !");
+        
       }
 
-      MC_trans_compute_enabled(next_state->enabled_transitions,
-                               next_state->transitions);
-
-      /* Choose one transition to interleave from the enabled transition set */
-      trans = xbt_setset_set_choose(next_state->enabled_transitions);
-      if (trans) {
-        DEBUG1("Choosing process %s for next interleave",
-               trans->process->name);
-        xbt_setset_foreach(next_state->enabled_transitions, cursor,
-                           trans_tmp) {
-          if (trans_tmp->process == trans->process)
-            xbt_setset_set_insert(next_state->interleave, trans_tmp);
-        }
-      }
+      xbt_fifo_unshift(mc_stack_safety, next_state);
       MC_UNSET_RAW_MEM;
 
-      /* Update Statistics */
-      mc_stats->state_size +=
-          xbt_setset_set_size(next_state->enabled_transitions);
-
       /* Let's loop again */
 
       /* The interleave set is empty or the maximum depth is reached, let's back-track */
     } else {
-      DEBUG0("There are no more transitions to interleave.");
 
+      if(xbt_fifo_size(mc_stack_safety) == _sg_mc_max_depth)  
+        XBT_WARN("/!\\ Max depth reached ! /!\\ ");
+      else
+        XBT_DEBUG("There are no more processes to interleave.");
 
-      /* Check for deadlocks */
-      xbt_setset_substract(mc_current_state->transitions,
-                           mc_current_state->done);
-      if (xbt_setset_set_size(mc_current_state->transitions) > 0) {
-        INFO0("**************************");
-        INFO0("*** DEAD-LOCK DETECTED ***");
-        INFO0("**************************");
-        INFO0("Locked transitions:");
-        xbt_setset_foreach(mc_current_state->transitions, cursor, trans) {
-          INFO3("%s [src=%p, dst=%p]", trans->name,
-                trans->wait.comm->src_proc, trans->wait.comm->dst_proc);
-        }
-
-        INFO0("Counter-example execution trace:");
-        MC_dump_stack(mc_stack);
+      /* Trash the current state, no longer needed */
+      MC_SET_RAW_MEM;
+      xbt_fifo_shift(mc_stack_safety);
+      MC_state_delete(state);
+      MC_UNSET_RAW_MEM;
 
-        MC_print_statistics(mc_stats);
-        xbt_abort();
+      /* Check for deadlocks */
+      if(MC_deadlock_check()){
+        MC_show_deadlock(NULL);
+        return;
       }
 
-      mc_transition_t q = NULL;
-      xbt_fifo_item_t item = NULL;
-      mc_state_t state = NULL;
-
-      /*
-         INFO0("*********************************");
-         MC_show_stack(mc_stack); */
-
-      /* Trash the current state, no longer needed */
       MC_SET_RAW_MEM;
-      xbt_fifo_shift(mc_stack);
-      MC_state_delete(mc_current_state);
-
       /* Traverse the stack backwards until a state with a non empty interleave
          set is found, deleting all the states that have it empty in the way.
-         For each deleted state, check if the transition that has generated it 
-         (from it's predecesor state), depends on any other previous transition 
+         For each deleted state, check if the request that has generated it 
+         (from it's predecesor state), depends on any other previous request 
          executed before it. If it does then add it to the interleave set of the
-         state that executed that previous transition. */
-      while ((mc_current_state = xbt_fifo_shift(mc_stack)) != NULL) {
-        q = mc_current_state->executed_transition;
-        xbt_fifo_foreach(mc_stack, item, state, mc_state_t) {
-          if (MC_transition_depend(q, state->executed_transition)) {
-            xbt_setset_foreach(state->enabled_transitions, cursor, trans) {
-              if ((trans->process == q->process)
-                  && !xbt_setset_set_belongs(state->done, trans)) {
-                DEBUG3("%s depend with %s at %p", q->name,
-                       state->executed_transition->name, state);
-
-                xbt_setset_foreach(state->enabled_transitions, cursor,
-                                   trans) {
-                  if (trans->process == q->process)
-                    xbt_setset_set_insert(state->interleave, trans);
-                }
-                /* FIXME: hack to make it work */
-                trans = q;
-                break;
-              }
+         state that executed that previous request. */
+      
+      while ((state = xbt_fifo_shift(mc_stack_safety)) != NULL) {
+        req = MC_state_get_internal_request(state);
+        xbt_fifo_foreach(mc_stack_safety, item, prev_state, mc_state_t) {
+          if(MC_request_depend(req, MC_state_get_internal_request(prev_state))){
+            if(XBT_LOG_ISENABLED(mc_dpor, xbt_log_priority_debug)){
+              XBT_DEBUG("Dependent Transitions:");
+              prev_req = MC_state_get_executed_request(prev_state, &value);
+              req_str = MC_request_to_string(prev_req, value);
+              XBT_DEBUG("%s (state=%p)", req_str, prev_state);
+              xbt_free(req_str);
+              prev_req = MC_state_get_executed_request(state, &value);
+              req_str = MC_request_to_string(prev_req, value);
+              XBT_DEBUG("%s (state=%p)", req_str, state);
+              xbt_free(req_str);              
             }
-            if (trans)
-              break;
+
+            break;
+
+          }else if(req->issuer == MC_state_get_internal_request(prev_state)->issuer){
+
+            XBT_DEBUG("Simcall %d and %d with same issuer", req->call, MC_state_get_internal_request(prev_state)->call);
+            break;
+
+          }else{
+
+            MC_state_remove_interleave_process(prev_state, req->issuer);
+            XBT_DEBUG("Simcall %d in process %lu independant with simcall %d process %lu", req->call, req->issuer->pid, MC_state_get_internal_request(prev_state)->call, MC_state_get_internal_request(prev_state)->issuer->pid);  
+
           }
         }
-        if (xbt_setset_set_size(mc_current_state->interleave) > 0) {
+       
+        if (MC_state_interleave_size(state)) {
           /* We found a back-tracking point, let's loop */
-          xbt_fifo_unshift(mc_stack, mc_current_state);
-          DEBUG1("Back-tracking to depth %d", xbt_fifo_size(mc_stack));
-          MC_replay(mc_stack);
+          if(_sg_mc_checkpoint){
+            if(state->system_state != NULL){
+              MC_restore_snapshot(state->system_state);
+              xbt_fifo_unshift(mc_stack_safety, state);
+              MC_UNSET_RAW_MEM;
+            }else{
+              pos = xbt_fifo_size(mc_stack_safety);
+              item = xbt_fifo_get_first_item(mc_stack_safety);
+              while(pos>0){
+                restore_state = (mc_state_t) xbt_fifo_get_item_content(item);
+                if(restore_state->system_state != NULL){
+                  break;
+                }else{
+                  item = xbt_fifo_get_next_item(item);
+                  pos--;
+                }
+              }
+              MC_restore_snapshot(restore_state->system_state);
+              xbt_fifo_unshift(mc_stack_safety, state);
+              MC_UNSET_RAW_MEM;
+              MC_replay(mc_stack_safety, pos);
+            }
+          }else{
+            xbt_fifo_unshift(mc_stack_safety, state);
+            MC_UNSET_RAW_MEM;
+            MC_replay(mc_stack_safety, -1);
+          }
+
+          MC_SET_RAW_MEM;
+          req2 = *req;
+          for(i=0; i<simix_process_maxpid; i++)
+            interleave_proc[i] = 0;
+          i=0;
+          while((i < MC_state_interleave_size(state))){
+            i++;
+            prev_req = MC_state_get_request(state, &value);
+            if(prev_req != NULL){
+              MC_state_set_executed_request(state, prev_req, value);
+              prev_req = MC_state_get_internal_request(state);
+              if(MC_request_depend(&req2, prev_req)){
+                XBT_DEBUG("Simcall %d in process %lu dependant with simcall %d in process %lu", req2.call, req2.issuer->pid, prev_req->call, prev_req->issuer->pid);  
+                interleave_proc[prev_req->issuer->pid] = 1;
+              }else{
+                XBT_DEBUG("Simcall %d in process %lu independant with simcall %d in process %lu", req2.call, req2.issuer->pid, prev_req->call, prev_req->issuer->pid); 
+                MC_state_remove_interleave_process(state, prev_req->issuer);
+              }
+            }
+          }
+          xbt_swag_foreach(process, simix_global->process_list){
+            if(interleave_proc[process->pid] == 1)
+              MC_state_interleave_process(state, process);
+          }
+          XBT_DEBUG("Back-tracking to depth %d", xbt_fifo_size(mc_stack_safety));
           MC_UNSET_RAW_MEM;
           break;
         } else {
-          MC_state_delete(mc_current_state);
+          MC_state_delete(state);
         }
       }
+      MC_UNSET_RAW_MEM;
     }
   }
-  DEBUG0("We are done");
-  /* We are done, show the statistics and return */
   MC_print_statistics(mc_stats);
+  MC_UNSET_RAW_MEM;  
+
+  return;
 }
+
+
+
+