Tested updating backtrack sets in the reachability graph.
[jpf-core.git] / src / main / gov / nasa / jpf / listener / DPORStateReducer.java
index ee61c190a0738687c8e75cf5eb26a828a39a2cae..f4b59233c47accb4f3cc0cae7671d1c98f864aef 100644 (file)
@@ -605,8 +605,8 @@ public class DPORStateReducer extends ListenerAdapter {
       stateToEventMap.put(stateId, eventSet);
     }
     saveExecutionToRGraph(stateId);
-    stateToChoiceCounterMap.put(stateId, choiceCounter);
     analyzeReachabilityAndCreateBacktrackPoints(search.getVM(), stateId);
+    stateToChoiceCounterMap.put(stateId, choiceCounter);
     justVisitedStates.add(stateId);
     currVisitedStates.add(stateId);
   }
@@ -722,7 +722,7 @@ public class DPORStateReducer extends ListenerAdapter {
     return currentChoice;
   }
 
-  private void createBacktrackingPoint(int currentChoice, int conflictChoice, Execution execution) {
+  private void createBacktrackingPoint(int backtrackChoice, int conflictChoice, Execution execution) {
 
     // Create a new list of choices for backtrack based on the current choice and conflicting event number
     // E.g. if we have a conflict between 1 and 3, then we create the list {3, 1, 0, 2}
@@ -731,14 +731,14 @@ public class DPORStateReducer extends ListenerAdapter {
     //int firstChoice = choices[actualChoice];
     ArrayList<BacktrackPoint> pastTrace = execution.getExecutionTrace();
     ArrayList<BacktrackPoint> currTrace = currentExecution.getExecutionTrace();
-    int backtrackEvent = currTrace.get(currentChoice).getChoice();
+    int btrackChoice = currTrace.get(backtrackChoice).getChoice();
     int stateId = pastTrace.get(conflictChoice).getStateId();
     // Check if this trace has been done from this state
-    if (isTraceAlreadyConstructed(backtrackEvent, stateId)) {
+    if (isTraceAlreadyConstructed(btrackChoice, stateId)) {
       return;
     }
     // Put the conflicting event numbers first and reverse the order
-    newChoiceList[0] = backtrackEvent;
+    newChoiceList[0] = btrackChoice;
     newChoiceList[1] = pastTrace.get(conflictChoice).getChoice();
     // Put the rest of the event numbers into the array starting from the minimum to the upper bound
     for (int i = 0, j = 2; i < refChoices.length; i++) {
@@ -803,7 +803,6 @@ public class DPORStateReducer extends ListenerAdapter {
                }
                // 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;
   }
@@ -866,19 +865,19 @@ public class DPORStateReducer extends ListenerAdapter {
     return false;
   }
 
-  private boolean isConflictFound(int currentChoice, int reachableEvent, Execution execution) {
+  private boolean isConflictFound(int reachableChoice, int conflictChoice, Execution execution) {
 
     ArrayList<BacktrackPoint> executionTrace = execution.getExecutionTrace();
     HashMap<Integer, ReadWriteSet> execRWFieldsMap = execution.getReadWriteFieldsMap();
     // Skip if this event does not have any Read/Write set or the two events are basically the same event (number)
-    if (!execRWFieldsMap.containsKey(reachableEvent) ||
-            executionTrace.get(currentChoice).getChoice() == executionTrace.get(reachableEvent).getChoice()) {
+    if (!execRWFieldsMap.containsKey(conflictChoice) ||
+            executionTrace.get(reachableChoice).getChoice() == executionTrace.get(conflictChoice).getChoice()) {
       return false;
     }
     // Current R/W set
-    ReadWriteSet currRWSet = execRWFieldsMap.get(currentChoice);
+    ReadWriteSet currRWSet = execRWFieldsMap.get(reachableChoice);
     // R/W set of choice/event that may have a potential conflict
-    ReadWriteSet evtRWSet = execRWFieldsMap.get(reachableEvent);
+    ReadWriteSet evtRWSet = execRWFieldsMap.get(conflictChoice);
     // Check for conflicts with Read and Write fields for Write instructions
     Set<String> currWriteSet = currRWSet.getWriteSet();
     for(String writeField : currWriteSet) {
@@ -950,6 +949,7 @@ public class DPORStateReducer extends ListenerAdapter {
       choices = icsCG.getAllChoices();
       refChoices = copyChoices(choices);
       // Clear data structures
+      currVisitedStates = new HashSet<>();
       stateToChoiceCounterMap = new HashMap<>();
       stateToEventMap = new HashMap<>();
       isEndOfExecution = false;
@@ -980,6 +980,23 @@ public class DPORStateReducer extends ListenerAdapter {
 
   // --- Functions related to the reachability analysis when there is a state match
 
+  // TODO: OPTIMIZATION!
+  // Check and make sure that state ID and choice haven't been explored for this trace
+  private boolean alreadyChecked(HashSet<String> checkedStateIdAndChoice, BacktrackPoint backtrackPoint) {
+    int stateId = backtrackPoint.getStateId();
+    int choice = backtrackPoint.getChoice();
+    StringBuilder sb = new StringBuilder();
+    sb.append(stateId);
+    sb.append(':');
+    sb.append(choice);
+    // Check if the trace has been constructed as a backtrack point for this state
+    if (checkedStateIdAndChoice.contains(sb.toString())) {
+      return true;
+    }
+    checkedStateIdAndChoice.add(sb.toString());
+    return false;
+  }
+
   // We use backtrackPointsList to analyze the reachable states/events when there is a state match:
   // 1) Whenever there is state match, there is a cycle of events
   // 2) We need to analyze and find conflicts for the reachable choices/events in the cycle
@@ -997,7 +1014,7 @@ public class DPORStateReducer extends ListenerAdapter {
         updateBacktrackSetsInCycle(stateId);
       } else if (prevVisitedStates.contains(stateId)) { // We visit a state in a previous execution
         // Update the backtrack sets in a previous execution
-        updateBacktrackSetsInPreviousExecution(stateId);
+        updateBacktrackSetsInPreviousExecutions(stateId);
       }
     }
   }
@@ -1034,47 +1051,56 @@ public class DPORStateReducer extends ListenerAdapter {
   // Update the backtrack sets in the cycle
   private void updateBacktrackSetsInCycle(int stateId) {
     // Find the choice/event that marks the start of this cycle: first choice we explore for conflicts
-    int currentChoice = stateToChoiceCounterMap.get(stateId);
+    int reachableChoice = stateToChoiceCounterMap.get(stateId);
     int cycleEndChoice = choiceCounter - 1;
     // Find conflicts between choices/events in this cycle (we scan forward in the cycle, not backward)
-    while (currentChoice < cycleEndChoice) {
-      for (int reachableEvent = currentChoice + 1; reachableEvent <= cycleEndChoice; reachableEvent++) {
-        if (isConflictFound(currentChoice, reachableEvent, currentExecution)) {
-          createBacktrackingPoint(currentChoice, reachableEvent, currentExecution);
+    while (reachableChoice < cycleEndChoice) {
+      for (int conflictChoice = reachableChoice + 1; conflictChoice <= cycleEndChoice; conflictChoice++) {
+        if (isConflictFound(reachableChoice, conflictChoice, currentExecution)) {
+          createBacktrackingPoint(reachableChoice, conflictChoice, currentExecution);
         }
       }
-      currentChoice++;
+      reachableChoice++;
     }
   }
 
-  // TODO: OPTIMIZATION!
-  // Check and make sure that state ID and choice haven't been explored for this trace
-  private boolean isNotChecked(HashMap<Integer, HashSet<Integer>> checkedStateIdAndChoice,
-                               BacktrackPoint backtrackPoint) {
-    int stateId = backtrackPoint.getStateId();
-    int choice = backtrackPoint.getChoice();
-    HashSet<Integer> choiceSet;
-    if (checkedStateIdAndChoice.containsKey(stateId)) {
-      choiceSet = checkedStateIdAndChoice.get(stateId);
-      if (choiceSet.contains(choice)) {
-        // State ID and choice found. It has been checked!
-        return false;
+  private void updateBacktrackSetsInPreviousExecution(Execution rExecution, int stateId,
+                                                      HashSet<String> checkedStateIdAndChoice) {
+    // Find the choice/event that marks the start of the subtrace from the previous execution
+    ArrayList<BacktrackPoint> pastExecutionTrace = rExecution.getExecutionTrace();
+    HashMap<Integer, ReadWriteSet> pastReadWriteFieldsMap = rExecution.getReadWriteFieldsMap();
+    int pastConfChoice = getPastConflictChoice(stateId, pastExecutionTrace);
+    int reachableChoice = choiceCounter;
+    // Iterate from the starting point until the end of the past execution trace
+    while (pastConfChoice < pastExecutionTrace.size() - 1) {  // BacktrackPoint list always has a surplus of 1
+      // Get the info of the event from the past execution trace
+      BacktrackPoint confBtrackPoint = pastExecutionTrace.get(pastConfChoice);
+      if (!alreadyChecked(checkedStateIdAndChoice, confBtrackPoint)) {
+        ReadWriteSet rwSet = pastReadWriteFieldsMap.get(pastConfChoice);
+        // Append this event to the current list and map
+        ArrayList<BacktrackPoint> currentTrace = currentExecution.getExecutionTrace();
+        HashMap<Integer, ReadWriteSet> currRWFieldsMap = currentExecution.getReadWriteFieldsMap();
+        currentTrace.add(confBtrackPoint);
+        currRWFieldsMap.put(choiceCounter, rwSet);
+        for (int conflictChoice = reachableChoice - 1; conflictChoice >= 0; conflictChoice--) {
+          if (isConflictFound(reachableChoice, conflictChoice, currentExecution)) {
+            createBacktrackingPoint(reachableChoice, conflictChoice, currentExecution);
+          }
+        }
+        // Remove this event to replace it with a new one
+        currentTrace.remove(currentTrace.size() - 1);
+        currRWFieldsMap.remove(choiceCounter);
       }
-    } else {
-      choiceSet = new HashSet<>();
-      checkedStateIdAndChoice.put(stateId, choiceSet);
+      pastConfChoice++;
     }
-    choiceSet.add(choice);
-
-    return true;
   }
 
   // Update the backtrack sets in a previous execution
-  private void updateBacktrackSetsInPreviousExecution(int stateId) {
+  private void updateBacktrackSetsInPreviousExecutions(int stateId) {
     // Don't check a past trace twice!
     HashSet<Execution> checkedTrace = new HashSet<>();
     // Don't check the same event twice for a revisited state
-    HashMap<Integer, HashSet<Integer>> checkedStateIdAndChoice = new HashMap<>();
+    HashSet<String> checkedStateIdAndChoice = new HashSet<>();
     // Get sorted reachable state IDs
     ArrayList<Integer> reachableStateIds = getReachableStateIds(rGraph.keySet(), stateId);
     // Iterate from this state ID until the biggest state ID
@@ -1083,33 +1109,7 @@ public class DPORStateReducer extends ListenerAdapter {
       ArrayList<Execution> rExecutions = rGraph.get(stId);
       for (Execution rExecution : rExecutions) {
         if (!checkedTrace.contains(rExecution)) {
-          // Find the choice/event that marks the start of the subtrace from the previous execution
-          ArrayList<BacktrackPoint> pastExecutionTrace = rExecution.getExecutionTrace();
-          HashMap<Integer, ReadWriteSet> pastReadWriteFieldsMap = rExecution.getReadWriteFieldsMap();
-          int pastConfChoice = getPastConflictChoice(stId, pastExecutionTrace);
-          int conflictChoice = choiceCounter;
-          // Iterate from the starting point until the end of the past execution trace
-          while (pastConfChoice < pastExecutionTrace.size() - 1) {  // BacktrackPoint list always has a surplus of 1
-            // Get the info of the event from the past execution trace
-            BacktrackPoint confBtrackPoint = pastExecutionTrace.get(pastConfChoice);
-            if (isNotChecked(checkedStateIdAndChoice, confBtrackPoint)) {
-              ReadWriteSet rwSet = pastReadWriteFieldsMap.get(pastConfChoice);
-              // Append this event to the current list and map
-              ArrayList<BacktrackPoint> currentTrace = currentExecution.getExecutionTrace();
-              HashMap<Integer, ReadWriteSet> currRWFieldsMap = currentExecution.getReadWriteFieldsMap();
-              currentTrace.add(confBtrackPoint);
-              currRWFieldsMap.put(choiceCounter, rwSet);
-              for (int pastChoice = conflictChoice - 1; pastChoice >= 0; pastChoice--) {
-                if (isConflictFound(conflictChoice, pastChoice, rExecution)) {
-                  createBacktrackingPoint(conflictChoice, pastChoice, rExecution);
-                }
-              }
-              // Remove this event to replace it with a new one
-              currentTrace.remove(currentTrace.size() - 1);
-              currRWFieldsMap.remove(choiceCounter);
-            }
-            pastConfChoice++;
-          }
+          updateBacktrackSetsInPreviousExecution(rExecution, stateId, checkedStateIdAndChoice);
           checkedTrace.add(rExecution);
         }
       }