private int choice; // Predecessor choice
private Execution execution; // Predecessor execution
- public Predecessor(int predChoice, Execution predExec) {
+ public Predecessor(Execution predExec, int predChoice) {
choice = predChoice;
execution = predExec;
}
}
public void addReachableTransition(int stateId, TransitionEvent transition) {
+ // Record transition into graph
HashSet<TransitionEvent> transitionSet;
if (graph.containsKey(stateId)) {
transitionSet = graph.get(stateId);
}
return graph.get(stateId);
}
-
- public HashSet<TransitionEvent> getReachableTransitions(int stateId) {
- HashSet<TransitionEvent> reachableTransitions = new HashSet<>();
- // All transitions from states higher than the given state ID (until the highest state ID) are reachable
- for(int stId = stateId; stId <= hiStateId; stId++) {
- // We might encounter state IDs from the first round of Boolean CG
- // The second round of Boolean CG should consider these new states
- if (graph.containsKey(stId)) {
- reachableTransitions.addAll(graph.get(stId));
- }
- }
- return reachableTransitions;
- }
}
// This class compactly stores Read and Write field sets
}
}
+ // This class provides a data structure to store TransitionEvent and ReadWriteSet for a summary
+ private class SummaryNode {
+ private TransitionEvent transitionEvent;
+ private ReadWriteSet readWriteSet;
+
+ public SummaryNode(TransitionEvent transEvent, ReadWriteSet rwSet) {
+ transitionEvent = transEvent;
+ readWriteSet = rwSet;
+ }
+
+ public TransitionEvent getTransitionEvent() {
+ return transitionEvent;
+ }
+
+ public ReadWriteSet getReadWriteSet() {
+ return readWriteSet;
+ }
+ }
+
// This class compactly stores transitions:
// 1) CG,
// 2) state ID,
private int choiceCounter; // Choice counter at this transition
private Execution execution; // The execution where this transition belongs
private HashSet<Predecessor> predecessors; // Maps incoming events/transitions (execution and choice)
+ private HashMap<Integer, SummaryNode> transitionSummary;
+ // Summary of pushed transitions at the current transition
+ private HashMap<Execution, HashSet<Integer>> recordedPredecessors;
+ // Memorize event and choice number to not record them twice
private int stateId; // State at this transition
private IntChoiceFromSet transitionCG; // CG at this transition
choiceCounter = 0;
execution = null;
predecessors = new HashSet<>();
+ transitionSummary = new HashMap<>();
+ recordedPredecessors = new HashMap<>();
stateId = 0;
transitionCG = null;
}
return stateId;
}
+ public HashMap<Integer, SummaryNode> getTransitionSummary() {
+ return transitionSummary;
+ }
+
public IntChoiceFromSet getTransitionCG() { return transitionCG; }
+ private boolean isRecordedPredecessor(Execution execution, int choice) {
+ // See if we have recorded this predecessor earlier
+ HashSet<Integer> recordedChoices;
+ if (recordedPredecessors.containsKey(execution)) {
+ recordedChoices = recordedPredecessors.get(execution);
+ if (recordedChoices.contains(choice)) {
+ return true;
+ }
+ } else {
+ recordedChoices = new HashSet<>();
+ recordedPredecessors.put(execution, recordedChoices);
+ }
+ // Record the choice if we haven't seen it
+ recordedChoices.add(choice);
+
+ return false;
+ }
+
+ private ReadWriteSet performUnion(ReadWriteSet recordedRWSet, ReadWriteSet rwSet) {
+ // Combine the same write accesses and record in the recordedRWSet
+ HashMap<String, Integer> recordedWriteMap = recordedRWSet.getWriteMap();
+ HashMap<String, Integer> writeMap = rwSet.getWriteMap();
+ for(Map.Entry<String, Integer> entry : recordedWriteMap.entrySet()) {
+ String writeField = entry.getKey();
+ // Remove the entry from rwSet if both field and object ID are the same
+ if (writeMap.containsKey(writeField) &&
+ (writeMap.get(writeField).equals(recordedWriteMap.get(writeField)))) {
+ writeMap.remove(writeField);
+ }
+ }
+ // Then add everything into the recorded map because these will be traversed
+ recordedWriteMap.putAll(writeMap);
+ // Combine the same read accesses and record in the recordedRWSet
+ HashMap<String, Integer> recordedReadMap = recordedRWSet.getReadMap();
+ HashMap<String, Integer> readMap = rwSet.getReadMap();
+ for(Map.Entry<String, Integer> entry : recordedReadMap.entrySet()) {
+ String readField = entry.getKey();
+ // Remove the entry from rwSet if both field and object ID are the same
+ if (readMap.containsKey(readField) &&
+ (readMap.get(readField).equals(recordedReadMap.get(readField)))) {
+ readMap.remove(readField);
+ }
+ }
+ // Then add everything into the recorded map because these will be traversed
+ recordedReadMap.putAll(readMap);
+
+ return rwSet;
+ }
+
public void recordPredecessor(Execution execution, int choice) {
- predecessors.add(new Predecessor(choice, execution));
+ if (!isRecordedPredecessor(execution, choice)) {
+ predecessors.add(new Predecessor(execution, choice));
+ }
+ }
+
+ public ReadWriteSet recordTransitionSummary(TransitionEvent transition, ReadWriteSet rwSet, boolean refresh) {
+ // Record transition into reachability summary
+ // TransitionMap maps event (choice) number to a R/W set
+ int choice = transition.getChoice();
+ SummaryNode summaryNode;
+ // Insert transition into the map if we haven't had this event number recorded
+ if (!transitionSummary.containsKey(choice) || refresh) {
+ summaryNode = new SummaryNode(transition, rwSet.getCopy());
+ transitionSummary.put(choice, summaryNode);
+ } else {
+ summaryNode = transitionSummary.get(choice);
+ // Perform union and subtraction between the recorded and the given R/W sets
+ rwSet = performUnion(summaryNode.getReadWriteSet(), rwSet);
+ }
+ return rwSet;
}
public void setChoice(int cho) {
// Memorize visited TransitionEvent object while performing backward DFS to avoid getting caught up in a cycle
HashSet<TransitionEvent> visited = new HashSet<>();
// Update backtrack set recursively
- // TODO: The following is the call to the original version of the method
-// updateBacktrackSetRecursive(execution, currentChoice, execution, currentChoice, currRWSet, visited);
- // TODO: The following is the call to the version of the method with pushing up happens-before transitions
- updateBacktrackSetRecursive(execution, currentChoice, execution, currentChoice, currRWSet, visited);
+ updateBacktrackSetRecursive(execution, currentChoice, execution, currentChoice, currRWSet, visited, false);
}
-// TODO: This is the original version of the recursive method
-// private void updateBacktrackSetRecursive(Execution execution, int currentChoice,
-// Execution conflictExecution, int conflictChoice,
-// ReadWriteSet currRWSet, HashSet<TransitionEvent> visited) {
-// // Halt when we have found the first read/write conflicts for all memory locations
-// if (currRWSet.isEmpty()) {
-// return;
-// }
-// TransitionEvent confTrans = conflictExecution.getExecutionTrace().get(conflictChoice);
-// // Halt when we have visited this transition (in a cycle)
-// if (visited.contains(confTrans)) {
-// return;
-// }
-// visited.add(confTrans);
-// // Explore all predecessors
-// for (Predecessor predecessor : confTrans.getPredecessors()) {
-// // Get the predecessor (previous conflict choice)
-// conflictChoice = predecessor.getChoice();
-// conflictExecution = predecessor.getExecution();
-// // Check if a conflict is found
-// if (isConflictFound(execution, currentChoice, conflictExecution, conflictChoice, currRWSet)) {
-// createBacktrackingPoint(execution, currentChoice, conflictExecution, conflictChoice);
-// }
-// // Continue performing DFS if conflict is not found
-// updateBacktrackSetRecursive(execution, currentChoice, conflictExecution, conflictChoice, currRWSet, visited);
-// }
-// }
-
- // TODO: This is the version of the method with pushing up happens-before transitions
+ // Recursive method to perform backward DFS to traverse the graph
private void updateBacktrackSetRecursive(Execution execution, int currentChoice,
Execution conflictExecution, int conflictChoice,
- ReadWriteSet currRWSet, HashSet<TransitionEvent> visited) {
- // Halt when we have found the first read/write conflicts for all memory locations
- if (currRWSet.isEmpty()) {
- return;
- }
+ ReadWriteSet currRWSet, HashSet<TransitionEvent> visited,
+ boolean refresh) {
TransitionEvent currTrans = execution.getExecutionTrace().get(currentChoice);
- // Halt when we have visited this transition (in a cycle)
if (visited.contains(currTrans)) {
return;
}
visited.add(currTrans);
+ TransitionEvent confTrans = conflictExecution.getExecutionTrace().get(conflictChoice);
+ // Record this transition into rGraph summary
+ currRWSet = currTrans.recordTransitionSummary(confTrans, currRWSet, refresh);
+ // Halt when we have found the first read/write conflicts for all memory locations
+ if (currRWSet.isEmpty()) {
+ return;
+ }
// Explore all predecessors
for (Predecessor predecessor : currTrans.getPredecessors()) {
// Get the predecessor (previous conflict choice)
// Check if a conflict is found
if (isConflictFound(conflictExecution, conflictChoice, predecessorExecution, predecessorChoice, currRWSet)) {
createBacktrackingPoint(conflictExecution, conflictChoice, predecessorExecution, predecessorChoice);
- newConflictChoice = conflictChoice;
- newConflictExecution = conflictExecution;
+ newConflictChoice = predecessorChoice;
+ newConflictExecution = predecessorExecution;
}
// Continue performing DFS if conflict is not found
updateBacktrackSetRecursive(predecessorExecution, predecessorChoice, newConflictExecution, newConflictChoice,
- currRWSet, visited);
+ currRWSet, visited, refresh);
}
- // Remove the transition after being explored
- // TODO: Seems to cause a lot of loops---commented out for now
- //visited.remove(confTrans);
}
// --- Functions related to the reachability analysis when there is a state match
}
}
- // Update the backtrack sets from previous executions
private void updateBacktrackSetsFromPreviousExecution(int stateId) {
// Collect all the reachable transitions from R-Graph
- HashSet<TransitionEvent> reachableTransitions = rGraph.getReachableTransitions(stateId);
+ HashSet<TransitionEvent> reachableTransitions = rGraph.getReachableTransitionsAtState(stateId);
for(TransitionEvent transition : reachableTransitions) {
- Execution execution = transition.getExecution();
+ // Current transition that stems from this state ID
+ Execution currentExecution = transition.getExecution();
int currentChoice = transition.getChoiceCounter();
- updateBacktrackSet(execution, currentChoice);
+ // Iterate over the stored conflict transitions in the summary
+ for(Map.Entry<Integer, SummaryNode> conflictTransition : transition.getTransitionSummary().entrySet()) {
+ SummaryNode summaryNode = conflictTransition.getValue();
+ // Conflict transition in the summary node
+ TransitionEvent confTrans = summaryNode.getTransitionEvent();
+ Execution conflictExecution = confTrans.getExecution();
+ int conflictChoice = confTrans.getChoiceCounter();
+ // Copy ReadWriteSet object
+ ReadWriteSet currRWSet = summaryNode.getReadWriteSet();
+ currRWSet = currRWSet.getCopy();
+ // Memorize visited TransitionEvent object while performing backward DFS to avoid getting caught up in a cycle
+ HashSet<TransitionEvent> visited = new HashSet<>();
+ updateBacktrackSetRecursive(currentExecution, currentChoice, conflictExecution,
+ conflictChoice, currRWSet, visited, true);
+ }
}
}
}