Printing out the number of transitions.
[jpf-core.git] / src / main / gov / nasa / jpf / listener / DPORStateReducer.java
index 7d5546c2be70d4028d79069dce39edb81b6cbb85..a35286454e3025d6311d0b50c72cb7ab0f538082 100644 (file)
@@ -28,7 +28,6 @@ import gov.nasa.jpf.vm.bytecode.WriteInstruction;
 import gov.nasa.jpf.vm.choice.IntChoiceFromSet;
 import gov.nasa.jpf.vm.choice.IntIntervalGenerator;
 
-import java.awt.*;
 import java.io.PrintWriter;
 import java.util.*;
 
@@ -75,10 +74,12 @@ public class DPORStateReducer extends ListenerAdapter {
   private ArrayList<BacktrackPoint> backtrackPointList;           // Record backtrack points (CG, state Id, and choice)
   private HashMap<Integer, HashSet<Integer>> conflictPairMap;     // Record conflicting events
   private HashSet<String> doneBacktrackSet;                       // Record state ID and trace already constructed
+  private HashMap<Integer,Integer> newStateEventMap;              // Record event producing a new state ID
   private HashMap<Integer, ReadWriteSet> readWriteFieldsMap;      // Record fields that are accessed
   private HashMap<Integer, RestorableVMState> restorableStateMap; // Maps state IDs to the restorable state object
 
   // Visible operation dependency graph implementation (SPIN paper) related fields
+  private int currChoiceValue;
   private int prevChoiceValue;
   private HashMap<Integer, HashSet<Integer>> vodGraphMap; // Visible operation dependency graph (VOD graph)
 
@@ -86,6 +87,9 @@ public class DPORStateReducer extends ListenerAdapter {
   private boolean isBooleanCGFlipped;
   private boolean isEndOfExecution;
 
+  // Statistics
+  private int numOfTransitions;        
+       
   public DPORStateReducer(Config config, JPF jpf) {
     verboseMode = config.getBoolean("printout_state_transition", false);
     stateReductionMode = config.getBoolean("activate_state_reduction", true);
@@ -95,6 +99,7 @@ public class DPORStateReducer extends ListenerAdapter {
       out = null;
     }
     isBooleanCGFlipped = false;
+               numOfTransitions = 0;
     restorableStateMap = new HashMap<>();
     initializeStatesVariables();
   }
@@ -161,6 +166,9 @@ public class DPORStateReducer extends ListenerAdapter {
   @Override
   public void searchFinished(Search search) {
     if (verboseMode) {
+      out.println("\n==> DEBUG: ----------------------------------- search finished");
+      out.println("\n==> DEBUG: State reduction mode  : " + stateReductionMode);
+      out.println("\n==> DEBUG: Number of transitions : " + numOfTransitions);
       out.println("\n==> DEBUG: ----------------------------------- search finished" + "\n");
     }
   }
@@ -217,15 +225,19 @@ public class DPORStateReducer extends ListenerAdapter {
         fairSchedulingAndBacktrackPoint(icsCG, vm);
         // Map state to event
         mapStateToEvent(icsCG.getNextChoice());
-        // Update the VOD graph always with the latest
-        updateVODGraph(icsCG.getNextChoice());
-        // Check if we have seen this state or this state contains cycles that involve all events
-        if (terminateCurrentExecution()) {
+        // Explore the next backtrack point: 
+        // 1) if we have seen this state or this state contains cycles that involve all events, and
+        // 2) after the current CG is advanced at least once
+        if (terminateCurrentExecution() && choiceCounter > 0) {
           exploreNextBacktrackPoints(vm, icsCG);
+        } else {
+          numOfTransitions++;
         }
         justVisitedStates.clear();
         choiceCounter++;
       }
+    } else {
+      numOfTransitions++;
     }
   }
 
@@ -266,7 +278,7 @@ public class DPORStateReducer extends ListenerAdapter {
                   if (isConflictFound(nextInsn, eventCounter, currentChoice, fieldClass) &&
                       isNewConflict(currentChoice, eventCounter)) {
                     // Lines 4-8 of the algorithm in the paper page 11 (see the heading note above)
-                    if (vm.isNewState() || isReachableInVODGraph(currentChoice)) {
+                    if (vm.isNewState() || isReachableInVODGraph(currentChoice, vm)) {
                       createBacktrackingPoint(currentChoice, eventCounter);
                     }
                   }
@@ -376,6 +388,8 @@ public class DPORStateReducer extends ListenerAdapter {
         icsCG.setChoice(currCGIndex, expectedChoice);
       }
     }
+    // Update current choice
+    currChoiceValue = refChoices[choiceIndex];
     // Record state ID and choice/event as backtrack point
     int stateId = vm.getStateId();
     backtrackPointList.add(new BacktrackPoint(icsCG, stateId, refChoices[choiceIndex]));
@@ -433,8 +447,10 @@ public class DPORStateReducer extends ListenerAdapter {
     backtrackPointList = new ArrayList<>();
     conflictPairMap = new HashMap<>();
     doneBacktrackSet = new HashSet<>();
+    newStateEventMap = new HashMap<>();
     readWriteFieldsMap = new HashMap<>();
     // VOD graph
+    currChoiceValue = 0;
     prevChoiceValue = -1;
     vodGraphMap = new HashMap<>();
     // Booleans
@@ -473,6 +489,8 @@ public class DPORStateReducer extends ListenerAdapter {
       stateToEventMap.put(stateId, eventSet);
     }
     justVisitedStates.add(stateId);
+    // Update the VOD graph when there is a new state
+    updateVODGraph(search.getVM());
   }
 
   // --- Functions related to Read/Write access analysis on shared fields
@@ -634,35 +652,32 @@ public class DPORStateReducer extends ListenerAdapter {
 
   private void exploreNextBacktrackPoints(VM vm, IntChoiceFromSet icsCG) {
 
-    // We can start exploring the next backtrack point after the current CG is advanced at least once
-    if (choiceCounter > 0) {
-      // Check if we are reaching the end of our execution: no more backtracking points to explore
-      // cgMap, backtrackMap, backtrackStateQ are updated simultaneously (checking backtrackStateQ is enough)
-      if (!backtrackStateQ.isEmpty()) {
-        // Set done all the other backtrack points
-        for (BacktrackPoint backtrackPoint : backtrackPointList) {
-          backtrackPoint.getBacktrackCG().setDone();
-        }
-        // Reset the next backtrack point with the latest state
-        int hiStateId = backtrackStateQ.peek();
-        // Restore the state first if necessary
-        if (vm.getStateId() != hiStateId) {
-          RestorableVMState restorableState = restorableStateMap.get(hiStateId);
-          vm.restoreState(restorableState);
-        }
-        // Set the backtrack CG
-        IntChoiceFromSet backtrackCG = (IntChoiceFromSet) vm.getChoiceGenerator();
-        setBacktrackCG(hiStateId, backtrackCG);
-      } else {
-        // Set done this last CG (we save a few rounds)
-        icsCG.setDone();
-      }
-      // Save all the visited states when starting a new execution of trace
-      prevVisitedStates.addAll(currVisitedStates);
-      currVisitedStates.clear();
-      // This marks a transitional period to the new CG
-      isEndOfExecution = true;
-    }
+               // Check if we are reaching the end of our execution: no more backtracking points to explore
+               // cgMap, backtrackMap, backtrackStateQ are updated simultaneously (checking backtrackStateQ is enough)
+               if (!backtrackStateQ.isEmpty()) {
+                       // Set done all the other backtrack points
+                       for (BacktrackPoint backtrackPoint : backtrackPointList) {
+                               backtrackPoint.getBacktrackCG().setDone();
+                       }
+                       // Reset the next backtrack point with the latest state
+                       int hiStateId = backtrackStateQ.peek();
+                       // Restore the state first if necessary
+                       if (vm.getStateId() != hiStateId) {
+                               RestorableVMState restorableState = restorableStateMap.get(hiStateId);
+                               vm.restoreState(restorableState);
+                       }
+                       // Set the backtrack CG
+                       IntChoiceFromSet backtrackCG = (IntChoiceFromSet) vm.getChoiceGenerator();
+                       setBacktrackCG(hiStateId, backtrackCG);
+               } else {
+                       // Set done this last CG (we save a few rounds)
+                       icsCG.setDone();
+               }
+               // Save all the visited states when starting a new execution of trace
+               prevVisitedStates.addAll(currVisitedStates);
+               currVisitedStates.clear();
+               // This marks a transitional period to the new CG
+               isEndOfExecution = true;
   }
 
   private ReadWriteSet getReadWriteSet(int currentChoice) {
@@ -775,29 +790,32 @@ public class DPORStateReducer extends ListenerAdapter {
 
   // --- Functions related to the visible operation dependency graph implementation discussed in the SPIN paper
 
-  // This method checks whether a choice is reachable in the VOD graph from a reference choice (BFS algorithm)
-  //private boolean isReachableInVODGraph(int checkedChoice, int referenceChoice) {
-  private boolean isReachableInVODGraph(int currentChoice) {
-    // Extract previous and current events
+  // This method checks whether a choice/event (transition) is reachable from the choice/event that produces
+  // the state right before this state in the VOD graph
+  // We use a BFS algorithm for this purpose
+  private boolean isReachableInVODGraph(int currentChoice, VM vm) {
+    // Current event
     int choiceIndex = currentChoice % refChoices.length;
-    int prevChoIndex = (currentChoice - 1) % refChoices.length;
     int currEvent = refChoices[choiceIndex];
-    int prevEvent = refChoices[prevChoIndex];
-    // Record visited choices as we search in the graph
-    HashSet<Integer> visitedChoice = new HashSet<>();
-    visitedChoice.add(prevEvent);
-    LinkedList<Integer> nodesToVisit = new LinkedList<>();
-    // If the state doesn't advance as the threads/sub-programs are executed (basically there is no new state),
-    // there is a chance that the graph doesn't have new nodes---thus this check will return a null.
+    // Previous event
+    int stateId = vm.getStateId();  // A state that has been seen
+    int prevEvent = newStateEventMap.get(stateId);
+    // Only start traversing the graph if prevEvent has an outgoing edge
     if (vodGraphMap.containsKey(prevEvent)) {
+      // Record visited choices as we search in the graph
+      HashSet<Integer> visitedChoice = new HashSet<>();
+      visitedChoice.add(prevEvent);
+      // Get the first nodes to visit (the neighbors of prevEvent)
+      LinkedList<Integer> nodesToVisit = new LinkedList<>();
       nodesToVisit.addAll(vodGraphMap.get(prevEvent));
-      while(!nodesToVisit.isEmpty()) {
-        int choice = nodesToVisit.getFirst();
+      // Traverse the graph using BFS
+      while (!nodesToVisit.isEmpty()) {
+        int choice = nodesToVisit.removeFirst();
         if (choice == currEvent) {
           return true;
         }
-        if (visitedChoice.contains(choice)) { // If there is a loop then we don't find it
-          return false;
+        if (visitedChoice.contains(choice)) { // If there is a loop then just continue the exploration
+          continue;
         }
         // Continue searching
         visitedChoice.add(choice);
@@ -817,18 +835,23 @@ public class DPORStateReducer extends ListenerAdapter {
     return false;
   }
 
-  private void updateVODGraph(int currChoiceValue) {
-    // Update the graph when we have the current choice value
-    HashSet<Integer> choiceSet;
-    if (vodGraphMap.containsKey(prevChoiceValue)) {
-      // If the key already exists, just retrieve it
-      choiceSet = vodGraphMap.get(prevChoiceValue);
-    } else {
-      // Create a new entry
-      choiceSet = new HashSet<>();
-      vodGraphMap.put(prevChoiceValue, choiceSet);
+  private void updateVODGraph(VM vm) {
+    // Do this only if it is a new state
+    if (vm.isNewState()) {
+      // Update the graph when we have the current choice value
+      HashSet<Integer> choiceSet;
+      if (vodGraphMap.containsKey(prevChoiceValue)) {
+        // If the key already exists, just retrieve it
+        choiceSet = vodGraphMap.get(prevChoiceValue);
+      } else {
+        // Create a new entry
+        choiceSet = new HashSet<>();
+        vodGraphMap.put(prevChoiceValue, choiceSet);
+      }
+      choiceSet.add(currChoiceValue);
+      prevChoiceValue = currChoiceValue;
+      // Map this state ID to the event (transition) that produces it
+      newStateEventMap.put(vm.getStateId(), currChoiceValue);
     }
-    choiceSet.add(currChoiceValue);
-    prevChoiceValue = currChoiceValue;
   }
 }