diff --git a/tregression/.classpath b/tregression/.classpath index 1386a7ce..a018758a 100644 --- a/tregression/.classpath +++ b/tregression/.classpath @@ -7,7 +7,7 @@ - + diff --git a/tregression/.settings/org.eclipse.jdt.core.prefs b/tregression/.settings/org.eclipse.jdt.core.prefs index 7341ab16..3a215370 100644 --- a/tregression/.settings/org.eclipse.jdt.core.prefs +++ b/tregression/.settings/org.eclipse.jdt.core.prefs @@ -1,11 +1,11 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/tregression/plugin.xml b/tregression/plugin.xml index 0de0ed22..cb3ca8d1 100644 --- a/tregression/plugin.xml +++ b/tregression/plugin.xml @@ -53,6 +53,26 @@ id="traceagent.command.runSingleDefects4jBugs" name="Run Single Defect4j Bug"> + + + + + + + + @@ -84,6 +104,30 @@ name="Step Properties" restorable="true"> + + + + + + @@ -139,6 +183,11 @@ label="Retrieve All Defect4j Regressions" style="push"> + + diff --git a/tregression/src/main/traceagent/handler/PlayRegressionLocalizationHandlerConc.java b/tregression/src/main/traceagent/handler/PlayRegressionLocalizationHandlerConc.java new file mode 100644 index 00000000..97514058 --- /dev/null +++ b/tregression/src/main/traceagent/handler/PlayRegressionLocalizationHandlerConc.java @@ -0,0 +1,97 @@ +package traceagent.handler; + +import java.util.Comparator; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import tregression.empiricalstudy.RootCauseFinder; +import tregression.empiricalstudy.RootCauseNode; +import tregression.views.BuggyTraceView; +import tregression.views.ConcurrentBuggyTraceView; +import tregression.views.ConcurrentCorrectTraceView; +import tregression.views.CorrectTraceView; +import tregression.views.TregressionViews; + +public class PlayRegressionLocalizationHandlerConc extends AbstractHandler { + + public static RootCauseFinder finder = null; + + ConcurrentBuggyTraceView buggyView; + ConcurrentCorrectTraceView correctView; + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + Job job = new Job("Recovering Regression ...") { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + buggyView = TregressionViews.getConcBuggyTraceView(); + correctView = TregressionViews.getConcCorrectTraceView(); + } + }); + + Thread.sleep(2000); + + finder.getRegressionNodeList().sort(new Comparator() { + @Override + public int compare(TraceNode o1, TraceNode o2) { + return o2.getOrder() - o1.getOrder(); + } + });; + + for(final TraceNode node: finder.getRegressionNodeList()) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + Trace buggyTrace = node.getTrace(); +// Trace correctTrace = correctView.getTrace(); + buggyView.jumpToNode(buggyTrace, node.getOrder(), true); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }); + + boolean stop = false; + for(RootCauseNode rNode: finder.getRealRootCaseList()) { + if(rNode.getRoot().equals(node)) { + stop = true; + break; + } + } + + if(stop)break; + + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return Status.OK_STATUS; + } + }; + job.schedule(); + + return null; + } + +} diff --git a/tregression/src/main/traceagent/handler/RunAllDefects4jHandler.java b/tregression/src/main/traceagent/handler/RunAllDefects4jHandler.java index d8d821ea..cef053ab 100644 --- a/tregression/src/main/traceagent/handler/RunAllDefects4jHandler.java +++ b/tregression/src/main/traceagent/handler/RunAllDefects4jHandler.java @@ -4,6 +4,8 @@ package traceagent.handler; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; @@ -17,6 +19,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.osgi.service.debug.DebugTrace; import experiment.utils.report.ExperimentReportComparisonReporter; import experiment.utils.report.rules.TextComparisonRule; @@ -33,6 +36,7 @@ import traceagent.report.BugCaseTrial.TraceTrial; import tregression.empiricalstudy.TestCase; import tregression.empiricalstudy.config.Defects4jProjectConfig; +import tregression.empiricalstudy.config.ProjectConfig; import tregression.handler.PathConfiguration; import tregression.separatesnapshots.AppClassPathInitializer; @@ -41,13 +45,62 @@ * */ public class RunAllDefects4jHandler extends AbstractHandler { + FileOutputStream fos = null; + boolean handlerStopped = false; + /** + * Used to check if the job is canceled + * @author Gabau + * + */ + private class CancelThread extends Thread { + public boolean stopped = false; + IProgressMonitor monitor; + InstrumentationExecutor executor; + public CancelThread(IProgressMonitor monitor, + InstrumentationExecutor executor) { + this.setName("Cancel thread"); + this.monitor = monitor; + this.executor = executor; + this.setDaemon(true); + } + + @Override + public void run() { + while (!stopped) { + if (monitor.isCanceled()) { + executor.interrupt(); + stopped = true; + break; + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + public void stopMonitoring() { + this.stopped = true; + handlerStopped = true; + } + + } + @Override public Object execute(ExecutionEvent event) throws ExecutionException { + try { + fos = new FileOutputStream(new File("K:\\output6.txt")); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } Job job = new Job("Run Trace Agent On Defects4j") { @Override protected IStatus run(IProgressMonitor monitor) { - String reportFile = "Agent_Defect4j.xlsx"; + String reportFile = "K:\\Agent_Defect4j.xlsx"; try { runAll(reportFile, monitor); System.out.println("Complete!"); @@ -72,11 +125,15 @@ && new File(oldDefects4jFile).exists()) { } protected void runAll(String reportFile, IProgressMonitor monitor) throws Exception { - String[] projects = {"Chart", "Closure", "Lang", "Math", "Mockito", "Time"}; - int[] bugNum = {26, 133, 65, 106, 38, 27}; + //String[] projects = {"Chart", "Closure", "Lang", "Math", "Mockito", "Time"}; + //int[] bugNum = {26, 133, 65, 106, 38, 27}; + String[] projects = {"Csv"}; + int[] bugNum = {16}; + AgentDefects4jReport report = new AgentDefects4jReport(new File(reportFile)); TestcaseFilter filter = new TestcaseFilter(false); for (int i = 0; i < projects.length; i++) { + if (handlerStopped) return; String project = projects[i]; if (monitor.isCanceled()) { return; @@ -86,7 +143,7 @@ protected void runAll(String reportFile, IProgressMonitor monitor) throws Except return; } System.out.println("working on the " + j + "th bug of " + project + " project."); - Defects4jProjectConfig d4jConfig = Defects4jProjectConfig.getConfig(project, String.valueOf(j)); + ProjectConfig d4jConfig = Defects4jProjectConfig.getConfig(project, String.valueOf(j)); try { runSingleBug(d4jConfig, report, null, filter, monitor); } catch (Exception e) { @@ -96,7 +153,7 @@ protected void runAll(String reportFile, IProgressMonitor monitor) throws Except } } - void runSingleBug(Defects4jProjectConfig config, AgentDefects4jReport report, List tcs, + void runSingleBug(ProjectConfig config, AgentDefects4jReport report, List tcs, TestcaseFilter filter, IProgressMonitor monitor) throws IOException { String projectName = config.projectName; @@ -116,11 +173,13 @@ void runSingleBug(Defects4jProjectConfig config, AgentDefects4jReport report, Li SingleTimer timer = SingleTimer.start("run buggy test"); if (!filter.filter(projectName, bugID, tc.getName(), true)) { TraceTrial bugTrace = run(buggyPath, tc, config, includeLibs, excludeLibs, true); + if (bugTrace == null) continue; trial.setBugTrace(bugTrace); } timer.startNewTask("run correct test"); if (!filter.filter(projectName, bugID, tc.getName(), false)) { TraceTrial correctTrace = run(fixPath, tc, config, includeLibs, excludeLibs, false); + if (correctTrace == null) continue; trial.setFixedTrace(correctTrace); } @@ -128,7 +187,7 @@ void runSingleBug(Defects4jProjectConfig config, AgentDefects4jReport report, Li } } - public TraceTrial run(String workingDir, TestCase tc, Defects4jProjectConfig config, List includeLibs, + public TraceTrial run(String workingDir, TestCase tc, ProjectConfig config, List includeLibs, List excludeLibs, boolean isBuggy) { SingleTimer timer = SingleTimer.start(String.format("run %s test", isBuggy ? "buggy" : "correct")); AppJavaClassPath appClassPath = AppClassPathInitializer.initialize(workingDir, tc, config); @@ -140,10 +199,19 @@ public TraceTrial run(String workingDir, TestCase tc, Defects4jProjectConfig con RunningInfo info = null; try { - info = executor.run(); + info = executor.runCounter(); + PreCheckInformation pci = executor.getPrecheckInfo(); + if (pci.getThreadNum() > 1) { + String toWrite = config.projectName + config.regressionID + "\n"; + fos.write(toWrite.getBytes()); + } } catch (StepLimitException e) { e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } + if (info == null) return null; PreCheckInformation precheckInfo = executor.getPrecheckInfo(); return new TraceTrial(workingDir, precheckInfo, info, timer.getExecutionTime(), isBuggy); } diff --git a/tregression/src/main/traceagent/handler/RunSingleTestcaseHandler.java b/tregression/src/main/traceagent/handler/RunSingleTestcaseHandler.java index c39b485f..d5c1bbca 100644 --- a/tregression/src/main/traceagent/handler/RunSingleTestcaseHandler.java +++ b/tregression/src/main/traceagent/handler/RunSingleTestcaseHandler.java @@ -19,6 +19,7 @@ import traceagent.report.AgentDefects4jReport; import tregression.empiricalstudy.TestCase; import tregression.empiricalstudy.config.Defects4jProjectConfig; +import tregression.empiricalstudy.config.ProjectConfig; import tregression.preference.TregressionPreference; /** @@ -43,7 +44,7 @@ protected IStatus run(IProgressMonitor monitor) { tcs = Arrays.asList(new TestCase(testcase)); } System.out.println("working on the " + id + "th bug of " + projectName + " project."); - Defects4jProjectConfig config = Defects4jProjectConfig.getConfig(projectName, + ProjectConfig config = Defects4jProjectConfig.getConfig(projectName, id); AgentDefects4jReport report = new AgentDefects4jReport(new File("Agent_Defect4j_tc.xlsx")); runSingleBug(config, report, tcs, new TestcaseFilter(false), monitor); diff --git a/tregression/src/main/traceagent/report/AgentDefects4jHeaders.java b/tregression/src/main/traceagent/report/AgentDefects4jHeaders.java index 52fd6dad..a42a4844 100644 --- a/tregression/src/main/traceagent/report/AgentDefects4jHeaders.java +++ b/tregression/src/main/traceagent/report/AgentDefects4jHeaders.java @@ -24,6 +24,8 @@ public enum AgentDefects4jHeaders implements ExcelHeader { LOADED_CLASSES, PRECHECK_STEP_NUM, RUN_STEP_NUM, + IS_DEADLOCK, + IS_TIMEOUT, PROGRAM_MSG, SUMMARY; diff --git a/tregression/src/main/tregression/StepChangeType.java b/tregression/src/main/tregression/StepChangeType.java index 0f8cf54f..4d8ab221 100644 --- a/tregression/src/main/tregression/StepChangeType.java +++ b/tregression/src/main/tregression/StepChangeType.java @@ -14,10 +14,10 @@ import tregression.empiricalstudy.RootCauseFinder; public class StepChangeType { - public static int IDT = 0; - public static int SRC = 1; - public static int DAT = 2; - public static int CTL = 3; + public final static int IDT = 0; + public final static int SRC = 1; + public final static int DAT = 2; + public final static int CTL = 3; private int type; private TraceNode matchingStep; @@ -83,15 +83,17 @@ public VarValue getWrongVariable(TraceNode node, boolean isOnBefore, RootCauseFi CausalityNode cNode = new CausalityNode(node, isOnBefore); VarValue value = guidance.get(cNode); if(value != null ){ - if(!node.getWrittenVariables().contains(value)){ - return value; - } +// if(!node.getWrittenVariables().contains(value)){ +// return value; +// } + return value; } } List virList = new ArrayList<>(); List primitiveList = new ArrayList<>(); List referenceList = new ArrayList<>(); + if (wrongVariableList == null) return new PrimitiveValue("dummy value", true, null); for(Pair pair: wrongVariableList){ VarValue var = pair.first(); diff --git a/tregression/src/main/tregression/StepChangeTypeChecker.java b/tregression/src/main/tregression/StepChangeTypeChecker.java index f495e0e5..7e74bcd9 100644 --- a/tregression/src/main/tregression/StepChangeTypeChecker.java +++ b/tregression/src/main/tregression/StepChangeTypeChecker.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import microbat.model.value.ReferenceValue; @@ -69,6 +70,10 @@ public StepChangeType getType(TraceNode step, boolean isOnBeforeTrace, } + public StepChangeType getType(ConcurrentTraceNode step, boolean isOnBeforeTrace, PairList pairList, DiffMatcher matcher) { + return getType(step.getInitialTraceNode(), isOnBeforeTrace, pairList, matcher); + } + /** * When invoking a method m() at line k, we will have two steps running into line k, i.e., a step s_1 * invoking m() and a step s_2 returning from the invocation. Suppose s_1 is matched and s_2 is not, diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java new file mode 100644 index 00000000..962d51c4 --- /dev/null +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -0,0 +1,666 @@ +package tregression.empiricalstudy; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.Stack; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; + +import japa.parser.ast.Node; +import microbat.instrumentation.instr.aggreplay.shared.ParseData; +import microbat.model.ConcNode; +import microbat.model.trace.ConcurrentTrace; +import microbat.model.trace.ConcurrentTraceNode; +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import microbat.model.value.VarValue; +import microbat.recommendation.UserFeedback; +import sav.common.core.Pair; +import tregression.SimulationFailException; +import tregression.StepChangeType; +import tregression.StepChangeTypeChecker; +import tregression.model.PairList; +import tregression.model.StepOperationTuple; +import tregression.model.TraceNodePair; +import tregression.separatesnapshots.DiffMatcher; + +/** + * Class containing logic for simulating debugging in concurrent programs + */ +public class ConcurrentSimulator extends Simulator { + + boolean isMultiThread = false; + public ConcurrentSimulator(boolean useSlicerBreaker, boolean enableRandom, int breakerTrialLimit) { + super(useSlicerBreaker, enableRandom, breakerTrialLimit); + } + + public boolean isMultiThread() { + return this.isMultiThread; + } + + public void prepareConc(List buggyTraces, + List correctTraces, + PairList combinedPairList, + Map threadIdMap, + DiffMatcher matcher) { + Map correctTraceMap = new HashMap<>(); + this.isMultiThread = correctTraces.size() > 1 || buggyTraces.size() > 1; + for (Trace trace : correctTraces) { + correctTraceMap.put(trace.getThreadId(), trace); + } + for (Trace trace : buggyTraces) { + if (!threadIdMap.containsKey(trace.getThreadId())) { + continue; + } + Trace correctTrace = correctTraceMap.get(threadIdMap.get(trace.getThreadId())); + this.prepare(trace, correctTrace, combinedPairList, matcher); + } + } + + private List startSimulationConc(TraceNode observedFaultNode, ConcurrentTrace buggyTrace, ConcurrentTrace correctTrace, + PairList pairList, DiffMatcher matcher, RootCauseFinder rootCauseFinder) { + StepChangeTypeChecker typeChecker = new StepChangeTypeChecker(buggyTrace, correctTrace); + List trials = new ArrayList<>(); + TraceNode currentNode = observedFaultNode; + EmpiricalTrial trial = workSingleTrialConc(buggyTrace, correctTrace, pairList, matcher, + rootCauseFinder, typeChecker, currentNode); + trials.add(trial); + + return trials; + } + + private ConcurrentTrace getTrace(boolean isBuggy, ConcurrentTrace trace1, ConcurrentTrace trace2) { + return isBuggy ? trace1 : trace2; + } + + public StepOperationTuple fromConcNode(ConcNode concNode, ConcurrentTrace buggyTrace, + ConcurrentTrace correctTrace, PairList pairList, DiffMatcher diffMatcher, StepChangeTypeChecker typeChecker, + RootCauseFinder rootCauseFinder) { + + ConcurrentTrace trace = buggyTrace; + if (!concNode.isBefore1()) { + trace = correctTrace; + } + UserFeedback feedback = null; + switch (concNode.getChangeType()) { + case StepChangeType.SRC: + feedback = new UserFeedback(UserFeedback.UNCLEAR); + break; + case StepChangeType.DAT: + // handle the data + feedback = new UserFeedback(UserFeedback.WRONG_VARIABLE_VALUE); + TraceNode currentNode = ((ConcurrentTraceNode)trace.getTraceNode(concNode.getNode1())).getInitialTraceNode(); + StepChangeType changeType = typeChecker.getType(currentNode, concNode.isBefore1(), pairList, matcher); + VarValue value = changeType.getWrongVariable(currentNode, concNode.isBefore1(), rootCauseFinder); + return generateDataFeedback(currentNode, changeType, value); + case StepChangeType.CTL: + feedback = new UserFeedback(UserFeedback.WRONG_PATH); + break; + case -1: + feedback = new UserFeedback(UserFeedback.UNCLEAR); + break; + } + return new StepOperationTuple(( + (ConcurrentTraceNode) trace.getTraceNode(concNode.getNode1())).getInitialTraceNode(), + feedback, + null); + } + + protected EmpiricalTrial workSingleTrialConc(ConcurrentTrace buggyTrace, + ConcurrentTrace correctTrace, PairList pairList, DiffMatcher matcher, + RootCauseFinder rootCauseFinder, StepChangeTypeChecker typeChecker, + TraceNode currentNode) { + List checkingList = new ArrayList<>(); + TraceNode rootcauseNode = rootCauseFinder.retrieveRootCause(pairList, matcher, buggyTrace, correctTrace); + rootCauseFinder.setRootCauseBasedOnDefects4J(pairList, matcher, buggyTrace, correctTrace); + long startTime = System.currentTimeMillis(); + + if (rootcauseNode != null) { + List regressionList = new LinkedList<>(); + List correctNodeList = new LinkedList<>(); + /** + * BFS to get to the root cause. + */ + List edgeList = rootCauseFinder.getConcNodes(); + // the edge taken that caused this node to be visited in bfs + HashMap, ConcNode> visitedPrevious = new HashMap<>(); + int target = rootcauseNode.getBound().getOrder(); + // use BFS to perform debugging -> find the path to root cause + HashMap, LinkedList> adjMatrix = new HashMap<>(); + for (ConcNode concNode : edgeList) { + if (!adjMatrix.containsKey(concNode.getFirst())) { + adjMatrix.put(concNode.getFirst(), new LinkedList<>()); + } + adjMatrix.get(concNode.getFirst()).add(concNode); + } + // start bfs from current node to rear + int startNode = currentNode.getBound().getOrder(); + Queue> frontier = new LinkedList<>(); + frontier.add(Pair.of(startNode, true)); + while (!frontier.isEmpty()) { + Pair frontPair = frontier.poll(); + // we found the target + if (frontPair.first() == target && frontPair.second() == true) { + break; + } + if (adjMatrix.get(frontPair) != null) { + for (ConcNode concNode : adjMatrix.get(frontPair)) { + Pair currPair = Pair.of(concNode.getNode2(), concNode.isBefore2()); + if (visitedPrevious.containsKey(currPair)) continue; + frontier.add(currPair); + visitedPrevious.put(currPair, concNode); + } + } + } + LinkedList edgesTakeNodes = new LinkedList<>(); + Pair currentPair = Pair.of(target, true); + Pair rootPair = Pair.of(startNode, true); + while (!currentPair.equals(rootPair)) { + ConcNode edgeConcNode = visitedPrevious.get(currentPair); + if (edgeConcNode == null) break; + edgesTakeNodes.add(edgeConcNode); + currentPair = Pair.of(edgeConcNode.getNode1(), edgeConcNode.isBefore1()); + } + Iterator descIterator = edgesTakeNodes.descendingIterator(); + + while (descIterator.hasNext()) { + ConcNode node = descIterator.next(); + checkingList.add(fromConcNode(node, buggyTrace, correctTrace, pairList, matcher, typeChecker, rootCauseFinder)); + ConcurrentTrace trace = getTrace(node.isBefore1(), buggyTrace, correctTrace); + TraceNode traceNode = trace.getTraceNode(node.getNode1()).getBound().getInitialTraceNode(); + if (node.isBefore1()) { + regressionList.add(traceNode); + } else { + correctNodeList.add(traceNode); + } + } + regressionList.add(rootcauseNode); + rootCauseFinder.setRegressionNodeList(regressionList); + rootCauseFinder.setCorrectNodeList(correctNodeList); + checkingList.add(new StepOperationTuple( + ((ConcurrentTraceNode) buggyTrace.getTraceNode(target)).getInitialTraceNode(), + new UserFeedback(UserFeedback.UNCLEAR), null)); + + long endTime = System.currentTimeMillis(); + EmpiricalTrial trial = new EmpiricalTrial(EmpiricalTrial.FIND_BUG, 0, rootcauseNode, + checkingList, -1, -1, (int)(endTime-startTime), buggyTrace.size(), correctTrace.size(), + rootCauseFinder, isMultiThread); + return trial; + } + + + /** + * start debugging + */ + while (true) { + TraceNode previousNode = null; + if(!checkingList.isEmpty()){ + StepOperationTuple lastTuple = checkingList.get(checkingList.size()-1); + previousNode = lastTuple.getNode(); + } + + if(currentNode==null || (previousNode!=null && currentNode.getOrder()==previousNode.getOrder())){ + long endTime = System.currentTimeMillis(); + EmpiricalTrial trial = new EmpiricalTrial(EmpiricalTrial.OVER_SKIP, -1, rootcauseNode, + checkingList, -1, -1, (int)(endTime-startTime), buggyTrace.size(), correctTrace.size(), + rootCauseFinder, isMultiThread); + return trial; + } + + StepChangeType changeType = typeChecker.getType(currentNode, true, pairList, matcher); + + if (changeType.getType() == StepChangeType.SRC) { + StepOperationTuple operation = new StepOperationTuple(currentNode, + new UserFeedback(UserFeedback.UNCLEAR), null); + checkingList.add(operation); + + long endTime = System.currentTimeMillis(); + EmpiricalTrial trial = new EmpiricalTrial(EmpiricalTrial.FIND_BUG, 0, rootcauseNode, + checkingList, -1, -1, (int)(endTime-startTime), buggyTrace.size(), correctTrace.size(), + rootCauseFinder, isMultiThread); + return trial; + } else if (changeType.getType() == StepChangeType.DAT) { + VarValue readVar = changeType.getWrongVariable(currentNode, true, rootCauseFinder); + StepOperationTuple operation = generateDataFeedback(currentNode, changeType, readVar); + checkingList.add(operation); + + TraceNode dataDom = buggyTrace.findDataDependency(currentNode, readVar); + + currentNode = dataDom; + } else if (changeType.getType() == StepChangeType.CTL) { + TraceNode controlDom = null; + if(currentNode.insideException()){ + controlDom = currentNode.getStepInPrevious(); + } + else{ + controlDom = currentNode.getInvocationMethodOrDominator(); + //indicate the control flow is caused by try-catch + if(controlDom!=null && !controlDom.isConditional() && controlDom.isBranch() + && !controlDom.equals(currentNode.getInvocationParent())){ + StepChangeType t = typeChecker.getType(controlDom, true, pairList, matcher); + if(t.getType()==StepChangeType.IDT){ + controlDom = findLatestControlDifferent(currentNode, controlDom, + typeChecker, pairList, matcher); + } + } + + if(controlDom==null) { + controlDom = currentNode.getStepInPrevious(); + } + } + + StepOperationTuple operation = new StepOperationTuple(currentNode, + new UserFeedback(UserFeedback.WRONG_PATH), null); + checkingList.add(operation); + + currentNode = controlDom; + } + /** + * when it is a correct node + */ + else { + StepOperationTuple operation = new StepOperationTuple(currentNode, + new UserFeedback(UserFeedback.CORRECT), null); + checkingList.add(operation); + + if(currentNode.isException()){ + currentNode = currentNode.getStepInPrevious(); + continue; + } + + int overskipLen = checkOverskipLength(pairList, matcher, buggyTrace, rootcauseNode, checkingList); + if(overskipLen<0 && checkingList.size()>=2){ + int size = checkingList.size(); + if(checkingList.get(size-2).getUserFeedback().getFeedbackType().equals(UserFeedback.WRONG_PATH)){ + overskipLen = 1; + } + } + + long endTime = System.currentTimeMillis(); + EmpiricalTrial trial = new EmpiricalTrial(EmpiricalTrial.OVER_SKIP, overskipLen, rootcauseNode, + checkingList, -1, -1, (int)(endTime-startTime), buggyTrace.size(), correctTrace.size(), + rootCauseFinder, isMultiThread); + + if(previousNode!=null){ + StepChangeType prevChangeType = typeChecker.getType(previousNode, true, pairList, matcher); + List list = null; + if(prevChangeType.getType()==StepChangeType.CTL){ + list = createControlRecord(currentNode, previousNode, typeChecker, pairList, matcher); + trial.setDeadEndRecordList(list); + } + else if(prevChangeType.getType()==StepChangeType.DAT){ + list = createDataRecord(currentNode, previousNode, typeChecker, pairList, matcher, rootCauseFinder); + trial.setDeadEndRecordList(list); + } + + if(trial.getBugType()==EmpiricalTrial.OVER_SKIP && trial.getOverskipLength()==0){ + if(list != null && !list.isEmpty()){ + DeadEndRecord record = list.get(0); + int len = currentNode.getOrder() - record.getBreakStepOrder(); + trial.setOverskipLength(len); + } + } + } + + return trial; + } + + } + + } + + + + @Override + protected List createDataRecord(TraceNode currentNode, TraceNode buggyNode, + StepChangeTypeChecker typeChecker, PairList pairList, DiffMatcher matcher, + RootCauseFinder rootCauseFinder) { + // TODO Auto-generated method stub + List deadEndlist = new ArrayList<>(); + TraceNodePair pair = pairList.findByBeforeNode(buggyNode); + TraceNode matchingStep = pair.getAfterNode(); + + TraceNode domOnRef = null; + StepChangeType matchingStepType = typeChecker.getType(matchingStep, false, pairList, matcher); + System.currentTimeMillis(); + if(matchingStepType.getWrongVariableList()==null) { + return deadEndlist; + } + + VarValue wrongVar = matchingStepType.getWrongVariable(currentNode, false, rootCauseFinder); + domOnRef = matchingStep.getDataDominator(wrongVar); + + List breakSteps = new ArrayList<>(); + + while(domOnRef != null){ + StepChangeType changeType = typeChecker.getType(domOnRef, false, pairList, matcher); + if(changeType.getType()==StepChangeType.SRC){ + breakSteps = findTheNearestCorrespondence(domOnRef, pairList, buggyNode.getTrace(), matchingStep.getTrace()); + break; + } + else{ + TraceNodePair conPair = pairList.findByAfterNode(domOnRef); + if(conPair != null && conPair.getBeforeNode() != null){ + /** + * if we find a matched step on buggy trace, then we find the first incorrect step starting at the matched + * step as the break step. + */ + TraceNode matchingPoint = conPair.getBeforeNode(); + for(int order=matchingPoint.getOrder(); order<=matchingPoint.getTrace().size(); order++){ + TraceNode potentialPoint = matchingPoint.getTrace().getTraceNode(order); + StepChangeType ct = typeChecker.getType(potentialPoint, true, pairList, matcher); + if(ct.getType()!=StepChangeType.IDT){ + breakSteps.add(potentialPoint); + break; + } + } + + break; + } + else{ + domOnRef = domOnRef.getInvocationMethodOrDominator(); + } + } + } + + VarValue wrongVarOnBuggyTrace = matchingStepType.getWrongVariable(currentNode, true, rootCauseFinder); + for(TraceNode breakStep: breakSteps){ + DeadEndRecord record = new DeadEndRecord(DeadEndRecord.DATA, buggyNode.getOrder(), + currentNode.getOrder(), -1, breakStep.getOrder()); + record.setVarValue(wrongVarOnBuggyTrace); + if(!deadEndlist.contains(record)) { + deadEndlist.add(record); + } + } + + return deadEndlist; + } + private List findSameLineSteps(TraceNode domOnRef) { + List list = new ArrayList<>(); + list.add(domOnRef); + + TraceNode node = domOnRef.getStepOverPrevious(); + while(node!=null && node.getLineNumber()==domOnRef.getLineNumber()){ + list.add(node); + node = node.getStepOverPrevious(); + } + + node = domOnRef.getStepOverNext(); + while(node!=null && node.getLineNumber()==domOnRef.getLineNumber()){ + list.add(node); + node = node.getStepOverNext(); + } + + return list; + } + @Override + protected List findTheNearestCorrespondence(TraceNode domOnRef, PairList pairList, Trace buggyTrace, + Trace correctTrace) { + List list = new ArrayList<>(); + + List sameLineSteps = findSameLineSteps(domOnRef); + for(TraceNode sameLineStep: sameLineSteps){ + TraceNodePair pair = pairList.findByAfterNode(sameLineStep); + if(pair!=null){ + TraceNode beforeNode = pair.getBeforeNode(); + if(beforeNode!=null){ + list.add(beforeNode); + } + } + } + if(!list.isEmpty()){ + return list; + } + + int endOrder = new RootCauseFinder().findEndOrderInOtherTrace(domOnRef, pairList, false, correctTrace); + if (endOrder >= buggyTrace.size()) { + endOrder = buggyTrace.size(); + } + TraceNode startNode = buggyTrace.getTraceNode(endOrder); + list.add(startNode); + while(startNode.getStepOverPrevious()!=null && + startNode.getStepOverPrevious().getBreakPoint().equals(startNode.getBreakPoint())){ + startNode = startNode.getStepOverPrevious(); + list.add(startNode); + } + +// TraceNode end = buggyTrace.getTraceNode(endOrder); +// TraceNode n = end.getStepOverNext(); +// while(n!=null && (n.getLineNumber()==end.getLineNumber())){ +// list.add(n); +// n = n.getStepOverNext(); +// } + + return list; + } + + protected EmpiricalTrial workSingleTrial(Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher, + RootCauseFinder rootCauseFinder, StepChangeTypeChecker typeChecker, + TraceNode currentNode) { + + List checkingList = new ArrayList<>(); + + TraceNode rootcauseNode = rootCauseFinder.retrieveRootCause(pairList, matcher, buggyTrace, correctTrace); + rootCauseFinder.setRootCauseBasedOnDefects4J(pairList, matcher, buggyTrace, correctTrace); + + boolean isMultiThread = false; + + long startTime = System.currentTimeMillis(); + + /** + * start debugging + */ + while (true) { + TraceNode previousNode = null; + if(!checkingList.isEmpty()){ + StepOperationTuple lastTuple = checkingList.get(checkingList.size()-1); + previousNode = lastTuple.getNode(); + previousNode = previousNode.getBound(); + } + + if(currentNode==null || (previousNode!=null && currentNode.getOrder()==previousNode.getOrder())){ + long endTime = System.currentTimeMillis(); + EmpiricalTrial trial = new EmpiricalTrial(EmpiricalTrial.OVER_SKIP, -1, rootcauseNode, + checkingList, -1, -1, (int)(endTime-startTime), buggyTrace.size(), correctTrace.size(), + rootCauseFinder, isMultiThread); + return trial; + } + + StepChangeType changeType = typeChecker.getType(currentNode, true, pairList, matcher); + + if (changeType.getType() == StepChangeType.SRC) { + StepOperationTuple operation = new StepOperationTuple(currentNode, + new UserFeedback(UserFeedback.UNCLEAR), null); + checkingList.add(operation); + + long endTime = System.currentTimeMillis(); + EmpiricalTrial trial = new EmpiricalTrial(EmpiricalTrial.FIND_BUG, 0, rootcauseNode, + checkingList, -1, -1, (int)(endTime-startTime), buggyTrace.size(), correctTrace.size(), + rootCauseFinder, isMultiThread); + return trial; + } else if (changeType.getType() == StepChangeType.DAT) { + VarValue readVar = changeType.getWrongVariable(currentNode, true, rootCauseFinder); + StepOperationTuple operation = generateDataFeedback(currentNode, changeType, readVar); + checkingList.add(operation); + + TraceNode dataDom = buggyTrace.findDataDependency(currentNode, readVar); + + currentNode = dataDom; + } else if (changeType.getType() == StepChangeType.CTL) { + TraceNode controlDom = null; + if(currentNode.insideException()){ + controlDom = currentNode.getStepInPrevious(); + } + else{ + controlDom = currentNode.getInvocationMethodOrDominator(); + //indicate the control flow is caused by try-catch + if(controlDom!=null && !controlDom.isConditional() && controlDom.isBranch() + && !controlDom.equals(currentNode.getInvocationParent())){ + StepChangeType t = typeChecker.getType(controlDom, true, pairList, matcher); + if(t.getType()==StepChangeType.IDT){ + controlDom = findLatestControlDifferent(currentNode, controlDom, + typeChecker, pairList, matcher); + } + } + + if(controlDom==null) { + controlDom = currentNode.getStepInPrevious(); + } + } + + StepOperationTuple operation = new StepOperationTuple(currentNode, + new UserFeedback(UserFeedback.WRONG_PATH), null); + checkingList.add(operation); + + currentNode = controlDom; + } + /** + * when it is a correct node + */ + else { + StepOperationTuple operation = new StepOperationTuple(currentNode, + new UserFeedback(UserFeedback.CORRECT), null); + checkingList.add(operation); + + if(currentNode.isException()){ + currentNode = currentNode.getStepInPrevious(); + continue; + } + + int overskipLen = checkOverskipLength(pairList, matcher, buggyTrace, rootcauseNode, checkingList); + if(overskipLen<0 && checkingList.size()>=2){ + int size = checkingList.size(); + if(checkingList.get(size-2).getUserFeedback().getFeedbackType().equals(UserFeedback.WRONG_PATH)){ + overskipLen = 1; + } + } + + long endTime = System.currentTimeMillis(); + EmpiricalTrial trial = new EmpiricalTrial(EmpiricalTrial.OVER_SKIP, overskipLen, rootcauseNode, + checkingList, -1, -1, (int)(endTime-startTime), buggyTrace.size(), correctTrace.size(), + rootCauseFinder, isMultiThread); + + if(previousNode!=null){ + StepChangeType prevChangeType = typeChecker.getType(previousNode, true, pairList, matcher); + List list = null; + if(prevChangeType.getType()==StepChangeType.CTL){ + list = createControlRecord(currentNode, previousNode, typeChecker, pairList, matcher); + trial.setDeadEndRecordList(list); + } + else if(prevChangeType.getType()==StepChangeType.DAT){ + list = createDataRecord(currentNode, previousNode, typeChecker, pairList, matcher, rootCauseFinder); + trial.setDeadEndRecordList(list); + } + + if(trial.getBugType()==EmpiricalTrial.OVER_SKIP && trial.getOverskipLength()==0){ + if(list != null && !list.isEmpty()){ + DeadEndRecord record = list.get(0); + int len = currentNode.getOrder() - record.getBreakStepOrder(); + trial.setOverskipLength(len); + } + } + } + + return trial; + } + + } + + } + + private List startSimulationWithCachedState(TraceNode observedFaultNode, Trace buggyTrace, Trace correctTrace, + PairList pairList, DiffMatcher matcher, RootCauseFinder rootCauseFinder) { + StepChangeTypeChecker typeChecker = new StepChangeTypeChecker(buggyTrace, correctTrace); + List trials = new ArrayList<>(); + TraceNode currentNode = observedFaultNode; + + Stack stack = new Stack<>(); + stack.push(new DebuggingState(currentNode, new ArrayList(), null)); + Set visitedStates = new HashSet<>(); + + while (!stack.isEmpty()){ + DebuggingState state = stack.pop(); + + EmpiricalTrial trial = workSingleTrialWithCachedState(buggyTrace, correctTrace, pairList, matcher, + rootCauseFinder, typeChecker, currentNode, stack, visitedStates, state); + trials.add(trial); + + if(trial.isBreakSlice()){ + break; + } + } + + return trials; + } + + + /** + * Method to perform ERASE without relying on merging the trace into a single trace list + * + * @param buggyTrace + * @param correctTrace + * @param matcher + * @param optionSearchLimit + * @return + * @throws SimulationFailException + */ + public List detectMutatedBugAlt(List buggyTrace, List correctTrace, + DiffMatcher matcher, + PairList overallPairList, + Map threadIdMap) throws SimulationFailException { + List trials = null; + return null; + } + + + public List detectMutatedBug(Trace buggyTrace, Trace correctTrace, DiffMatcher matcher, + int optionSearchLimit) throws SimulationFailException { + List trials = null; + for (TraceNode observedFault: observedFaultList) { + RootCauseFinder finder = new RootCauseFinder(); + + long start = System.currentTimeMillis(); + finder.checkRootCauseConc(observedFault, (ConcurrentTrace) buggyTrace, (ConcurrentTrace) correctTrace, pairList, matcher); + long end = System.currentTimeMillis(); + int checkTime = (int) (end-start); + + System.out.println("use slice breaker: " + useSliceBreaker); + if(useSliceBreaker) { + trials = startSimulationWithCachedState(observedFault, buggyTrace, correctTrace, getPairList(), matcher, finder); + } + else { + trials = startSimulationConc(observedFault, (ConcurrentTrace) buggyTrace, (ConcurrentTrace) correctTrace, getPairList(), matcher, finder); + } + + if(trials!=null) { + boolean rootcauseFind = false; + for(EmpiricalTrial trial: trials) { + if(!rootcauseFind && trial.getRootcauseNode()!=null) { + rootcauseFind = true; + } + trial.setSimulationTime(checkTime); + } + + if(rootcauseFind){ + observedFaultList.clear(); + observedFaultList.add(observedFault); + return trials; + } + } + } + + return trials; + } + + + + +} diff --git a/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java b/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java index 361279ab..e5bf3c4b 100644 --- a/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java +++ b/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java @@ -37,6 +37,8 @@ public class EmpiricalTrial { private List visitedRegressionNodes; private List visitedCorrectNodes; + private boolean isDeadLock = false; + private int totalVisitedNodesNum; private List checkList = new ArrayList<>(); @@ -46,7 +48,7 @@ public class EmpiricalTrial { private RootCauseFinder rootCauseFinder; private List deadEndRecordList = new ArrayList<>(); - + private boolean timeOut = false; private boolean isMultiThread; private long executionTime; @@ -80,6 +82,22 @@ public static EmpiricalTrial createDumpTrial(String reason){ return trial; } + public void setTimeout(boolean timeout) { + this.timeOut = timeout; + } + + public boolean isTimeout() { + return this.timeOut; + } + + public void setDeadLock(boolean isDeadLock) { + this.isDeadLock = isDeadLock; + } + + public boolean isDeadLock() { + return this.isDeadLock; + } + public boolean isDump(){ return bugType==-1 && checkList.isEmpty(); } @@ -100,7 +118,9 @@ public String toString() { String type = (this.bugType==FIND_BUG) ? "bug_found" : "over_skip"; buffer.append("trial type: " + type + "\n"); int rootcauseOrder = (this.rootcauseNode==null)? -1 : this.rootcauseNode.getOrder(); - buffer.append("found root cause: " + rootcauseOrder + "\n"); + String rootCauseThreadName = (this.rootcauseNode==null)?"":this.rootcauseNode.getTrace().getThreadName(); + + buffer.append("found root cause: " + rootcauseOrder + " " + rootCauseThreadName + "\n"); String realcauseOrders = ""; if(this.rootCauseFinder==null){ @@ -109,7 +129,7 @@ public String toString() { else{ for(RootCauseNode node: this.rootCauseFinder.getRealRootCaseList()){ realcauseOrders += node.toString() + ", "; - } + } } buffer.append("error message: " + exceptionExplanation + "\n"); diff --git a/tregression/src/main/tregression/empiricalstudy/Header.java b/tregression/src/main/tregression/empiricalstudy/Header.java index a9869c6a..4dd7fdad 100644 --- a/tregression/src/main/tregression/empiricalstudy/Header.java +++ b/tregression/src/main/tregression/empiricalstudy/Header.java @@ -24,6 +24,8 @@ public enum Header { EXCEPTION ("exception"), MULTI_THREAD ("multi thread"), + IS_DEADLOCK ("is deadlock"), + IS_TIMEOUT ("is timeout"), BREAK_TO_BUG ("break to bug"), diff --git a/tregression/src/main/tregression/empiricalstudy/Regression.java b/tregression/src/main/tregression/empiricalstudy/Regression.java index 018bc5bb..55f272ea 100644 --- a/tregression/src/main/tregression/empiricalstudy/Regression.java +++ b/tregression/src/main/tregression/empiricalstudy/Regression.java @@ -11,6 +11,7 @@ import microbat.preference.AnalysisScopePreference; import sav.strategies.dto.AppJavaClassPath; import tregression.empiricalstudy.config.Defects4jProjectConfig; +import tregression.empiricalstudy.config.ProjectConfig; import tregression.model.PairList; import tregression.separatesnapshots.AppClassPathInitializer; import tregression.separatesnapshots.TraceCollector0; @@ -20,6 +21,8 @@ public class Regression { private String testMethod; private Trace buggyTrace; private Trace correctTrace; + private List buggyTraces; + private List correctTraces; private PairList pairList; public Regression(Trace buggyTrace, Trace correctTrace, PairList pairList) { @@ -28,6 +31,7 @@ public Regression(Trace buggyTrace, Trace correctTrace, PairList pairList) { this.correctTrace = correctTrace; this.pairList = pairList; } + public Trace getBuggyTrace() { return buggyTrace; @@ -37,6 +41,11 @@ public void setBuggyTrace(Trace buggyTrace) { this.buggyTrace = buggyTrace; } + public void setBuggyAndCorrectTraces(List buggyTraces, List correctTraces) { + this.buggyTraces = buggyTraces; + this.correctTraces = correctTraces; + } + public Trace getCorrectTrace() { return correctTrace; } @@ -53,11 +62,24 @@ public void setPairList(PairList pairList) { this.pairList = pairList; } - public void fillMissingInfo(Defects4jProjectConfig config, String buggyPath, String fixPath) { - fillMissingInfo(buggyTrace, AppClassPathInitializer.initialize(buggyPath, new TestCase(testClass, testMethod), config)); - fillMissingInfo(correctTrace, AppClassPathInitializer.initialize(fixPath, new TestCase(testClass, testMethod), config)); + public void fillMissingInfo(ProjectConfig config, String buggyPath, String fixPath) { + AppJavaClassPath buggyAppJavaClassPath = AppClassPathInitializer.initialize(buggyPath, new TestCase(testClass, testMethod), config); + AppJavaClassPath correctAppJavaClassPath = AppClassPathInitializer.initialize(fixPath, new TestCase(testClass, testMethod), config); + if (buggyTraces != null) { + for (Trace buggyTrace : buggyTraces) { + fillMissingInfo(buggyTrace, buggyAppJavaClassPath); + } + for (Trace correctTrace: correctTraces) { + fillMissingInfo(correctTrace, correctAppJavaClassPath); + } + } else { + fillMissingInfo(buggyTrace, buggyAppJavaClassPath); + fillMissingInfo(correctTrace, correctAppJavaClassPath); + + } } + public static void fillMissingInfo(Trace trace, AppJavaClassPath appClassPath) { trace.setAppJavaClassPath(appClassPath); diff --git a/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java b/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java index 4729ae3b..eec60885 100644 --- a/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java +++ b/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java @@ -24,6 +24,7 @@ import microbat.codeanalysis.bytecode.MethodFinderBySignature; import microbat.codeanalysis.runtime.PreCheckInformation; import microbat.model.BreakPoint; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import microbat.util.PrimitiveUtils; @@ -73,7 +74,9 @@ public static List identifyIncludedClassNames(List stopSteps, private static TraceNode findClosestStep(TraceNode stopStep, List visitedSteps) { TraceNode closestStep = null; int distance = -1; - for(TraceNode step: visitedSteps) { + for(TraceNode st: visitedSteps) { + TraceNode step = ConcurrentTraceNode.getIniTraceNode(st); + if (step.getTrace().getThreadId() != stopStep.getTrace().getThreadId()) continue; if(step.getOrder()>stopStep.getOrder()) { if(closestStep==null) { closestStep = step; @@ -99,7 +102,7 @@ private static List identifyEnhanceRange(TraceNode stopStep, ListstopStep.getOrder(); i--) { TraceNode step = trace.getTraceNode(i); diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java index 84303541..8a5d1a1b 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java @@ -9,7 +9,10 @@ import microbat.codeanalysis.bytecode.MethodFinderByLine; import microbat.model.BreakPoint; import microbat.model.ClassLocation; +import microbat.model.ConcNode; import microbat.model.ControlScope; +import microbat.model.trace.ConcurrentTrace; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import microbat.model.trace.TraceNodeOrderComparator; @@ -123,6 +126,29 @@ private TraceNode findCorrespondingCorrectNode(PairList pairList, TraceNode bugg return null; } + public void setRootCauseBasedOnDefects4JConc(List pairLists, DiffMatcher matcher, List buggyTrace, List correctTrace) { + List list = new ArrayList<>(); + for (Trace bTrace : buggyTrace) { + for(int i=bTrace.size()-1; i>=0; i--) { + TraceNode buggyNode = bTrace.getExecutionList().get(i); + if(matcher.checkSourceDiff(buggyNode.getBreakPoint(), true)) { + list.add(new RootCauseNode(buggyNode, true)); + } + } + } + + for (Trace cTrace: correctTrace) { + for(int i=cTrace.size()-1; i>=0; i--) { + TraceNode correctTraceNode = cTrace.getExecutionList().get(i); + if(matcher.checkSourceDiff(correctTraceNode.getBreakPoint(), false)) { + list.add(new RootCauseNode(correctTraceNode, false)); + } + } + } + + this.setRealRootCaseList(list); + } + public void setRootCauseBasedOnDefects4J(PairList pairList, DiffMatcher matcher, Trace buggyTrace, Trace correctTrace) { List list = new ArrayList<>(); for(int i=buggyTrace.size()-1; i>=0; i--) { @@ -144,6 +170,153 @@ public void setRootCauseBasedOnDefects4J(PairList pairList, DiffMatcher matcher, private CausalityGraph causalityGraph; + private ArrayList nodes; + + public List getConcNodes() { + return nodes; + } + + /** + * Used to keep track of changes to work list and then construct explaination + * from observed fault to root cause. + */ + private void addConcNodes(TraceNode node1, TraceNode node2, boolean isOnBefore1, boolean isOnBefore2 + , int changeType) { + if (node1 == null || node2 == null) { + return; + } + nodes.add(ConcNode.fromTraceNodes(node1, node2, isOnBefore1, isOnBefore2, changeType)); + } + + + public void checkRootCauseConc(TraceNode observedFaultNode, ConcurrentTrace buggyTrace, ConcurrentTrace correctTrace, + PairList pairList, DiffMatcher matcher){ + nodes = new ArrayList<>(); + getRegressionNodeList().add(observedFaultNode); + + CausalityGraph causalityGraph = new CausalityGraph(); + CausalityNode causeNode = new CausalityNode(observedFaultNode, true); + causalityGraph.getObservedFaults().add(causeNode); + + List workList = new ArrayList<>(); + workList.add(new TraceNodeW(observedFaultNode, true)); + + StepChangeTypeChecker typeChecker = new StepChangeTypeChecker(buggyTrace, correctTrace); + + while(!workList.isEmpty()){ + TraceNodeW stepW = workList.remove(0); + TraceNode step = stepW.node; + + if (step instanceof ConcurrentTraceNode) { + step = ((ConcurrentTraceNode) step).getInitialTraceNode(); + } + CausalityNode resultNode = causalityGraph.findOrCreate(step, stepW.isOnBefore); + + StepChangeType changeType = typeChecker.getType(step, stepW.isOnBefore, pairList, matcher); + Trace trace = getCorrespondingTrace(stepW.isOnBefore, buggyTrace, correctTrace); + +// String isBefore = stepW.isOnBefore?"before":"after"; +// System.out.println("On " + isBefore + " trace," + step); +// System.out.println("It's a " + changeType.getType() + " type"); + + if(changeType.getType()==StepChangeType.SRC){ + //TODO + causalityGraph.addRoot(resultNode); + if(resultNode.isOnBefore()){ + break; + } + } + else if(changeType.getType()==StepChangeType.DAT){ + for(Pair pair: changeType.getWrongVariableList()){ + VarValue readVar = (stepW.isOnBefore)? pair.first() : pair.second(); + trace = getCorrespondingTrace(stepW.isOnBefore, buggyTrace, correctTrace); + + TraceNode dataDom = trace.findDataDependency(step, readVar); + addWorkNode(workList, dataDom, stepW.isOnBefore); + addCausality(dataDom, stepW.isOnBefore, causalityGraph, resultNode, readVar); + addConcNodes(step, dataDom, stepW.isOnBefore, stepW.isOnBefore, StepChangeType.DAT); + + + TraceNode matchedStep = changeType.getMatchingStep(); + addWorkNode(workList, matchedStep, !stepW.isOnBefore); + addConcNodes(step, matchedStep, stepW.isOnBefore, !stepW.isOnBefore, -1); + CausalityNode cNode = addCausality(matchedStep, !stepW.isOnBefore, causalityGraph, resultNode, null); + + trace = getCorrespondingTrace(!stepW.isOnBefore, buggyTrace, correctTrace); + + VarValue matchedVar = MatchStepFinder.findMatchVariable(readVar, matchedStep); + + if(matchedVar != null) { + TraceNode otherDataDom = trace.findDataDependency(matchedStep, matchedVar); + addConcNodes(step, otherDataDom, stepW.isOnBefore, !stepW.isOnBefore, StepChangeType.DAT); + addWorkNode(workList, otherDataDom, !stepW.isOnBefore); + addCausality(otherDataDom, !stepW.isOnBefore, causalityGraph, cNode, matchedVar); + } + + } + + } + else if(changeType.getType()==StepChangeType.CTL){ + TraceNode controlDom = step.getBound().getInvocationMethodOrDominator(); + if(step.insideException()){ + controlDom = step.getStepInPrevious(); + } + else if(controlDom!=null && !controlDom.isConditional() && controlDom.isBranch() + && !controlDom.equals(step.getInvocationParent())){ + StepChangeType t = typeChecker.getType(controlDom, true, pairList, matcher); + if(t.getType()==StepChangeType.IDT){ + controlDom = findLatestControlDifferent(step, controlDom, + typeChecker, pairList, matcher); + } + } + + if(controlDom==null){ + TraceNode invocationParent = step.getInvocationParent(); + if(!isMatchable(invocationParent, pairList, stepW.isOnBefore)){ + controlDom = invocationParent; + } + } + addWorkNode(workList, controlDom, stepW.isOnBefore); + addConcNodes(step, controlDom, stepW.isOnBefore, stepW.isOnBefore, StepChangeType.CTL); + CausalityNode cNode = addCausality(controlDom, stepW.isOnBefore, causalityGraph, resultNode, null); + + trace = getCorrespondingTrace(!stepW.isOnBefore, buggyTrace, correctTrace); + + ClassLocation correspondingLocation = matcher.findCorrespondingLocation(step.getBreakPoint(), !stepW.isOnBefore); + + TraceNode otherControlDom = findControlMendingNodeOnOtherTrace(step, pairList, trace, + !stepW.isOnBefore, correspondingLocation, matcher); + addWorkNode(workList, otherControlDom, !stepW.isOnBefore); + + addConcNodes(step, otherControlDom, stepW.isOnBefore, !stepW.isOnBefore, StepChangeType.CTL); + addCausality(otherControlDom, !stepW.isOnBefore, causalityGraph, cNode, null); + } + else if(changeType.getType()==StepChangeType.IDT){ + if(step.isException()){ + TraceNode nextStep = step.getStepInPrevious(); + addConcNodes(step, nextStep, stepW.isOnBefore, !stepW.isOnBefore, StepChangeType.IDT); + addWorkNode(workList, nextStep, !stepW.isOnBefore); + addCausality(nextStep, stepW.isOnBefore, causalityGraph, resultNode, null); + continue; + } + + if(stepW.isOnBefore){ + if(!this.stopStepsOnBuggyTrace.contains(step)){ + this.stopStepsOnBuggyTrace.add(step); + } + } + else{ + if(!this.stopStepsOnCorrectTrace.contains(step)){ + this.stopStepsOnCorrectTrace.add(step); + } + } + } + } + + causalityGraph.generateSimulationGuidance(); + this.causalityGraph = causalityGraph; + } + public void checkRootCause(TraceNode observedFaultNode, Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher){ getRegressionNodeList().add(observedFaultNode); @@ -609,6 +782,15 @@ public void setRootCause(TraceNode rootCause) { public List getRealRootCaseList() { return realRootCaseList; } + + /** + * Checks if the real root cause is empty. + * @return false if the real root cause is empty or null and true otherwise. + */ + public boolean hasRealRootCause() { + if (realRootCaseList == null) return false; + return !realRootCaseList.isEmpty(); + } public void setRealRootCaseList(List realRootCaseList) { this.realRootCaseList = realRootCaseList; diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java b/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java index 1dde75be..daf1bb3b 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java @@ -1,5 +1,6 @@ package tregression.empiricalstudy; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.TraceNode; public class RootCauseNode { @@ -31,10 +32,17 @@ public void setOnBefore(boolean isOnBefore) { @Override public String toString(){ + int order = root.getOrder(); + if (root instanceof ConcurrentTraceNode) { + order = ((ConcurrentTraceNode) root).getInitialOrder(); + } + StringBuffer buffer = new StringBuffer(); String trace = isOnBefore?"buggy":"correct"; buffer.append("On " + trace + " trace, order: "); - buffer.append(root.getOrder()); + buffer.append(order); + buffer.append(" On thread: "); + buffer.append(root.getTrace().getThreadName()); return buffer.toString(); } diff --git a/tregression/src/main/tregression/empiricalstudy/Simulator.java b/tregression/src/main/tregression/empiricalstudy/Simulator.java index 23e5f8ac..1d0887d7 100644 --- a/tregression/src/main/tregression/empiricalstudy/Simulator.java +++ b/tregression/src/main/tregression/empiricalstudy/Simulator.java @@ -2,11 +2,15 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.Stack; +import microbat.model.trace.ConcurrentTrace; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import microbat.model.value.VarValue; @@ -35,9 +39,9 @@ public class Simulator { protected PairList pairList; protected DiffMatcher matcher; - private List observedFaultList = new ArrayList<>(); + protected List observedFaultList = new ArrayList<>(); + protected boolean useSliceBreaker; - private boolean useSliceBreaker; private boolean enableRandom; private int breakerTrialLimit; @@ -169,15 +173,16 @@ protected boolean isObservedFaultWrongPath(TraceNode observableNode, PairList pa return false; } - + // List rootCauseNodes; public void prepare(Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher) { this.pairList = pairList; this.matcher = matcher; TraceNode initialStep = buggyTrace.getLatestNode(); + if (initialStep == null) return; TraceNode lastObservableFault = findObservedFault(initialStep, buggyTrace, correctTrace); - if(lastObservableFault!=null){ + if(lastObservableFault!=null) { observedFaultList.add(lastObservableFault); StepChangeTypeChecker checker = new StepChangeTypeChecker(buggyTrace, correctTrace); @@ -189,8 +194,7 @@ public void prepare(Trace buggyTrace, Trace correctTrace, PairList pairList, Dif StepChangeType changeType = checker.getType(node, true, pairList, matcher); if(changeType.getType()!=StepChangeType.IDT){ observedFaultList.add(node); - } - + } node = node.getStepOverPrevious(); } } @@ -234,6 +238,8 @@ public List detectMutatedBug(Trace buggyTrace, Trace correctTrac return trials; } + + private List startSimulationWithCachedState(TraceNode observedFaultNode, Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher, RootCauseFinder rootCauseFinder) { @@ -293,7 +299,7 @@ private List startSimulation(TraceNode observedFaultNode, Trace * @param state * @return */ - private EmpiricalTrial workSingleTrial(Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher, + protected EmpiricalTrial workSingleTrial(Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher, RootCauseFinder rootCauseFinder, StepChangeTypeChecker typeChecker, TraceNode currentNode) { @@ -445,7 +451,7 @@ else if(prevChangeType.getType()==StepChangeType.DAT){ * @param state * @return */ - private EmpiricalTrial workSingleTrialWithCachedState(Trace buggyTrace, Trace correctTrace, + protected EmpiricalTrial workSingleTrialWithCachedState(Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher, RootCauseFinder rootCauseFinder, StepChangeTypeChecker typeChecker, TraceNode currentNode, Stack stack, Set visitedStates, @@ -762,7 +768,7 @@ private List findRandomBreaker(List list, int breakerT } - private TraceNode findLatestControlDifferent(TraceNode currentNode, TraceNode controlDom, + protected TraceNode findLatestControlDifferent(TraceNode currentNode, TraceNode controlDom, StepChangeTypeChecker checker, PairList pairList, DiffMatcher matcher) { TraceNode n = currentNode.getStepInPrevious(); StepChangeType t = checker.getType(n, true, pairList, matcher); @@ -778,8 +784,12 @@ private TraceNode findLatestControlDifferent(TraceNode currentNode, TraceNode co return controlDom; } - private List createControlRecord(TraceNode currentNode, TraceNode latestBugNode, StepChangeTypeChecker typeChecker, + protected List createControlRecord(TraceNode currentNode, TraceNode latestBugNode, StepChangeTypeChecker typeChecker, PairList pairList, DiffMatcher matcher) { + if (latestBugNode instanceof ConcurrentTraceNode) { + return concurrentCreateControlRecord(currentNode, (ConcurrentTraceNode) latestBugNode, typeChecker, pairList, matcher); + } + List deadEndRecords = new ArrayList<>(); Trace trace = currentNode.getTrace(); @@ -806,7 +816,45 @@ private List createControlRecord(TraceNode currentNode, TraceNode return deadEndRecords; } - private List findTheNearestCorrespondence(TraceNode domOnRef, PairList pairList, Trace buggyTrace, Trace correctTrace) { + /** + * Find the dead end for control steps iff the change type is a control change type + * @param currentNode + * @param latestBugNode + * @param typeChecker + * @param pairList + * @param matcher + * @return + */ + private List concurrentCreateControlRecord(TraceNode currentNode, ConcurrentTraceNode latestBugNode, StepChangeTypeChecker typeChecker, + PairList pairList, DiffMatcher matcher) { + List deadEndRecords = new ArrayList<>(); + Trace trace = currentNode.getTrace(); + for(int i=currentNode.getOrder()+1; i<=latestBugNode.getInitialOrder() && i < trace.size(); i++) { + TraceNode node = trace.getTraceNode(i); + StepChangeType changeType = typeChecker.getType(node, true, pairList, matcher); + if(changeType.getType()==StepChangeType.CTL){ + DeadEndRecord record = new DeadEndRecord(DeadEndRecord.CONTROL, + latestBugNode.getOrder(), currentNode.getOrder(), -1, node.getOrder()); + deadEndRecords.add(record); + + TraceNode equivalentNode = node.getStepOverNext(); + while(equivalentNode!=null && equivalentNode.getBreakPoint().equals(node.getBreakPoint())){ + DeadEndRecord addRecord = new DeadEndRecord(DeadEndRecord.CONTROL, + latestBugNode.getOrder(), currentNode.getOrder(), -1, equivalentNode.getOrder()); + deadEndRecords.add(addRecord); + equivalentNode = equivalentNode.getStepOverNext(); + } + + break; + } + } + + return deadEndRecords; + + } + + + protected List findTheNearestCorrespondence(TraceNode domOnRef, PairList pairList, Trace buggyTrace, Trace correctTrace) { List list = new ArrayList<>(); List sameLineSteps = findSameLineSteps(domOnRef); @@ -861,7 +909,7 @@ private List findSameLineSteps(TraceNode domOnRef) { return list; } - private List createDataRecord(TraceNode currentNode, TraceNode buggyNode, + protected List createDataRecord(TraceNode currentNode, TraceNode buggyNode, StepChangeTypeChecker typeChecker, PairList pairList, DiffMatcher matcher, RootCauseFinder rootCauseFinder) { List deadEndlist = new ArrayList<>(); @@ -943,7 +991,7 @@ private List cloneList(List checkingList return list; } - private StepOperationTuple generateDataFeedback(TraceNode currentNode, StepChangeType changeType, + protected StepOperationTuple generateDataFeedback(TraceNode currentNode, StepChangeType changeType, VarValue readVar) { UserFeedback feedback = new UserFeedback(UserFeedback.WRONG_VARIABLE_VALUE); ChosenVariableOption option = new ChosenVariableOption(readVar, null); @@ -952,7 +1000,7 @@ private StepOperationTuple generateDataFeedback(TraceNode currentNode, StepChang return operation; } - private int checkOverskipLength(PairList pairList, DiffMatcher matcher, Trace buggyTrace, TraceNode rootcauseNode, + protected int checkOverskipLength(PairList pairList, DiffMatcher matcher, Trace buggyTrace, TraceNode rootcauseNode, List checkingList) { TraceNode latestNode = checkingList.get(checkingList.size() - 1).getNode(); diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 60baf437..b32a6fcd 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -4,9 +4,22 @@ import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Scanner; - +import java.util.Set; +import java.util.Stack; + +import microbat.codeanalysis.runtime.InstrumentationExecutor; +import microbat.handler.CancelThread; +import microbat.instrumentation.instr.aggreplay.TimeoutThread; +import microbat.instrumentation.output.RunningInfo; +import microbat.model.trace.ConcurrentTrace; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import microbat.preference.AnalysisScopePreference; @@ -22,11 +35,16 @@ import tregression.io.RegressionRecorder; import tregression.model.PairList; import tregression.model.StepOperationTuple; +import tregression.model.TraceNodePair; import tregression.separatesnapshots.AppClassPathInitializer; +import tregression.separatesnapshots.BuggyRnRTraceCollector; +import tregression.separatesnapshots.BuggyTraceCollector; import tregression.separatesnapshots.DiffMatcher; import tregression.separatesnapshots.RunningResult; import tregression.separatesnapshots.TraceCollector0; import tregression.tracematch.ControlPathBasedTraceMatcher; +import tregression.util.ConcurrentTraceMatcher; +import tregression.views.ConcurrentVisualiser; import tregression.views.Visualizer; public class TrialGenerator0 { @@ -38,13 +56,21 @@ public class TrialGenerator0 { public static final int OVER_LONG_INSTRUMENTATION_METHOD = 5; public static final int EXPECTED_STEP_NOT_MET = 6; public static final int UNDETERMINISTIC = 7; + public static final int NOT_MULTI_THREAD = 8; + public static final int NO_TRACE = 9; private RunningResult cachedBuggyRS; private RunningResult cachedCorrectRS; private DiffMatcher cachedDiffMatcher; private PairList cachedPairList; - + private List cachedPairLists; + private CancelThread cancelThread = null; + + public void setCancelThread(CancelThread cThread) { + this.cancelThread = cThread; + } + public static String getProblemType(int type) { switch (type) { case OVER_LONG: @@ -61,11 +87,128 @@ public static String getProblemType(int type) { return "expected steps are not met"; case UNDETERMINISTIC: return "this is undeterministic testcase"; + case NOT_MULTI_THREAD: + return "this is not multi threaded"; + case NO_TRACE: + return "main trace has no recording"; default: break; } return "I don't know"; } + + + public List findConcurrent(String buggyPath, String fixPath, boolean isReuse, boolean useSliceBreaker, + boolean enableRandom, int breakLimit, boolean requireVisualization, ProjectConfig config, String testcase) { + List tcList; + EmpiricalTrial trial = null; + TestCase workingTC = null; + LinkedList result = new LinkedList<>(); + try { + tcList = retrieveD4jFailingTestCase(buggyPath); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return new LinkedList<>(); + } + + if(testcase!=null){ + tcList = filterSpecificTestCase(testcase, tcList); + } + + for (TestCase tc : tcList) { + if (cancelThread != null && cancelThread.stopped) break; + System.out.println("#####working on test case " + tc.testClass + "#" + tc.testMethod); + workingTC = tc; + SingleTimer timer = SingleTimer.start("generateTrial"); + + List includedClassNames = AnalysisScopePreference.getIncludedLibList(); + List excludedClassNames = AnalysisScopePreference.getExcludedLibList(); + try { + InstrumentationExecutor executor = TraceCollector0.generateExecutor(buggyPath, tc, config, true, includedClassNames, excludedClassNames, true); + executor.runPrecheck(null, Settings.stepLimit); + + trial = EmpiricalTrial.createDumpTrial(""); + trial.setTestcase(tc.getName()); + trial.setMultiThread(executor.getPrecheckInfo().getThreadNum() > 1); + result.add(trial); + } catch (Exception e) { + trial = EmpiricalTrial.createDumpTrial("Runtime exception occurs " + e); + trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); + trial.setExecutionTime(timer.getExecutionTime()); + result.add(trial); + e.printStackTrace(); + } + +// if(!trial.isDump()){ +// break; +// } + } + + + +// if (trial == null) { +// trial = EmpiricalTrial.createDumpTrial("runtime exception occurs"); +// trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); +// } +// List list = new ArrayList<>(); +// list.add(trial); + return result; + } + + + public List generateTrialsConcurrent(String buggyPath, String fixPath, boolean isReuse, boolean useSliceBreaker, + boolean enableRandom, int breakLimit, boolean requireVisualization, ProjectConfig config, String testcase) { + List tcList; + EmpiricalTrial trial = null; + TestCase workingTC = null; + LinkedList result = new LinkedList<>(); + try { + tcList = retrieveD4jFailingTestCase(buggyPath); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return new LinkedList<>(); + } + + if(testcase!=null){ + tcList = filterSpecificTestCase(testcase, tcList); + } + + for (TestCase tc : tcList) { + if (cancelThread != null && cancelThread.stopped) break; + System.out.println("#####working on test case " + tc.testClass + "#" + tc.testMethod); + workingTC = tc; + SingleTimer timer = SingleTimer.start("generateTrial"); + try { + trial = analyzeConcurrentTestCase(buggyPath, fixPath, isReuse, + tc, config, requireVisualization, true, useSliceBreaker, enableRandom, breakLimit); + trial.setExecutionTime(timer.getExecutionTime()); + result.add(trial); + } catch (Exception e) { + trial = EmpiricalTrial.createDumpTrial("Runtime exception occurs " + e); + trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); + trial.setExecutionTime(timer.getExecutionTime()); + result.add(trial); + e.printStackTrace(); + } + +// if(!trial.isDump()){ +// break; +// } + } + + + +// if (trial == null) { +// trial = EmpiricalTrial.createDumpTrial("runtime exception occurs"); +// trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); +// } +// List list = new ArrayList<>(); +// list.add(trial); + return result; + } + public List generateTrials(String buggyPath, String fixPath, boolean isReuse, boolean useSliceBreaker, boolean enableRandom, int breakLimit, boolean requireVisualization, @@ -88,7 +231,7 @@ public List generateTrials(String buggyPath, String fixPath, boo trial = analyzeTestCase(buggyPath, fixPath, isReuse, allowMultiThread, tc, config, requireVisualization, true, useSliceBreaker, enableRandom, breakLimit); if(!trial.isDump()){ - break; + break; } } @@ -173,6 +316,324 @@ private void generateMainMethod(String workingPath, TestCase tc, Defects4jProjec System.currentTimeMillis(); } + /** + * + * @param traces The list of traces to check for dead lock + * @return The set of threads that are involved in the deadlock. + */ + private Set hasDeadlock(List traces) { + HashMap waitingForMap = new HashMap(); + HashSet visited = new HashSet<>(); + HashMap lockedOnMap = new HashMap(); + for (Trace trace : traces) { + for (Long object : trace.getAcquiredLocks()) { + lockedOnMap.put(object, trace.getThreadId()); + } + } + for (Trace trace : traces) { + if (lockedOnMap.containsKey(trace.getAcquiringLock())) { + waitingForMap.put(trace.getThreadId(), lockedOnMap.get(trace.getAcquiringLock())); + } + } + long cycleNode = -1L; + for (Trace trace : traces) { + if (visited.contains(trace.getThreadId())) continue; + long currentNode = trace.getThreadId(); + while (true) { + if (visited.contains(currentNode)) { + // detected a cycle. + cycleNode = currentNode; + break; + } + visited.add(currentNode); + if (!waitingForMap.containsKey(currentNode)) { + break; + } + currentNode = waitingForMap.get(currentNode); + } + if (cycleNode != -1) break; + } + // no cycles found + if (cycleNode == -1) return Collections.emptySet(); + HashSet cycleNodes = new HashSet(); + long currentNode = cycleNode; + while (true) { + if (cycleNodes.contains(currentNode)) break; + cycleNodes.add(currentNode); + currentNode = waitingForMap.get(currentNode); + } + + return cycleNodes; + } + + /** + * Used to run erased on concurrent program + */ + private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPath, boolean isReuse, + TestCase tc, ProjectConfig config, boolean requireVisualization, + boolean isRunInTestCaseMode, boolean useSliceBreaker, boolean enableRandom, int breakLimit) throws SimulationFailException { + TraceCollector0 buggyCollector = new BuggyTraceCollector(100); + TraceCollector0 correctCollector = new TraceCollector0(false); + long time1 = 0; + long time2 = 0; + + RunningResult buggyRS = null; + RunningResult correctRs = null; + + DiffMatcher diffMatcher = null; + PairList pairList = null; + + List basePairLists = null; + + int matchTime = -1; + if (cachedBuggyRS != null && cachedCorrectRS != null && cachedPairList != null && isReuse) { + buggyRS = cachedBuggyRS; + correctRs = cachedCorrectRS; + +// System.out.println("start matching trace..., buggy trace length: " + buggyRS.getRunningTrace().size() +// + ", correct trace length: " + correctRs.getRunningTrace().size()); +// time1 = System.currentTimeMillis(); +// diffMatcher = new DiffMatcher(config.srcSourceFolder, config.srcTestFolder, buggyPath, fixPath); +// diffMatcher.matchCode(); +// +// ControlPathBasedTraceMatcher traceMatcher = new ControlPathBasedTraceMatcher(); +// pairList = traceMatcher.matchTraceNodePair(buggyRS.getRunningTrace(), correctRs.getRunningTrace(), +// diffMatcher); +// time2 = System.currentTimeMillis(); +// matchTime = (int) (time2 - time1); +// System.out.println("finish matching trace, taking " + matchTime + "ms"); +// cachedDiffMatcher = diffMatcher; +// cachedPairList = pairList; + + diffMatcher = cachedDiffMatcher; + pairList = cachedPairList; + EmpiricalTrial trial = simulateDebuggingWithCatchedObjects(buggyRS.getRunningTrace(), + correctRs.getRunningTrace(), pairList, diffMatcher, requireVisualization, + useSliceBreaker, enableRandom, breakLimit); + return trial; + } else { + int trialLimit = 10; + int trialNum = 0; + boolean isDataFlowComplete = false; + EmpiricalTrial trial = null; + List includedClassNames = AnalysisScopePreference.getIncludedLibList(); + List excludedClassNames = AnalysisScopePreference.getExcludedLibList(); + + while(!isDataFlowComplete && trialNum buggyTraces = buggyRS.getRunningInfo().getTraceList(); + List correctTraces = correctRs.getRunningInfo().getTraceList(); + + AppJavaClassPath buggyAppJavaClassPath = buggyRS.getRunningInfo().getMainTrace().getAppJavaClassPath(); + AppJavaClassPath correctAppJavaClassPath = correctRs.getRunningInfo().getMainTrace().getAppJavaClassPath(); + for (Trace buggyTrace : buggyTraces) { + if (buggyTrace.getAppJavaClassPath() == null) { + buggyTrace.setAppJavaClassPath(buggyAppJavaClassPath); + } + } + for (Trace correctTrace : correctTraces) { + if (correctTrace.getAppJavaClassPath() == null) { + correctTrace.setAppJavaClassPath(correctAppJavaClassPath); + } + } + boolean isTimeout = buggyRS.getRunningInfo().getProgramMsg().equals(TimeoutThread.TIMEOUT_MSG); + boolean isCorrectTimeout = correctRs.getRunningInfo().getProgramMsg().equals(TimeoutThread.TIMEOUT_MSG); + + Set deadLockThreads = new HashSet(); + if (isTimeout) { + deadLockThreads = hasDeadlock(buggyTraces); + } + + Map threadIdMap = new HashMap<>(); + if (buggyRS != null && correctRs != null) { + cachedBuggyRS = buggyRS; + cachedCorrectRS = correctRs; + + System.out.println("start matching trace..., buggy trace length: " + buggyRS.getRunningTrace().size() + + ", correct trace length: " + correctRs.getRunningTrace().size()); + time1 = System.currentTimeMillis(); + diffMatcher = new DiffMatcher(config.srcSourceFolder, config.srcTestFolder, buggyPath, fixPath); + diffMatcher.matchCode(); + + threadIdMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); + ControlPathBasedTraceMatcher traceMatcher = new ControlPathBasedTraceMatcher(); + basePairLists = traceMatcher.matchConcurrentTraceNodePair(buggyTraces, correctTraces, diffMatcher, threadIdMap); + LinkedList pairs = new LinkedList<>(); + for (PairList pList : basePairLists) { + pairs.addAll(pList.getPairList()); + } + pairList = new PairList(pairs); + + time2 = System.currentTimeMillis(); + matchTime = (int) (time2 - time1); + System.out.println("finish matching trace, taking " + matchTime + "ms"); + System.out.println("Finish matching concurrent trace"); + cachedDiffMatcher = diffMatcher; + cachedPairLists = basePairLists; + cachedPairList = pairList; + } + + System.out.println("Wrong traces"); + + for (Trace trace : buggyTraces) { + if (trace.getInnerThreadId() == null) { + System.out.println("null"); + continue; + } + System.out.println(trace.getInnerThreadId().printRootListNode()); + } + + System.out.println("Correct traces"); + for (Trace trace : correctTraces) { + if (trace.getInnerThreadId() == null) { + System.out.println("null"); + continue; + } + System.out.println(trace.getInnerThreadId().printRootListNode()); + } + for (Trace trace : buggyTraces) { + if (trace.getAppJavaClassPath() == null) { + System.out.println("Null app java path"); + throw new RuntimeException("missing app java path"); + } + } + for (Trace trace : correctTraces) { + if (trace.getAppJavaClassPath() == null) { + throw new RuntimeException("Missing app java path"); + } + } + + ConcurrentTrace buggyTrace = ConcurrentTrace.fromTimeStampOrder(buggyTraces); + ConcurrentTrace correctTrace = ConcurrentTrace.fromTimeStampOrder(correctTraces); + + + if (requireVisualization) { + ConcurrentVisualiser visualizer = + new ConcurrentVisualiser(correctTraces, buggyTraces, buggyTrace, correctTrace, pairList, diffMatcher); + visualizer.visualise(); + } + + RootCauseFinder rootcauseFinder = new RootCauseFinder(); + rootcauseFinder.setRootCauseBasedOnDefects4JConc(basePairLists, diffMatcher, buggyTraces, correctTraces); + + + + + + ConcurrentSimulator simulator = new ConcurrentSimulator(useSliceBreaker, enableRandom, breakLimit); + + simulator.prepareConc(buggyTraces, correctTraces, pairList, threadIdMap, diffMatcher); + if (!simulator.isMultiThread()) { + EmpiricalTrial trial0 = EmpiricalTrial.createDumpTrial("is not multi thread"); + trial0.setTestcase(tc.getName()); + trial0.setBugType(NOT_MULTI_THREAD); + return trial0; + } + if(rootcauseFinder.getRealRootCaseList().isEmpty()) { + trial = EmpiricalTrial.createDumpTrial("cannot find real root cause"); + StepOperationTuple tuple = new StepOperationTuple(simulator.getObservedFault(), + new UserFeedback(UserFeedback.UNCLEAR), simulator.getObservedFault(), DebugState.UNCLEAR); + trial.getCheckList().add(tuple); + return trial; + } + + if(simulator.getObservedFault()==null){ + trial = EmpiricalTrial.createDumpTrial("cannot find observable fault"); + return trial; + } + + rootcauseFinder.checkRootCauseConc(simulator.getObservedFault(), buggyTrace, correctTrace, pairList, diffMatcher); + TraceNode rootCause = rootcauseFinder.retrieveRootCause(pairList, diffMatcher, buggyTrace, correctTrace); + + if(rootCause==null){ + + System.out.println("[Search Lib Class] Cannot find the root cause, I am searching for library classes..."); + + List buggySteps = rootcauseFinder.getStopStepsOnBuggyTrace(); + List correctSteps = rootcauseFinder.getStopStepsOnCorrectTrace(); + + List newIncludedClassNames = new ArrayList<>(); + + List convertedBuggySteps = ConcurrentTraceNode.convert(buggySteps); + List convertedConcurrentSteps = ConcurrentTraceNode.convert(correctSteps); + List convertedRegressionNodes = ConcurrentTraceNode.convert(rootcauseFinder.getRegressionNodeList()); + List convertedCorrectNodeList = ConcurrentTraceNode.convert(rootcauseFinder.getCorrectNodeList()); + + + List newIncludedBuggyClassNames = RegressionUtil.identifyIncludedClassNames(convertedBuggySteps, buggyRS.getPrecheckInfo(), convertedRegressionNodes); + List newIncludedCorrectClassNames = RegressionUtil.identifyIncludedClassNames(convertedConcurrentSteps, correctRs.getPrecheckInfo(), convertedCorrectNodeList); + + newIncludedClassNames.addAll(newIncludedBuggyClassNames); + newIncludedClassNames.addAll(newIncludedCorrectClassNames); + boolean includedClassChanged = false; + for(String name: newIncludedClassNames){ + if(!includedClassNames.contains(name)){ + includedClassNames.add(name); + includedClassChanged = true; + } + } + + if(!includedClassChanged) { + trialNum = trialLimit + 1; + } + else { + continue; + } + } + + isDataFlowComplete = true; + + System.out.println("start simulating debugging..."); + time1 = System.currentTimeMillis(); + List trials0 = simulator.detectMutatedBug(buggyTrace, correctTrace, diffMatcher, 0); + time2 = System.currentTimeMillis(); + int simulationTime = (int) (time2 - time1); + System.out.println("finish simulating debugging, taking " + simulationTime / 1000 + "s"); + + for (EmpiricalTrial t : trials0) { + t.setTestcase(tc.testClass + "#" + tc.testMethod); + t.setTraceCollectionTime(buggyTrace.getConstructTime() + correctTrace.getConstructTime()); + t.setTraceMatchTime(matchTime); + t.setBuggyTrace(buggyTrace); + t.setFixedTrace(correctTrace); + t.setPairList(pairList); + t.setDiffMatcher(diffMatcher); + t.setDeadLock(deadLockThreads.size() > 0); + PatternIdentifier identifier = new PatternIdentifier(); + identifier.identifyPattern(t); + } + + trial = trials0.get(0); + return trial; + } + + } + + return null; + + } + + private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean isReuse, boolean allowMultiThread, TestCase tc, ProjectConfig config, boolean requireVisualization, boolean isRunInTestCaseMode, boolean useSliceBreaker, boolean enableRandom, int breakLimit) throws SimulationFailException { @@ -188,7 +649,7 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean PairList pairList = null; int matchTime = -1; - if (cachedBuggyRS != null && cachedCorrectRS != null && isReuse) { + if (cachedBuggyRS != null && cachedCorrectRS != null && cachedPairList != null && isReuse) { buggyRS = cachedBuggyRS; correctRs = cachedCorrectRS; @@ -209,7 +670,6 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean diffMatcher = cachedDiffMatcher; pairList = cachedPairList; - EmpiricalTrial trial = simulateDebuggingWithCatchedObjects(buggyRS.getRunningTrace(), correctRs.getRunningTrace(), pairList, diffMatcher, requireVisualization, useSliceBreaker, enableRandom, breakLimit); @@ -259,7 +719,7 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean time2 = System.currentTimeMillis(); matchTime = (int) (time2 - time1); System.out.println("finish matching trace, taking " + matchTime + "ms"); - + System.out.println("Finish matching concurrent trace"); cachedDiffMatcher = diffMatcher; cachedPairList = pairList; } @@ -277,12 +737,11 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean Simulator simulator = new Simulator(useSliceBreaker, enableRandom, breakLimit); simulator.prepare(buggyTrace, correctTrace, pairList, diffMatcher); - if(rootcauseFinder.getRealRootCaseList().isEmpty()){ + if(rootcauseFinder.getRealRootCaseList().isEmpty()) { trial = EmpiricalTrial.createDumpTrial("cannot find real root cause"); StepOperationTuple tuple = new StepOperationTuple(simulator.getObservedFault(), new UserFeedback(UserFeedback.UNCLEAR), simulator.getObservedFault(), DebugState.UNCLEAR); trial.getCheckList().add(tuple); - return trial; } diff --git a/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java b/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java index 04497068..032075af 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java @@ -14,6 +14,8 @@ import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import microbat.model.trace.ConcurrentTraceNode; +import microbat.model.trace.TraceNode; import tregression.model.StepOperationTuple; public class TrialRecorder { @@ -109,17 +111,20 @@ private void fillRowInformation(Row row, EmpiricalTrial trial, String project, S setCellValue(row, Header.BUG_ID, bugID); setCellValue(row, Header.MUTATION_TYPE, mutationType); setCellValue(row, Header.TESTCASE, trial.getTestcase()); - - int order = -1; + // set to + String order = -1 + ""; if(trial.getRootcauseNode()!=null) { - order = trial.getRootcauseNode().getOrder(); + TraceNode trialRootCauseNode = ConcurrentTraceNode.getIniTraceNode(trial.getRootcauseNode()); + order = trial.getRootcauseNode().getOrder() + "," + trialRootCauseNode.getTrace().getThreadId(); } setCellValue(row, Header.FOUND_CAUSE, order); - order = -1; + order = -1 + ""; if(trial.getRootCauseFinder()!=null) { if(!trial.getRootCauseFinder().getRealRootCaseList().isEmpty()){ - order = trial.getRootCauseFinder().getRealRootCaseList().get(0).getRoot().getOrder(); + TraceNode root = trial.getRootCauseFinder().getRealRootCaseList().get(0).getRoot(); + root = ConcurrentTraceNode.getIniTraceNode(root); + order = root.getOrder() + "," + root.getTrace().getThreadId(); } } setCellValue(row, Header.GENERAL_CAUSE, order); @@ -153,6 +158,8 @@ private void fillRowInformation(Row row, EmpiricalTrial trial, String project, S setCellValue(row, Header.EXCEPTION, trial.getExceptionExplanation()); } setCellValue(row, Header.MULTI_THREAD, trial.isMultiThread()); + setCellValue(row, Header.IS_DEADLOCK, trial.isDeadLock()); + setCellValue(row, Header.IS_TIMEOUT, trial.isTimeout()); setCellValue(row, Header.BREAK_TO_BUG, trial.isBreakSlice()); setCellValue(row, Header.EXECTION_TIME, trial.getExecutionTime()); diff --git a/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java b/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java index 0bebfd09..6bfabdf0 100644 --- a/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java +++ b/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java @@ -4,8 +4,15 @@ import java.util.ArrayList; import java.util.List; +import org.eclipse.jdt.ui.actions.RemoveFromClasspathAction; + public class Defects4jProjectConfig extends ProjectConfig{ + private static final String TARGET_DIR = "target"; + private static final String DEFAULT_JAVA_DIR = "src:java"; + private static final String MAIN_JAVA_DIR = "src:main:java"; + private static final String DEFAULT_MAVEN_TEST = "src:test"; + private Defects4jProjectConfig(String srcTestFolder, String srcSourceFolder, String bytecodeTestFolder, String bytecodeSourceFolder, String buildFolder, String projectName, String bugID) { super(srcTestFolder, srcSourceFolder, bytecodeTestFolder, bytecodeSourceFolder, buildFolder, projectName, bugID); @@ -13,9 +20,9 @@ private Defects4jProjectConfig(String srcTestFolder, String srcSourceFolder, Str public String rootPath = ""+File.separator+"home"+File.separator+"linyun"+File.separator+"doc"+File.separator+"git_space"+File.separator+"defects4j"+File.separator+"framework"+File.separator+"bin"+File.separator+"defects4j"; - public static Defects4jProjectConfig getConfig(String projectName, String regressionID) { + public static ProjectConfig getConfig(String projectName, String regressionID) { int bugID = Integer.valueOf(regressionID); - Defects4jProjectConfig config = null; + ProjectConfig config = null; if(projectName.equals("Chart")) { config = new Defects4jProjectConfig("tests", "source", "build-tests", "build", "build", projectName, regressionID); } @@ -68,9 +75,40 @@ else if (projectName.equals("Time")) { else{ config = new Defects4jProjectConfig("src"+File.separator+"test"+File.separator+"java", "src"+File.separator+"main"+File.separator+"java", "build"+File.separator+"tests", "build"+File.separator+"classes", "build", projectName, regressionID); } + } else if (projectName.equals("Codec")) { + config = new MavenProjectConfig("src"+File.separator+"test", "src"+File.separator+"java", "target"+File.separator+"tests", "target"+File.separator+"classes", "target", projectName, regressionID); + } else if (projectName.equals("Collections")) { + config = generateMaventProjectConfig("src:test", "src:main:java", "target", "tests", projectName, regressionID); + } else if (projectName.equals("Compress")) { + config = generateMaventProjectConfig( + DEFAULT_MAVEN_TEST, MAIN_JAVA_DIR, TARGET_DIR, "test-classes", + projectName, regressionID); + } else if (projectName.equals("Csv")) { + config = generateMaventProjectConfig( + DEFAULT_MAVEN_TEST, MAIN_JAVA_DIR, TARGET_DIR, "test-classes", + projectName, regressionID); + } + + if (projectName.equals("simple_defects")) { + config = generateMaventProjectConfig(DEFAULT_MAVEN_TEST, MAIN_JAVA_DIR, TARGET_DIR, "test-classes", projectName, regressionID); } return config; } + private static String fromColonSeparatorString(String path) { + String[] dirs = path.split(":"); + return String.join(File.separator, dirs); + } + + private static MavenProjectConfig generateMaventProjectConfig(String testDir, String javaDir, String buildOutput, String testClasses, String projName, String projId) { + String testSrcDirString = fromColonSeparatorString(testDir); + String javaDirString = fromColonSeparatorString(javaDir); + return new MavenProjectConfig(testSrcDirString, + javaDirString, + buildOutput +File.separator + testClasses, + buildOutput + File.separator + "classes", + buildOutput, projName, projId); + } + } diff --git a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java new file mode 100644 index 00000000..651a23b3 --- /dev/null +++ b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java @@ -0,0 +1,190 @@ +package tregression.handler; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +import experiment.utils.report.ExperimentReportComparisonReporter; +import experiment.utils.report.rules.SimulatorComparisonRule; +import experiment.utils.report.rules.TextComparisonRule; +import microbat.Activator; +import microbat.handler.CancelThread; +import sav.common.core.utils.SingleTimer; +import tregression.empiricalstudy.EmpiricalTrial; +import tregression.empiricalstudy.ReadEmpiricalTrial; +import tregression.empiricalstudy.TrialGenerator; +import tregression.empiricalstudy.TrialGenerator0; +import tregression.empiricalstudy.TrialReader; +import tregression.empiricalstudy.TrialRecorder; +import tregression.empiricalstudy.config.ConfigFactory; +import tregression.empiricalstudy.config.Defects4jProjectConfig; +import tregression.empiricalstudy.config.ProjectConfig; +import tregression.empiricalstudy.training.DED; +import tregression.empiricalstudy.training.DeadEndData; +import tregression.preference.TregressionPreference; + +public class AllDefects4jConcHandler extends AbstractHandler { + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + Job job = new Job("Do evaluation") { + @Override + protected IStatus run(IProgressMonitor monitor) { + Thread.currentThread().setName("All defects 4j conc run"); + int skippedNum = 0; + int endNum = 500; + CancelThread cancelThread = new CancelThread(monitor, null); + cancelThread.start(); +// String[] projects = {"Chart", "Closure", "Lang", "Math", "Mockito", "Time"}; +// int[] bugNum = {26, 133, 65, 106, 38, 27}; + +// String fileName = "defects4j0.old.xlsx"; + String fileName = "benchmark" + File.separator + "ben.xlsx"; + Map map = new HashMap<>(); + try { + map = new TrialReader().readXLSX(fileName); + } catch (Exception e1) { + e1.printStackTrace(); + } + + String[] projects = {"simple_defects"}; + int[] bugNum = {1}; +// String[] projects = {"Pool"}; +// int[] bugNum = {6}; +// +// String[] projects = {"Lang"}; +// int[] bugNum = {65}; +// +// String[] projects = {"Time"}; +// int[] bugNum = {2}; + + String prefix = Activator.getDefault().getPreferenceStore().getString(TregressionPreference.REPO_PATH) + File.separator; + + int count = 0; + File defects4jFile = null; + try { + for(int i=0; i endNum) { + continue; + } + + if(!map.isEmpty()){ + ReadEmpiricalTrial tmp = new ReadEmpiricalTrial(); + tmp.setProject(projects[i]); + tmp.setBugID(String.valueOf(j)); + + ReadEmpiricalTrial t = map.get(tmp); + if(t==null){ + System.err.println(projects[i]+"-"+j+" is missing."); + continue; + } + +// String deadEndType = t.getDeadEndType(); +// if(deadEndType==null || !(deadEndType.equals("control") || deadEndType.equals("data"))){ +// continue; +// } + +// String exception = t.getException(); +// if(exception==null || !exception.contains("over long")){ +// continue; +// } + } + + System.out.println("***working on the " + j + "th bug of " + projects[i] + " project."); + + String buggyPath = prefix + projects[i] + File.separator + j + File.separator + "bug"; + String fixPath = prefix + projects[i] + File.separator + j + File.separator + "fix"; + + System.out.println("analyzing the " + j + "th bug in " + projects[i] + " project."); + + TrialGenerator0 generator0 = new TrialGenerator0(); + generator0.setCancelThread(cancelThread); + + ProjectConfig d4jConfig = ConfigFactory.createConfig(projects[i], i + "", buggyPath, fixPath); + List trials = generator0.generateTrialsConcurrent(buggyPath, fixPath, + false, false, false, 3, false, d4jConfig, null); +// List trials = generator0.findConcurrent(buggyPath, fixPath, +// false, false, false, 3, false, d4jConfig, null); + TrialRecorder recorder; + try { + recorder = new TrialRecorder(); + defects4jFile = recorder.export(trials, projects[i], j); + +// for(EmpiricalTrial t: trials){ +// +// if(!t.getDeadEndRecordList().isEmpty()){ +// Repository.clearCache(); +// DeadEndRecord record = t.getDeadEndRecordList().get(0); +//// DED datas = new TrainingDataTransfer().transfer(record, t.getBuggyTrace()); +// DED datas = record.getTransformedData(t.getBuggyTrace()); +// setTestCase(datas, t.getTestcase()); +// try { +//// new DeadEndReporter().export(datas.getAllData(), projects[i], Integer.valueOf(j)); +// +// if(!t.getRootCauseFinder().getCausalityGraph().getRoots().isEmpty()){ +// new DeadEndCSVWriter("_d4j", null).export(datas.getAllData(), projects[i], String.valueOf(j)); +// } +// } catch (NumberFormatException | IOException e) { +// e.printStackTrace(); +// } +// } +// } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } finally { + String oldDefects4jFile = Activator.getDefault().getPreferenceStore() + .getString(TregressionPreference.DEFECTS4J_FILE); + + if (defects4jFile != null && defects4jFile.exists() && oldDefects4jFile != null + && new File(oldDefects4jFile).exists()) { + Map> keys = new HashMap>(); + keys.put("data", Arrays.asList("project", "bug_ID")); + ExperimentReportComparisonReporter.reportChange("defects4j_compare.xlsx", oldDefects4jFile, defects4jFile.getAbsolutePath(), + Arrays.asList(new TextComparisonRule(null), new SimulatorComparisonRule()), keys); + } + } + cancelThread.stopMonitoring(); +// System.out.println("all the trials"); +// for(int j=0; j buggyTraces = execTraceReader.getAllTraces(); Trace fixTrace = execTraceReader.read(fixExec); + List correctTraces = execTraceReader.getAllTraces(); Regression regression = new Regression(buggyTrace, fixTrace, null); + regression.setBuggyAndCorrectTraces(buggyTraces, correctTraces); return regression; } diff --git a/tregression/src/main/tregression/handler/RunRecordingExperiment.java b/tregression/src/main/tregression/handler/RunRecordingExperiment.java new file mode 100644 index 00000000..6c556b3a --- /dev/null +++ b/tregression/src/main/tregression/handler/RunRecordingExperiment.java @@ -0,0 +1,278 @@ +package tregression.handler; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Scanner; + +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +import microbat.codeanalysis.runtime.InstrumentationExecutor; +import microbat.evaluation.junit.TestCaseAnalyzer; +import microbat.handler.CancelThread; +import microbat.instrumentation.instr.aggreplay.shared.ParseData; +import microbat.instrumentation.instr.aggreplay.shared.RecordingOutput; +import microbat.instrumentation.instr.aggreplay.shared.SharedDataParser; +import microbat.preference.AnalysisScopePreference; +import microbat.util.MicroBatUtil; +import microbat.util.Settings; +import sav.common.core.utils.FileUtils; +import sav.common.core.utils.SingleTimer; +import sav.strategies.dto.AppJavaClassPath; +import traceagent.report.excel.AbstractExcelWriter; +import traceagent.report.excel.ExcelHeader; + +/** + * Used to run benchmark for data on record log size + success rate + * at replaying bugs + */ +public class RunRecordingExperiment extends AbstractHandler { + + private CancelThread cancelThread; + IProgressMonitor monitor; + private String testCaseLoc = "C:\\Users\\Gabriel\\Desktop\\jacon_testcases.txt"; + RecordingReport report; + enum RecordHeaders implements ExcelHeader { + TEST_CASE, + EXECUTION_TIME, + ORIGINAL_MEMORY_SIZE, + MEMEORY_SIZE, + LOG_SIZE, + /** + * For error during the normal run. + */ + PROCESS_ERROR, + /** + * For error during shared memory detection. + */ + SHARED_MEM_DETEC_ERROR; + public String getTitle() { + return name(); + } + + public int getCellIdx() { + return ordinal(); + } + } + enum ErrorHeaders implements ExcelHeader { + + TEST_CASE, + EXCEPTION; + @Override + public String getTitle() { + return name(); + } + + @Override + public int getCellIdx() { + return ordinal(); + } + } + + class RecordingReport extends AbstractExcelWriter { + public RecordingReport(File file) throws Exception { + super(file); + } + + public void writeRow(String testCaseName, long executionTime, long originalMem, long memorySize, long logSize, String processError, + String sharedMemError) { + Sheet sheet = getSheet("data", RecordHeaders.values(), 0); + int rowNum = sheet.getLastRowNum() + 1; + Row row = sheet.createRow(rowNum); + addCell(row, RecordHeaders.TEST_CASE, testCaseName); + addCell(row, RecordHeaders.EXECUTION_TIME, executionTime); + addCell(row, RecordHeaders.ORIGINAL_MEMORY_SIZE, originalMem); + addCell(row, RecordHeaders.MEMEORY_SIZE, memorySize); + addCell(row, RecordHeaders.LOG_SIZE, logSize); + addCell(row, RecordHeaders.PROCESS_ERROR, processError); + } + + private void writeError(String testCaseName, Exception exception) { + Sheet sheet = getSheet("error", ErrorHeaders.values(), 0); + int rowNum = sheet.getLastRowNum() + 1; + Row row = sheet.createRow(rowNum); + addCell(row, ErrorHeaders.TEST_CASE, testCaseName); + StringWriter sw = new StringWriter(); + PrintWriter pWriter = new PrintWriter(sw); + exception.printStackTrace(pWriter); + addCell(row, ErrorHeaders.EXCEPTION, sw.toString()); + } + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + File testCasesFile = new File(testCaseLoc); + Scanner sc = null; + try { + report = new RecordingReport(new File("C:\\Users\\Gabriel\\Desktop\\defects4j_out\\output.xlsx")); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + sc = new Scanner(testCasesFile); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + List testCases = new LinkedList<>(); + while (sc.hasNext()) { + testCases.add(sc.nextLine()); + } + sc.close(); + Job runningJob = new Job("Recording experiment") { + + @Override + protected IStatus run(IProgressMonitor m) { + monitor = m; + for (String testCase : testCases) { + if (m.isCanceled()) break; + try { + runSingleTestCase(testCase); + } catch (Exception e) { + report.writeError(testCase, e); + } + } + try { + report.writeWorkbook(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return Status.OK_STATUS; + } + + }; + runningJob.schedule(); + return null; + } + + private void runSingleTestCase(String testCase) { + String temp = Settings.launchClass; + Settings.launchClass = testCase; + final AppJavaClassPath appClassPath = MicroBatUtil.constructClassPaths(); + List srcFolders = MicroBatUtil.getSourceFolders(Settings.projectName); + appClassPath.setSourceCodePath(appClassPath.getTestCodePath()); + for (String srcFolder : srcFolders) { + if (!srcFolder.equals(appClassPath.getTestCodePath())) { + appClassPath.getAdditionalSourceFolders().add(srcFolder); + } + } + executeAggrRecord(null, appClassPath); + + Settings.launchClass = temp; + } + + protected String generateTraceDir(AppJavaClassPath appPath) { + String traceFolder; + if (appPath.getOptionalTestClass() != null) { + traceFolder = FileUtils.getFilePath(MicroBatUtil.getTraceFolder(), + Settings.projectName, + appPath.getOptionalTestClass(), + appPath.getOptionalTestMethod()); + } else { + traceFolder = FileUtils.getFilePath(MicroBatUtil.getTraceFolder(), + Settings.projectName, + appPath.getLaunchClass()); + } + FileUtils.createFolder(traceFolder); + return traceFolder; + } + + + private Object executeAggrRecord(ExecutionEvent event, final AppJavaClassPath appJavaClassPath) { + long origMemSize = -1; + List includedClassNames = AnalysisScopePreference.getIncludedLibList(); + List excludedClassNames = AnalysisScopePreference.getExcludedLibList(); + String sharedMemError = ""; + String processMemError = ""; + InstrumentationExecutor executor = new InstrumentationExecutor(appJavaClassPath, + generateTraceDir(appJavaClassPath), "trace", includedClassNames, excludedClassNames); + cancelThread = new CancelThread(monitor, executor); + cancelThread.start(); + String fileName = null; + File dumpFile = null; + File concDumpFile = null; + // the absolute path to the dump file. + String concFileNameString = null; + if (Settings.concurrentDumpFile.isPresent()) { + concFileNameString = Settings.concurrentDumpFile.get(); + concDumpFile = new File(concFileNameString); + } + try { + dumpFile = File.createTempFile("temp", ".txt"); + if (concDumpFile == null) { + concDumpFile = File.createTempFile("concTemp", ".txt"); + Settings.concurrentDumpFile = Optional.of(concDumpFile.getPath()); + } + fileName = dumpFile.getPath(); + concFileNameString = concDumpFile.getPath(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + executor.runMemoryMeasureMent(fileName); + Scanner dumpFileScanner; + try { + dumpFileScanner = new Scanner(dumpFile); + if (dumpFileScanner.hasNext()) origMemSize = dumpFileScanner.nextLong(); + dumpFileScanner.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + CancelThread ctThread = new CancelThread(monitor, executor); + ctThread.start(); + sharedMemError = executor.runSharedVariable(fileName, Settings.stepLimit); + SingleTimer timer = SingleTimer.start("execute record"); + processMemError = executor.runRecordConc(fileName, concFileNameString, Settings.stepLimit); + ctThread.stopMonitoring(); + long logSize = concDumpFile.length(); + long timeTaken = timer.getExecutionTime(); + List data; + long memoryUsed = -1; + try { + data = new SharedDataParser().parse(new FileReader(concDumpFile)); + RecordingOutput output = new RecordingOutput().parse(data.get(0)); + + memoryUsed = output.memoryUsed; + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + report.writeRow(Settings.launchClass, timeTaken, origMemSize, memoryUsed, logSize, processMemError, sharedMemError); + cancelThread.stopMonitoring(); + return null; + } + + + +} diff --git a/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java b/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java new file mode 100644 index 00000000..81d34286 --- /dev/null +++ b/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java @@ -0,0 +1,122 @@ +package tregression.handler; + +import java.io.IOException; +import java.util.List; + +import org.apache.bcel.Repository; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +import microbat.Activator; +import microbat.model.trace.Trace; +import microbat.util.JavaUtil; +import traceagent.handler.PlayRegressionLocalizationHandlerConc; +import tregression.empiricalstudy.DeadEndCSVWriter; +import tregression.empiricalstudy.DeadEndRecord; +import tregression.empiricalstudy.EmpiricalTrial; +import tregression.empiricalstudy.TrialGenerator; +import tregression.empiricalstudy.TrialGenerator0; +import tregression.empiricalstudy.TrialRecorder; +import tregression.empiricalstudy.config.ConfigFactory; +import tregression.empiricalstudy.config.ProjectConfig; +import tregression.empiricalstudy.training.DED; +import tregression.empiricalstudy.training.DeadEndData; +import tregression.preference.TregressionPreference; + +public class SeparateVersionConcHandler extends AbstractHandler { + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + JavaUtil.sourceFile2CUMap.clear(); + + Job job = new Job("Do evaluation") { + @Override + protected IStatus run(IProgressMonitor monitor) { + + TrialGenerator0 generator0 = new TrialGenerator0(); + String projectPath = Activator.getDefault().getPreferenceStore().getString(TregressionPreference.PROJECT_NAME); + String bugID = Activator.getDefault().getPreferenceStore().getString(TregressionPreference.BUG_ID); + + String buggyPath = PathConfiguration.getBuggyPath(projectPath, bugID); + String fixPath = PathConfiguration.getCorrectPath(projectPath, bugID); + + String projectName = Activator.getDefault().getPreferenceStore().getString(TregressionPreference.PROJECT_NAME); + String id = Activator.getDefault().getPreferenceStore().getString(TregressionPreference.BUG_ID); + + String testcase = Activator.getDefault().getPreferenceStore().getString(TregressionPreference.TEST_CASE); + + System.out.println("working on the " + id + "th bug of " + projectName + " project."); + + ProjectConfig config = ConfigFactory.createConfig(projectName, id, buggyPath, fixPath); + + if(config == null) { + try { + throw new Exception("cannot parse the configuration of the project " + projectName + " with id " + id); + } catch (Exception e) { + e.printStackTrace(); + } + return Status.CANCEL_STATUS; + } + + List trials = generator0.generateTrialsConcurrent(buggyPath, fixPath, + false, false, false, 3, true, config, testcase); + + if(trials.size() != 0) { + PlayRegressionLocalizationHandlerConc.finder = trials.get(0).getRootCauseFinder(); + } + + System.out.println("all the trials"); + for(int i=0; i[] adj; + int[] pairU, pairV, dist; + + public int hopcroftKarp() { + pairU = new int[m + 1]; + pairV = new int[n + 1]; + dist = new int[m + 1]; + Arrays.fill(pairU, NIL); + Arrays.fill(pairV, NIL); + int result = 0; + while (bfs()) { + + for (int u = 1; u <= m; u++) + + if (pairU[u] == NIL && dfs(u)) + result++; + } + return result; + } + + boolean bfs() { + + Queue Q = new LinkedList<>(); + + for (int u = 1; u <= m; u++) { + if (pairU[u] == NIL) { + + dist[u] = 0; + Q.add(u); + } + + else + dist[u] = INF; + } + dist[NIL] = INF; + + while (!Q.isEmpty()) { + int u = Q.poll(); + if (dist[u] < dist[NIL]) { + for (int i : adj[u]) { + int v = i; + if (dist[pairV[v]] == INF) { + dist[pairV[v]] = dist[u] + 1; + Q.add(pairV[v]); + } + } + } + } + return (dist[NIL] != INF); + } + + boolean dfs(int u) { + if (u != NIL) { + for (int i : adj[u]) { + int v = i; + if (dist[pairV[v]] == dist[u] + 1) { + if (dfs(pairV[v]) == true) { + pairV[v] = u; + pairU[u] = v; + return true; + } + } + } + dist[u] = INF; + return false; + } + return true; + } + + // Constructor + @SuppressWarnings("unchecked") + public BipGraph(int m, int n) { + this.m = m; + this.n = n; + adj = new ArrayList[m + 1]; + Arrays.fill(adj, new ArrayList<>()); + } + + public void addEdge(int u, int v) { + adj[u].add(v); + } +} diff --git a/tregression/src/main/tregression/model/MCMF.java b/tregression/src/main/tregression/model/MCMF.java new file mode 100644 index 00000000..884f2e03 --- /dev/null +++ b/tregression/src/main/tregression/model/MCMF.java @@ -0,0 +1,175 @@ +package tregression.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import sav.common.core.Pair; + +/** + * MCMF implementation from + * https://www.geeksforgeeks.org/minimum-cost-maximum-flow-from-a-graph-using-bellman-ford-algorithm/ + */ +public class MCMF { + + // Stores the found edges + boolean found[]; + + // Stores the number of nodes + int N; + + // Stores the capacity + // of each edge + int cap[][]; + + int flow[][]; + + // Stores the cost per + // unit flow of each edge + int cost[][]; + + // Stores the distance from each node + // and picked edges for each node + int dad[], dist[], pi[]; + + static final int INF + = Integer.MAX_VALUE / 2 - 1; + + // Function to check if it is possible to + // have a flow from the src to sink + boolean search(int src, int sink) + { + + // Initialise found[] to false + Arrays.fill(found, false); + + // Initialise the dist[] to INF + Arrays.fill(dist, INF); + + // Distance from the source node + dist[src] = 0; + + // Iterate until src reaches N + while (src != N) { + + int best = N; + found[src] = true; + + for (int k = 0; k < N; k++) { + + // If already found + if (found[k]) + continue; + + // Evaluate while flow + // is still in supply + if (flow[k][src] != 0) { + + // Obtain the total value + int val + = dist[src] + pi[src] + - pi[k] - cost[k][src]; + + // If dist[k] is > minimum value + if (dist[k] > val) { + + // Update + dist[k] = val; + dad[k] = src; + } + } + + if (flow[src][k] < cap[src][k]) { + + int val = dist[src] + pi[src] + - pi[k] + cost[src][k]; + + // If dist[k] is > minimum value + if (dist[k] > val) { + + // Update + dist[k] = val; + dad[k] = src; + } + } + + if (dist[k] < dist[best]) + best = k; + } + + // Update src to best for + // next iteration + src = best; + } + + for (int k = 0; k < N; k++) + pi[k] + = Math.min(pi[k] + dist[k], + INF); + + // Return the value obtained at sink + return found[sink]; + } + + public List> getSTEdgeList(int start, int end, int start2, int end2) { + List> resultArrayList = new LinkedList<>(); + for (int i = start; i < end; ++i) { + for (int j = start2; j < end2; ++j) { + if (flow[i][j] > 0) { + resultArrayList.add(Pair.of(i, j)); + break; + } + } + } + return resultArrayList; + } + + // Function to obtain the maximum Flow + public int[] getMaxFlow(int cap[][], int cost[][], + int src, int sink) + { + + this.cap = cap; + this.cost = cost; + + N = cap.length; + found = new boolean[N]; + flow = new int[N][N]; + dist = new int[N + 1]; + dad = new int[N]; + pi = new int[N]; + + int totflow = 0, totcost = 0; + + // If a path exist from src to sink + while (search(src, sink)) { + + // Set the default amount + int amt = INF; + for (int x = sink; x != src; x = dad[x]) + + amt = Math.min(amt, + flow[x][dad[x]] != 0 + ? flow[x][dad[x]] + : cap[dad[x]][x] + - flow[dad[x]][x]); + + for (int x = sink; x != src; x = dad[x]) { + + if (flow[x][dad[x]] != 0) { + flow[x][dad[x]] -= amt; + totcost -= amt * cost[x][dad[x]]; + } + else { + flow[dad[x]][x] += amt; + totcost += amt * cost[dad[x]][x]; + } + } + totflow += amt; + } + + // Return pair total cost and sink + return new int[] { totflow, totcost }; + } +} diff --git a/tregression/src/main/tregression/model/PairList.java b/tregression/src/main/tregression/model/PairList.java index c921c817..cddecfe1 100644 --- a/tregression/src/main/tregression/model/PairList.java +++ b/tregression/src/main/tregression/model/PairList.java @@ -9,9 +9,20 @@ public class PairList { private List pairList = new ArrayList<>(); - private Map beforeNodeToPairMap = new HashMap<>(); - private Map afterNodeToPairMap = new HashMap<>(); - + + // map from before node thread + order -> trace node + private Map> beforeNodeToThreadPairMap = new HashMap<>(); + private Map> afterNodeToThreadPairMap = new HashMap<>(); + + private Map assertThreadExists(Map> map, long threadId) { + if (map.containsKey(threadId)) { + return map.get(threadId); + } + Map result = new HashMap<>(); + map.put(threadId, result); + return result; + } + public PairList(List pairList) { super(); this.pairList = pairList; @@ -20,10 +31,14 @@ public PairList(List pairList) { TraceNode afterNode = pair.getAfterNode(); if(beforeNode!=null){ + Map beforeNodeToPairMap = + assertThreadExists(beforeNodeToThreadPairMap, beforeNode.getTrace().getThreadId()); beforeNodeToPairMap.put(beforeNode.getOrder(), pair); } if(afterNode!=null){ + Map afterNodeToPairMap = + assertThreadExists(afterNodeToThreadPairMap, afterNode.getTrace().getThreadId()); afterNodeToPairMap.put(afterNode.getOrder(), pair); } } @@ -41,6 +56,10 @@ public void add(TraceNodePair pair){ this.pairList.add(pair); } + private TraceNodePair getFromThreadTraceNodePairMap(Map> map, TraceNode node) { + return map.getOrDefault(node.getTrace().getThreadId(), new HashMap<>()).get(node.getOrder()); + } + public TraceNodePair findByAfterNode(TraceNode node) { // for(TraceNodePair pair: pairList){ // if(pair.getAfterNode().equals(node)){ @@ -50,8 +69,7 @@ public TraceNodePair findByAfterNode(TraceNode node) { if(node==null){ return null; } - TraceNodePair pair = afterNodeToPairMap.get(node.getOrder()); - return pair; + return getFromThreadTraceNodePairMap(afterNodeToThreadPairMap, node); } public TraceNodePair findByBeforeNode(TraceNode node) { @@ -63,8 +81,7 @@ public TraceNodePair findByBeforeNode(TraceNode node) { if(node==null){ return null; } - TraceNodePair pair = beforeNodeToPairMap.get(node.getOrder()); - return pair; + return getFromThreadTraceNodePairMap(beforeNodeToThreadPairMap, node); } public int size(){ @@ -89,7 +106,8 @@ public boolean isPair(TraceNode beforeNode, TraceNode afterNode) { if(pair!=null) { TraceNode n = pair.getAfterNode(); if(n != null) { - return n.getOrder()==afterNode.getOrder(); + return n.getOrder()==afterNode.getOrder() + && n.getTrace().getThreadId() == afterNode.getTrace().getThreadId(); } } diff --git a/tregression/src/main/tregression/model/StepOperationTuple.java b/tregression/src/main/tregression/model/StepOperationTuple.java index 2fb80c40..8ec0de9f 100644 --- a/tregression/src/main/tregression/model/StepOperationTuple.java +++ b/tregression/src/main/tregression/model/StepOperationTuple.java @@ -1,5 +1,6 @@ package tregression.model; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.TraceNode; import microbat.model.value.VarValue; import microbat.recommendation.ChosenVariableOption; @@ -59,7 +60,9 @@ public String toString() { int order = node.getOrder(); int lineNumber = node.getBreakPoint().getLineNumber(); + String threadName = ConcurrentTraceNode.getIniTraceNode(node).getTrace().getThreadName(); buffer.append("order " + order + ", "); + buffer.append("threadName: " + threadName + ","); buffer.append("line " + lineNumber + ", "); ChosenVariableOption option = userFeedback.getOption(); @@ -69,14 +72,15 @@ public String toString() { } if(getReferenceNode() != null){ - buffer.append("reference node order " + getReferenceNode().getOrder()); + buffer.append("reference node order " + getReferenceNode().getOrder() + " reference thread name " + getReferenceNode().getTrace().getThreadName()); } return buffer.toString(); } public TraceNode getReferenceNode() { - return referenceNode; + TraceNode refNode = ConcurrentTraceNode.getIniTraceNode(referenceNode); + return refNode; } public void setReferenceNode(TraceNode referenceNode) { diff --git a/tregression/src/main/tregression/model/TregressionConcurrentContext.java b/tregression/src/main/tregression/model/TregressionConcurrentContext.java new file mode 100644 index 00000000..2539b52b --- /dev/null +++ b/tregression/src/main/tregression/model/TregressionConcurrentContext.java @@ -0,0 +1,208 @@ +package tregression.model; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import microbat.instrumentation.output.RunningInfo; +import microbat.model.trace.ConcurrentTrace; +import microbat.model.trace.ConcurrentTraceNode; +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import microbat.recommendation.DebugState; +import microbat.recommendation.UserFeedback; +import microbat.trace.Reader; +import microbat.trace.TraceReader; +import sav.common.core.utils.SingleTimer; +import sav.strategies.dto.AppJavaClassPath; +import tregression.SimulationFailException; +import tregression.empiricalstudy.ConcurrentSimulator; +import tregression.empiricalstudy.EmpiricalTrial; +import tregression.empiricalstudy.RegressionUtil; +import tregression.empiricalstudy.RootCauseFinder; +import tregression.empiricalstudy.TestCase; +import tregression.empiricalstudy.config.ProjectConfig; +import tregression.empiricalstudy.solutionpattern.PatternIdentifier; +import tregression.separatesnapshots.DiffMatcher; +import tregression.tracematch.ControlPathBasedTraceMatcher; +import tregression.util.ConcurrentTraceMatcher; + +public class TregressionConcurrentContext { + private AppJavaClassPath buggyAppJavaClassPath; + private AppJavaClassPath correctAppJavaClassPath; + private List buggyTraces; + private List correctTraces; + private ProjectConfig projectConfig; + private int numOfTrials = 0; + private long executionTime = -1; + /** + * The path to the buggy project. + */ + private String buggyPath; + /** + * The path to the fixed project. + */ + private String fixPath; + private TestCase testCase; + + private DiffMatcher diffMatcher = null; + private PairList pairList = null; + private Map threadIdMap = null; + private List basePairLists = null; + private SingleTimer singleTimer = null; + private TregressionConcurrentContext() { + + } + + private TregressionConcurrentContext(AppJavaClassPath buggyAppJavaClassPath, + AppJavaClassPath correctAppJavaClassPath) { + this.buggyAppJavaClassPath = buggyAppJavaClassPath; + this.correctAppJavaClassPath = correctAppJavaClassPath; + } + + public static TregressionConcurrentContext fromFile(String buggyFilePath, String correctFilePath, AppJavaClassPath appJavaClassPath) { + TregressionConcurrentContext result = new TregressionConcurrentContext(appJavaClassPath, + appJavaClassPath); + + return result; + } + + public static TregressionConcurrentContext fromReader(TraceReader buggyReader, TraceReader correctReader, + String buggyDumpFile, String correctDumpFile, ProjectConfig config, TestCase testCase) { + RunningInfo correctRun = correctReader.read(null, correctDumpFile); + RunningInfo buggyRun = buggyReader.read(null, buggyDumpFile); + TregressionConcurrentContext result = new TregressionConcurrentContext(); + result.buggyTraces = buggyRun.getTraceList(); + result.correctTraces = correctRun.getTraceList(); + result.testCase = testCase; + result.projectConfig = config; + return result; + } + + public EmpiricalTrial runTrial() { + ConcurrentSimulator concurrentSimulator = new ConcurrentSimulator(false, false, 3); + this.singleTimer = SingleTimer.start("run trial"); + SingleTimer matchTimer = SingleTimer.start("matching"); + generateCacheData(); + long matchTime = matchTimer.getExecutionTime(); + RootCauseFinder rootCauseFinder = createRootCauseFinder(); + concurrentSimulator.prepareConc(buggyTraces, correctTraces, pairList, threadIdMap, diffMatcher); + if (!rootCauseFinder.hasRealRootCause()) { + EmpiricalTrial result = EmpiricalTrial.createDumpTrial("Cannot find real root cause"); + StepOperationTuple tuple = new StepOperationTuple(concurrentSimulator.getObservedFault(), + new UserFeedback(UserFeedback.UNCLEAR), concurrentSimulator.getObservedFault(), DebugState.UNCLEAR); + result.getCheckList().add(tuple); + return result; + } + if (concurrentSimulator.getObservedFault() == null) { + return EmpiricalTrial.createDumpTrial("Cannot find observable fault"); + } + ConcurrentTrace buggyTrace = ConcurrentTrace.fromTimeStampOrder(buggyTraces); + ConcurrentTrace correctTrace = ConcurrentTrace.fromTimeStampOrder(correctTraces); + rootCauseFinder.checkRootCause( + concurrentSimulator.getObservedFault(), buggyTrace, correctTrace, pairList, diffMatcher); + TraceNode rootCause = rootCauseFinder.retrieveRootCause(pairList, diffMatcher, buggyTrace, correctTrace); + numOfTrials++; + if (rootCause==null) { + return handleMissingRootCause(10, rootCauseFinder); + } + return runSimulation(concurrentSimulator, buggyTrace, correctTrace, (int) matchTime, diffMatcher); + + } + + private EmpiricalTrial runSimulation( + ConcurrentSimulator concurrentSimulator, + ConcurrentTrace buggyTrace, + ConcurrentTrace correctTrace, + int matchTime, + DiffMatcher diffMatcher) { + try { + List trials = concurrentSimulator.detectMutatedBug(buggyTrace, correctTrace, diffMatcher, 0); + for (EmpiricalTrial t : trials) { + t.setTestcase(this.testCase.testClass + "#" + this.testCase.testMethod); + t.setTraceCollectionTime(buggyTrace.getConstructTime() + correctTrace.getConstructTime()); + t.setTraceMatchTime(matchTime); + t.setBuggyTrace(buggyTrace); + t.setFixedTrace(correctTrace); + t.setPairList(pairList); + t.setDiffMatcher(diffMatcher); + + PatternIdentifier identifier = new PatternIdentifier(); + identifier.identifyPattern(t); + } + + this.executionTime = this.singleTimer.getExecutionTime(); + EmpiricalTrial trial = trials.get(0); + return trial; + } catch (SimulationFailException e) { + + e.printStackTrace(); + return null; + } + + } + + /** + * Handles the case where no root cause can be found by looking through the + * libraries and adding new classes. + * @param maxTrials + * @return + */ + private EmpiricalTrial handleMissingRootCause(int maxTrials, RootCauseFinder rootCauseFinder) { + System.out.println("[Search Lib Class] Cannot find the root cause, I am searching for library classes..."); + + List buggySteps = rootCauseFinder.getStopStepsOnBuggyTrace(); + List correctSteps = rootCauseFinder.getStopStepsOnCorrectTrace(); + + List newIncludedClassNames = new ArrayList<>(); + + List convertedBuggySteps = ConcurrentTraceNode.convert(buggySteps); + List convertedConcurrentSteps = ConcurrentTraceNode.convert(correctSteps); + List convertedRegressionNodes = ConcurrentTraceNode.convert(rootCauseFinder.getRegressionNodeList()); + List convertedCorrectNodeList = ConcurrentTraceNode.convert(rootCauseFinder.getCorrectNodeList()); + + +// List newIncludedBuggyClassNames = RegressionUtil.identifyIncludedClassNames(convertedBuggySteps, buggyRS.getPrecheckInfo(), convertedRegressionNodes); +// List newIncludedCorrectClassNames = RegressionUtil.identifyIncludedClassNames(convertedConcurrentSteps, correctRs.getPrecheckInfo(), convertedCorrectNodeList); +// +// newIncludedClassNames.addAll(newIncludedBuggyClassNames); +// newIncludedClassNames.addAll(newIncludedCorrectClassNames); + boolean includedClassChanged = false; +// for(String name: newIncludedClassNames){ +// if(!includedClassNames.contains(name)){ +// includedClassNames.add(name); +// includedClassChanged = true; +// } +// } + return null; + + + } + + private RootCauseFinder createRootCauseFinder() { + RootCauseFinder result = new RootCauseFinder(); + result.setRootCauseBasedOnDefects4JConc(basePairLists, diffMatcher, buggyTraces, correctTraces); + return result; + } + + private void generateCacheData() { + if (diffMatcher == null || basePairLists == null || pairList == null || threadIdMap == null) { + diffMatcher = new DiffMatcher(projectConfig.srcSourceFolder, projectConfig.srcTestFolder, + buggyPath, fixPath); + diffMatcher.matchCode(); + ControlPathBasedTraceMatcher traceMatcher = new ControlPathBasedTraceMatcher(); + Map threadIdMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); + this.basePairLists = traceMatcher.matchConcurrentTraceNodePair(correctTraces, buggyTraces, diffMatcher, threadIdMap); + this.pairList = combinePairLists(basePairLists); + } + } + + private PairList combinePairLists(List basePairLists) { + LinkedList pairs = new LinkedList<>(); + for (PairList pList : basePairLists) { + pairs.addAll(pList.getPairList()); + } + return new PairList(pairs); + } +} diff --git a/tregression/src/main/tregression/model/TregressionTestCase.java b/tregression/src/main/tregression/model/TregressionTestCase.java new file mode 100644 index 00000000..1e4efc1d --- /dev/null +++ b/tregression/src/main/tregression/model/TregressionTestCase.java @@ -0,0 +1,31 @@ +package tregression.model; + +import tregression.empiricalstudy.config.ProjectConfig; + +public class TregressionTestCase { + private final ProjectConfig projectConfig; + private final String testClassName; + private final String testMethodName; + + public TregressionTestCase(final ProjectConfig pc, + final String testClassName, + final String testMethod) { + this.projectConfig = pc; + this.testClassName = testClassName; + this.testMethodName = testMethod; + } + + public ProjectConfig getProjectConfig() { + return projectConfig; + } + + public String getTestClassName() { + return testClassName; + } + + public String getTestMethodName() { + return testMethodName; + } + + +} diff --git a/tregression/src/main/tregression/preference/TregressionPreference.java b/tregression/src/main/tregression/preference/TregressionPreference.java index 7a42649d..4e83eeab 100644 --- a/tregression/src/main/tregression/preference/TregressionPreference.java +++ b/tregression/src/main/tregression/preference/TregressionPreference.java @@ -1,5 +1,7 @@ package tregression.preference; +import java.util.Optional; + import org.eclipse.core.runtime.preferences.ConfigurationScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.jface.preference.PreferencePage; @@ -35,6 +37,7 @@ public class TregressionPreference extends PreferencePage implements IWorkbenchP private String defaultBugID; private String defaultTestCase; private String defaultDefects4jFile; + private Optional traceLocation = Optional.empty(); // public static final String BUGGY_PATH = "buggy_path"; // public static final String CORRECT_PATH = "correct_path"; @@ -45,6 +48,12 @@ public class TregressionPreference extends PreferencePage implements IWorkbenchP public static final String TEST_CASE = "test_case"; public static final String DEFECTS4J_FILE = "defects4j_file"; + /** + * + */ + public static final String TRACE_LOCATION = "trace_location"; + + public TregressionPreference() { } diff --git a/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java b/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java new file mode 100644 index 00000000..3b8928f1 --- /dev/null +++ b/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java @@ -0,0 +1,124 @@ +package tregression.separatesnapshots; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import microbat.codeanalysis.runtime.InstrumentationExecutor; +import microbat.codeanalysis.runtime.PreCheckInformation; +import microbat.instrumentation.output.RunningInfo; +import microbat.instrumentation.output.StorableReader; +import microbat.instrumentation.precheck.PrecheckInfo; +import microbat.instrumentation.utils.MicrobatUtils; +import microbat.preference.MicrobatPreference; +import microbat.util.MicroBatUtil; +import microbat.util.Settings; +import sav.strategies.dto.AppJavaClassPath; +import tregression.empiricalstudy.TestCase; +import tregression.empiricalstudy.TrialGenerator0; +import tregression.empiricalstudy.config.ProjectConfig; + +/** + * Clas + * @author Gabau + * + */ +public class BuggyRnRTraceCollector extends BuggyTraceCollector { + + private int firstIter = -1; + private int secondIter = -1; + + public BuggyRnRTraceCollector(int limit) { + super(limit); + } + + @Override + protected RunningResult generateResult(String workingDir, TestCase tc, ProjectConfig config, + boolean isRunInTestCaseMode, boolean allowMultiThread, List includeLibs, List excludeLibs) { + + InstrumentationExecutor executor = generateExecutor(workingDir, tc, config, isRunInTestCaseMode, includeLibs, excludeLibs); + executor.setIsForceJunit3Or4(true); + try { + File precheckInfoFile = File.createTempFile("precheck", ".txt"); + File recording = File.createTempFile("var", ".txt"); + File concDumpFile = File.createTempFile("recording", ".txt"); + File outputFile = File.createTempFile("output", ".txt"); + String concDumpFileString = concDumpFile.getAbsolutePath(); + executor.runPrecheck(precheckInfoFile.getAbsolutePath(), Settings.stepLimit); + PreCheckInformation precheckInfo = executor.getPrecheckInfo(); + + if(precheckInfo.isOverLong()) { + System.out.println("The trace is over long!"); + RunningResult rs = new RunningResult(); + rs.setFailureType(TrialGenerator0.OVER_LONG); + return rs; + } + + executor.runSharedVariable(recording.getPath(), Settings.stepLimit); + for (int i = 0; i < limit; ++i) { + executor.runRecordConc(recording.getPath(), concDumpFile.getAbsolutePath(), Settings.stepLimit); + try { + StorableReader reader = new StorableReader(concDumpFile); + reader.read(); + String programMsgString = reader.getProgramMsg(); + // when it is a fail + if (!MicroBatUtil.checkTestResult(programMsgString)) { + firstIter = i + 1; + break; + } + } catch (Exception exception) { + // handle recording exceptions + System.out.println("Exception occured during record"); + throw new RuntimeException(exception); + } + } + RunningInfo resultInfo = null; + for (int i = 0; i < limit; ++i) { + resultInfo = executor.runReplayTracer(concDumpFileString, outputFile.getAbsolutePath(), Settings.stepLimit); + if (!MicroBatUtil.checkTestResult(resultInfo.getProgramMsg())) { + secondIter = i + 1; + break; + } + } + if (secondIter == -1) { + System.out.println("Failed to find failing test case"); + RunningResult rsResult = new RunningResult(); + rsResult.setFailureType(TrialGenerator0.UNDETERMINISTIC);; + return rsResult; + } + + if (resultInfo.getMainTrace() == null) { + System.out.println("Missing main trace"); + RunningResult rsResult = new RunningResult(); + rsResult.setFailureType(TrialGenerator0.INSUFFICIENT_TRACE); + return rsResult; + + } + +// if(!precheckInfo.getOverLongMethods().isEmpty()) { +// String method = precheckInfo.getOverLongMethods().get(0); +// System.out.println("Method " + method + " is over long after instrumentation!"); +// RunningResult rs = new RunningResult(); +// rs.setFailureType(TrialGenerator0.OVER_LONG_INSTRUMENTATION_METHOD); +// return rs; +// } + + updateTraceInfo(resultInfo); + + RunningResult result = new RunningResult(resultInfo.getMainTrace(), + null, null, precheckInfo, executor.getAppPath()); + result.setRunningInfo(resultInfo); + result.setRunningTrace(resultInfo.getMainTrace()); + return result; + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + + + +} + diff --git a/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java b/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java new file mode 100644 index 00000000..f7e945c8 --- /dev/null +++ b/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java @@ -0,0 +1,49 @@ +package tregression.separatesnapshots; + +import java.util.List; + +import tregression.empiricalstudy.TestCase; +import tregression.empiricalstudy.config.ProjectConfig; + +/** + * Class used to run non determistic traces by running them multiple times + * @author Gabau + * + */ +public class BuggyTraceCollector extends TraceCollector0 { + + /** + * The limit on the number of runs to get the bug. + */ + protected final int limit; + protected int numOfIter = 0; + + public BuggyTraceCollector(int limit) { + super(true); + isForceJunit3Or4 = true; + this.limit = limit; + // TODO Auto-generated constructor stub + } + + + protected RunningResult generateResult(String workingDir, TestCase tc, ProjectConfig config, boolean isRunInTestCaseMode, + boolean allowMultiThread, List includeLibs, List excludeLibs) { + RunningResult tmpResult = super.run(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); + for (int i = 0; i < limit; ++i) { + if (!tmpResult.hasPassedTest()) { + break; + } + numOfIter = i + 2; + tmpResult = super.run(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); + } + return tmpResult; + } + + @Override + public RunningResult run(String workingDir, TestCase tc, ProjectConfig config, boolean isRunInTestCaseMode, + boolean allowMultiThread, List includeLibs, List excludeLibs) { + return this.generateResult(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); + } + + +} diff --git a/tregression/src/main/tregression/separatesnapshots/RunningResult.java b/tregression/src/main/tregression/separatesnapshots/RunningResult.java index 9cbba69e..c3faa577 100644 --- a/tregression/src/main/tregression/separatesnapshots/RunningResult.java +++ b/tregression/src/main/tregression/separatesnapshots/RunningResult.java @@ -24,6 +24,13 @@ public class RunningResult { public RunningResult() { } + public boolean hasPassedTest() { + if (runningInfo == null) { + return false; + } + return runningInfo.hasPassedTest(); + } + public RunningResult(Trace runningTrace, List executedStatements, ExecutionStatementCollector checker, PreCheckInformation precheckInfo, AppJavaClassPath appClassPath) { diff --git a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java index 681761b1..3b3c18e5 100644 --- a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java +++ b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java @@ -1,6 +1,7 @@ package tregression.separatesnapshots; import java.util.List; +import java.util.concurrent.Executor; import microbat.codeanalysis.runtime.InstrumentationExecutor; import microbat.codeanalysis.runtime.PreCheckInformation; @@ -15,15 +16,28 @@ public class TraceCollector0 { private boolean isBuggy; - + protected boolean isForceJunit3Or4 = false; public TraceCollector0(boolean buggy) { this.isBuggy = buggy; } - public RunningResult run(String workingDir, TestCase tc, - ProjectConfig config, boolean isRunInTestCaseMode, boolean allowMultiThread, - List includeLibs, List excludeLibs){ + protected InstrumentationExecutor generateExecutor(String workingDir, TestCase tc, + ProjectConfig config, boolean isRunInTestCaseMode, List includeLibs, List excludeLibs) { + AppJavaClassPath appClassPath = AppClassPathInitializer.initialize(workingDir, tc, config); + if(!isRunInTestCaseMode) { + appClassPath.setLaunchClass(appClassPath.getOptionalTestClass()); + } + String traceDir = MicroBatUtil.generateTraceDir(config.projectName, config.regressionID); + String traceName = isBuggy ? "bug" : "fix"; + return new InstrumentationExecutor(appClassPath, + traceDir, traceName, includeLibs, excludeLibs); + + } + + + public static InstrumentationExecutor generateExecutor(String workingDir, TestCase tc, + ProjectConfig config, boolean isRunInTestCaseMode, List includeLibs, List excludeLibs, boolean isBuggy) { AppJavaClassPath appClassPath = AppClassPathInitializer.initialize(workingDir, tc, config); if(!isRunInTestCaseMode) { appClassPath.setLaunchClass(appClassPath.getOptionalTestClass()); @@ -31,17 +45,28 @@ public RunningResult run(String workingDir, TestCase tc, String traceDir = MicroBatUtil.generateTraceDir(config.projectName, config.regressionID); String traceName = isBuggy ? "bug" : "fix"; - InstrumentationExecutor exectuor = new InstrumentationExecutor(appClassPath, + return new InstrumentationExecutor(appClassPath, traceDir, traceName, includeLibs, excludeLibs); + } + + + + public RunningResult runInner(String workingDir, TestCase tc, + ProjectConfig config, boolean isRunInTestCaseMode, boolean mustBeMultiThread, + boolean allowMultiThread, + List includeLibs, List excludeLibs){ + + InstrumentationExecutor executor = generateExecutor(workingDir, tc, config, isRunInTestCaseMode, includeLibs, excludeLibs); + executor.setIsForceJunit3Or4(this.isForceJunit3Or4); RunningInfo info = null; try { - info = exectuor.run(); + info = executor.run(); } catch (StepLimitException e) { e.printStackTrace(); } - PreCheckInformation precheckInfo = exectuor.getPrecheckInfo(); + PreCheckInformation precheckInfo = executor.getPrecheckInfo(); System.out.println("There are " + precheckInfo.getStepNum() + " steps in this trace"); if(precheckInfo.isOverLong()) { System.out.println("The trace is over long!"); @@ -67,6 +92,7 @@ public RunningResult run(String workingDir, TestCase tc, boolean isMultiThread = precheckInfo.getThreadNum()!=1; + if(isMultiThread && !allowMultiThread) { System.out.println("It is multi-thread program!"); RunningResult rs = new RunningResult(); @@ -74,21 +100,47 @@ public RunningResult run(String workingDir, TestCase tc, return rs; } + if (info.getTraceList().size() == 0) { + RunningResult rs = new RunningResult(); + System.out.println("No trace"); + rs.setFailureType(TrialGenerator0.NO_TRACE); + return rs; + } + // if(!info.isExpectedStepsMet()){ // System.out.println("The expected steps are not met by normal run"); // RunningResult rs = new RunningResult(); // rs.setFailureType(TrialGenerator0.EXPECTED_STEP_NOT_MET); // return rs; // } + updateTraceInfo(info); + Trace mainTrace = info.getMainTrace(); - Trace trace = info.getMainTrace(); - trace.constructLoopParentRelation(); - trace.setSourceVersion(isBuggy); - - RunningResult rs = new RunningResult(trace, null, null, precheckInfo, appClassPath); - rs.setRunningTrace(trace); + RunningResult rs = new RunningResult(mainTrace, null, null, precheckInfo, executor.getAppPath()); + rs.setRunningTrace(mainTrace); rs.setRunningInfo(info); return rs; } + protected void updateTraceInfo(RunningInfo runningInfo) { + List traces = runningInfo.getTraceList(); + for (Trace trace : traces) { + trace.constructLoopParentRelation(); + trace.setSourceVersion(isBuggy); + } + } + + + public RunningResult runForceMultithreaded(String workingDir, TestCase tc, + ProjectConfig config, boolean isRunInTestCaseMode, + List includeLibs, List excludeLibs) { + return runInner(workingDir, tc, config, isRunInTestCaseMode, true, true, includeLibs, excludeLibs); + } + + public RunningResult run(String workingDir, TestCase tc, + ProjectConfig config, boolean isRunInTestCaseMode, boolean allowMultiThread, + List includeLibs, List excludeLibs){ + return runInner(workingDir, tc, config, isRunInTestCaseMode, false, allowMultiThread, includeLibs, excludeLibs); + } + } diff --git a/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java b/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java index 96f95e10..7d6d100a 100644 --- a/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java +++ b/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java @@ -3,8 +3,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import microbat.algorithm.graphdiff.GraphDiff; import microbat.algorithm.graphdiff.HierarchyGraphDiffer; @@ -16,6 +18,39 @@ import tregression.separatesnapshots.DiffMatcher; public class ControlPathBasedTraceMatcher{ + + + /** + * Matches trace nodes using match trace node pair. + * If a particular trace doesn't have a map from 1 to another, we assume an + * empty trace maps to it. + * @param trace1 + * @param trace2 + * @param diffMatcher + * @param threadIdMap Map from buggy trace id to + * @return + */ + public List matchConcurrentTraceNodePair(List trace1, List trace2, DiffMatcher diffMatcher, + Map threadIdMap) { + Map trace2Map = new HashMap<>(); + LinkedList resultLinkedList = new LinkedList<>(); + for (Trace trace : trace2) { + trace2Map.put(trace.getThreadId(), trace); + } + for (Trace trace: trace1) { + for (TraceNode traceNode : trace.getExecutionList()) { + if (traceNode.getBreakPoint().getFullJavaFilePath() == null) { + throw new RuntimeException("NO full java path"); + } + } + if (threadIdMap.containsKey(trace.getThreadId())) { + Long nextThreadId = threadIdMap.get(trace.getThreadId()); + Objects.requireNonNull(trace2Map.get(nextThreadId)); + resultLinkedList.add(matchTraceNodePair(trace, trace2Map.get(nextThreadId), diffMatcher)); + } + } + return resultLinkedList; + } public PairList matchTraceNodePair(Trace mutatedTrace, Trace correctTrace, DiffMatcher matcher) { diff --git a/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java new file mode 100644 index 00000000..f0127414 --- /dev/null +++ b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java @@ -0,0 +1,182 @@ +package tregression.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import microbat.instrumentation.model.id.ThreadId; +import microbat.model.BreakPoint; +import microbat.model.trace.Trace; +import sav.common.core.Pair; +import tregression.model.BipGraph; +import tregression.model.MCMF; +import tregression.separatesnapshots.DiffMatcher; + +public class ConcurrentTraceMatcher implements TraceMatcher { + + private DiffMatcher diffMatcher; + + public ConcurrentTraceMatcher(DiffMatcher diffMatcher) { + this.diffMatcher = diffMatcher; + } + + /** + * Matches the traces + * @param trace1 + * @param trace2 + * @return + */ + public Map matchTraces(List trace1, List trace2) { + Map resultMap = new HashMap<>(); + HashSet notMatchedT1 = new HashSet<>(); + HashSet notMatchedT2 = new HashSet<>(); + // trying matching without threadId + HashMap traceThreadIdHashMap = new HashMap(); + for (Trace trace: trace1) { + notMatchedT1.add(trace.getThreadId()); + if (trace.getInnerThreadId() == null) continue; + traceThreadIdHashMap.put(trace.getInnerThreadId(), trace.getThreadId()); + } + for (Trace trace: trace2) { +// if (false) { + if (trace.getInnerThreadId() != null && traceThreadIdHashMap.containsKey(trace.getInnerThreadId())) { + Long prevTrace = traceThreadIdHashMap.get(trace.getInnerThreadId()); + notMatchedT1.remove(prevTrace); + resultMap.put(prevTrace, trace.getThreadId()); + } else { + notMatchedT2.add(trace.getThreadId()); + } + } + // early return. + if (resultMap.size() == Math.min(trace1.size(), trace2.size())) { + return resultMap; + } + List filteredTrace1 = trace1.stream().filter(t1 -> notMatchedT1.contains(t1.getThreadId())).toList(); + List filteredTrace2 = trace2.stream().filter(t2 -> notMatchedT2.contains(t2.getThreadId())).toList(); + Map heuristicMatchedMap = heuristicMatcher(filteredTrace1, filteredTrace2); + resultMap.putAll(heuristicMatchedMap); + return resultMap; + } + + /** + * Constructs the similarity for each trace + * use mcm + * @param trace1 + * @param trace2 + * @return + */ + private Map heuristicMatcher(List traces1, List traces2) { + Map resultMap = new HashMap<>(); + MCMF mcmf = new MCMF(); + int s = traces1.size() + traces2.size() + 2; + int[][] cap = new int[s][s]; + int[][] cost = new int[s][s]; + initCapCostForMCMF(traces1, traces2, s, cap, cost); + + mcmf.getMaxFlow(cap, cost, s-2, s-1); + List> matchEdgeList = mcmf.getSTEdgeList(0, traces1.size(), traces1.size(), traces2.size() + traces1.size()); + + ArrayList tempTraces1 = new ArrayList<>(traces1); + ArrayList tempTraces2 = new ArrayList<>(traces2); + for (Pair pair : matchEdgeList) { + Trace t1 = tempTraces1.get(pair.first()); + Trace t2 = tempTraces2.get(pair.second() - traces1.size()); + resultMap.put(t1.getThreadId(), t2.getThreadId()); + } + return resultMap; + } + + /** + * Generates the capacity and costs for mcmf + * @param traces1 + * @param traces2 + * @param s + * @param cap + * @param cost + */ + private void initCapCostForMCMF(List traces1, List traces2, int s, int[][] cap, int[][] cost) { + for (int i = 0; i < traces1.size(); ++i) { + cap[s-2][i] = 1; + } + for (int i = traces1.size(); i < traces1.size() + traces2.size(); ++i) { + cap[i][s-1] = 1; + } + int max_trace = 0; + for (Trace trace: traces1) { + max_trace = Math.max(trace.size(), max_trace); + } + for (Trace trace: traces2) { + max_trace = Math.max(trace.size(), max_trace); + } + + int i = 0; + int m_weight = 0; + for (Trace trace : traces1) { + int j = traces1.size(); + for (Trace trace2: traces2) { +// int weight = computeWeight(trace, trace2); + int weight = computeWeight2(trace, trace2); + // use this weight to differentiate + // between matching small to superset and small to equal set + double score = weight / Math.max(Math.max(trace.size(), trace2.size()), 1); + int arbitraryMult = max_trace; + int k_weight = (int) (score * arbitraryMult); + if (weight > traces1.size() / 2) { + m_weight = Math.max(weight, k_weight); + cap[i][j] = 1; + cost[i][j] = weight; + } + j++; + } + i++; + } + + for (i = 0; i < traces1.size(); ++i) { + for (int j = traces1.size(); j < traces1.size() + traces2.size(); ++j) { + if (cap[i][j] == 0) continue; + cost[i][j] = m_weight - cost[i][j]; + } + } + } + + private int computeWeight2(Trace t1, Trace t2) { + int sameLined = 0; + int i = 1; + int j = 1; + while (i <= t1.size() && j <= t2.size()) { + BreakPoint bp1 = t1.getTraceNode(j).getBreakPoint(); + BreakPoint bp2 = t2.getTraceNode(j).getBreakPoint(); + if (diffMatcher.isMatch(bp1, bp2)) { + sameLined++; + i++; j++; + } else { + i++; + } + } + return sameLined; + } + + /** + * Should be larger for a larger similarity of the trace. + * Compute similarity using bipartite matching + * @param t1 + * @param t2 + * @return + */ + private int computeWeight(Trace t1, Trace t2) { + BipGraph bipGraph = new BipGraph(t1.size(), t2.size()); + int sameLines = 0; + for (int i = 1; i <= t1.size(); ++i) { + BreakPoint bp1 = t1.getTraceNode(i).getBreakPoint(); + for (int j = 1; j <= t2.size(); ++j) { + BreakPoint bp2 = t2.getTraceNode(j).getBreakPoint(); + if (diffMatcher.isMatch(bp1, bp2)) { + bipGraph.addEdge(i, j); + } + } + } + return bipGraph.hopcroftKarp(); + } +} diff --git a/tregression/src/main/tregression/util/ConcurrentTregressionRunner.java b/tregression/src/main/tregression/util/ConcurrentTregressionRunner.java new file mode 100644 index 00000000..8c1017bc --- /dev/null +++ b/tregression/src/main/tregression/util/ConcurrentTregressionRunner.java @@ -0,0 +1,33 @@ +package tregression.util; + +import tregression.model.TregressionTestCase; + +/* + * + */ +public class ConcurrentTregressionRunner implements Runnable { + private final TregressionTestCase testCase; + private String logText; + + + public ConcurrentTregressionRunner( + TregressionTestCase testCase) { + this.testCase = testCase; + } + + public void run() { + + } + + public void deleteLogFile() { + + } + + private void createLogFile() { + + } + + public void record() { + + } +} diff --git a/tregression/src/main/tregression/util/TraceMatcher.java b/tregression/src/main/tregression/util/TraceMatcher.java new file mode 100644 index 00000000..1b09a55e --- /dev/null +++ b/tregression/src/main/tregression/util/TraceMatcher.java @@ -0,0 +1,10 @@ +package tregression.util; + +import java.util.List; +import java.util.Map; + +import microbat.model.trace.Trace; + +public interface TraceMatcher { + public Map matchTraces(List trace1, List trace2); +} diff --git a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java new file mode 100644 index 00000000..0c8f7a5c --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java @@ -0,0 +1,151 @@ +package tregression.views; + +import java.io.File; +import java.util.Map; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +import microbat.model.BreakPoint; +import microbat.model.ClassLocation; +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import tregression.editors.CompareEditor; +import tregression.editors.CompareTextEditorInput; +import tregression.empiricalstudy.RootCauseFinder; +import tregression.model.TraceNodePair; +import tregression.separatesnapshots.DiffMatcher; +import tregression.separatesnapshots.diff.FilePairWithDiff; +import tregression.views.BuggyTraceView.CompareFileName; + +public class ConcurrentBuggyTraceView extends ConcurrentTregressionTraceView { + public static final String ID = "tregression.evalView.buggyConcTraceView"; + + @Override + protected Action createControlMendingAction() { + Action action = new Action() { + public void run() { + if (listViewer.getSelection().isEmpty()) { + return; + } + + if (listViewer.getSelection() instanceof IStructuredSelection) { + IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); + TraceNode node = (TraceNode) selection.getFirstElement(); + + ConcurrentCorrectTraceView correctTraceView = TregressionViews.getConcCorrectTraceView(); + ClassLocation correspondingLocation = diffMatcher.findCorrespondingLocation(node.getBreakPoint(), false); + TraceNode otherControlDom = new RootCauseFinder().findControlMendingNodeOnOtherTrace(node, pairList, + correctTraceView.getTrace(), false, correspondingLocation, diffMatcher); + + if (otherControlDom != null) { + correctTraceView.otherViewsBehavior(otherControlDom); + correctTraceView.jumpToNode(correctTraceView.getTrace(), otherControlDom.getOrder(), refreshProgramState); + } + + } + + } + + public String getText() { + return "control mend"; + } + }; + + return action; + } + + + class CompareFileName { + String buggyFileName; + String fixFileName; + + public CompareFileName(String buggyFileName, String fixFileName) { + super(); + this.buggyFileName = buggyFileName; + this.fixFileName = fixFileName; + } + + } + + private CompareFileName generateCompareFile(BreakPoint breakPoint, DiffMatcher matcher) { + + String fixPath = "null"; + String buggyPath = breakPoint.getFullJavaFilePath(); + + FilePairWithDiff fileDiff = diffMatcher.findDiffBySourceFile(breakPoint); + if (this.diffMatcher == null || fileDiff == null) { + String bugBase = diffMatcher.getBuggyPath(); + String content = buggyPath.substring(bugBase.length(), buggyPath.length()); + fixPath = diffMatcher.getFixPath() + content; + if(!new File(fixPath).exists()){ + fixPath = buggyPath; + } + } else { + fixPath = fileDiff.getTargetFile(); + } + + CompareFileName cfn = new CompareFileName(buggyPath, fixPath); + return cfn; + } + private void openInCompare(CompareTextEditorInput input, TraceNode node) { + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchWindow win = wb.getActiveWorkbenchWindow(); + IWorkbenchPage workBenchPage = win.getActivePage(); + + IEditorPart editPart = workBenchPage.findEditor(input); + if(editPart != null){ + workBenchPage.activate(editPart); + CompareEditor editor = (CompareEditor)editPart; + editor.highLight(node); + } + else{ + try { + workBenchPage.openEditor(input, CompareEditor.ID); + } catch (PartInitException e) { + e.printStackTrace(); + } + } + + } + + @Override + protected void markJavaEditor(TraceNode node) { + BreakPoint breakPoint = node.getBreakPoint(); + + CompareFileName cfn = generateCompareFile(breakPoint, diffMatcher); + + CompareTextEditorInput input = new CompareTextEditorInput(node, this.pairList, + cfn.buggyFileName, cfn.fixFileName, diffMatcher); + + openInCompare(input, node); + + } + @Override + public void otherViewsBehavior(TraceNode buggyNode) { + if (this.refreshProgramState) { + ConcurrentStepPropertyView stepPropertyView = TregressionViews.getConcStepPropertyView(); + TraceNodePair pair = pairList.findByBeforeNode(buggyNode); + buggyNode.toString(); + TraceNode correctNode = null; + if(pair != null){ + correctNode = pair.getAfterNode(); + if (correctNode != null) { + ConcurrentCorrectTraceView concurrentCorrectTraceView = TregressionViews.getConcCorrectTraceView(); + concurrentCorrectTraceView.jumpToNode(correctNode.getTrace(), correctNode.getOrder(), false); + } + } + + stepPropertyView.refreshConc(correctNode, buggyNode, diffMatcher, pairList); + } + + markJavaEditor(buggyNode); + } + +} diff --git a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java new file mode 100644 index 00000000..b701813c --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java @@ -0,0 +1,162 @@ +package tregression.views; + +import java.io.File; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +import microbat.model.BreakPoint; +import microbat.model.ClassLocation; +import microbat.model.trace.TraceNode; +import tregression.editors.CompareEditor; +import tregression.editors.CompareTextEditorInput; +import tregression.empiricalstudy.RootCauseFinder; +import tregression.model.PairList; +import tregression.model.TraceNodePair; +import tregression.separatesnapshots.DiffMatcher; +import tregression.separatesnapshots.diff.FilePairWithDiff; +import tregression.views.CorrectTraceView.CompareFileName; + +public class ConcurrentCorrectTraceView extends ConcurrentTregressionTraceView { + public static final String ID = "tregression.evalView.concurrentCorrectTraceView"; + + public ConcurrentCorrectTraceView() {} + + @Override + protected Action createControlMendingAction() { + Action action = new Action() { + public void run() { + if (listViewer.getSelection().isEmpty()) { + return; + } + + if (listViewer.getSelection() instanceof IStructuredSelection) { + IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); + TraceNode node = (TraceNode) selection.getFirstElement(); + + ConcurrentBuggyTraceView buggyTraceView = TregressionViews.getConcBuggyTraceView(); + ClassLocation correspondingLocation = diffMatcher.findCorrespondingLocation(node.getBreakPoint(), true); + TraceNode otherControlDom = new RootCauseFinder().findControlMendingNodeOnOtherTrace(node, pairList, + buggyTraceView.getTrace(), true, correspondingLocation, diffMatcher); + + if (otherControlDom != null) { + buggyTraceView.otherViewsBehavior(otherControlDom); + buggyTraceView.jumpToNode(buggyTraceView.getTrace(), otherControlDom.getOrder(), refreshProgramState); + } + + } + + } + + public String getText() { + return "control mend"; + } + }; + + return action; + } + + private void openInCompare(CompareTextEditorInput input, TraceNode node) { + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchWindow win = wb.getActiveWorkbenchWindow(); + IWorkbenchPage workBenchPage = win.getActivePage(); + + IEditorPart editPart = workBenchPage.findEditor(input); + if(editPart != null){ + workBenchPage.activate(editPart); + CompareEditor editor = (CompareEditor)editPart; + editor.highLight(node); + } + else{ + try { + workBenchPage.openEditor(input, CompareEditor.ID); + } catch (PartInitException e) { + e.printStackTrace(); + } + } + + } + + class CompareFileName { + String buggyFileName; + String fixFileName; + + public CompareFileName(String buggyFileName, String fixFileName) { + super(); + this.buggyFileName = buggyFileName; + this.fixFileName = fixFileName; + } + + } + + private CompareFileName generateCompareFile(BreakPoint breakPoint, DiffMatcher matcher) { + String fixPath = breakPoint.getFullJavaFilePath(); + String buggyPath = "null"; + + FilePairWithDiff fileDiff = getDiffMatcher().findDiffByTargetFile(breakPoint); + if (getDiffMatcher() == null || fileDiff == null) { + String fixBase = diffMatcher.getFixPath(); + String content = fixPath.substring(fixBase.length(), fixPath.length()); + buggyPath = diffMatcher.getBuggyPath() + content; + + if(!new File(buggyPath).exists()){ + buggyPath = fixPath; + } + + } else { + buggyPath = fileDiff.getSourceFile(); + } + + CompareFileName cfn = new CompareFileName(buggyPath, fixPath); + return cfn; + } + + @Override + protected void markJavaEditor(TraceNode node) { + BreakPoint breakPoint = node.getBreakPoint(); + + CompareFileName cfn = generateCompareFile(breakPoint, getDiffMatcher()); + + CompareTextEditorInput input = new CompareTextEditorInput(node, this.pairList, + cfn.buggyFileName, cfn.fixFileName, getDiffMatcher()); + + openInCompare(input, node); + + } + + @Override + public void otherViewsBehavior(TraceNode correctNode) { + if (this.refreshProgramState) { + ConcurrentStepPropertyView stepPropertyView = TregressionViews.getConcStepPropertyView(); + TraceNodePair pair = pairList.findByAfterNode(correctNode); + correctNode.toString(); + TraceNode buggyNode = null; + if(pair != null){ + buggyNode = pair.getBeforeNode(); + if (buggyNode != null) { + ConcurrentBuggyTraceView buggyTraceView = TregressionViews.getConcBuggyTraceView(); + buggyTraceView.jumpToNode(buggyNode.getTrace(), buggyNode.getOrder(), false); + } + } + + stepPropertyView.refreshConc(correctNode, buggyNode, diffMatcher, pairList); + } + + markJavaEditor(correctNode); + } + + public PairList getPairList() { + return pairList; + } + + + public DiffMatcher getDiffMatcher() { + return diffMatcher; + } +} diff --git a/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java b/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java new file mode 100644 index 00000000..7fabd4c6 --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java @@ -0,0 +1,693 @@ +package tregression.views; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ICheckStateProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.ITreeViewerListener; +import org.eclipse.jface.viewers.TreeExpansionEvent; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.PlatformUI; + +import microbat.algorithm.graphdiff.GraphDiff; +import microbat.model.BreakPointValue; +import microbat.model.UserInterestedVariables; +import microbat.model.trace.ConcurrentTrace; +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import microbat.model.value.ReferenceValue; +import microbat.model.value.VarValue; +import microbat.model.value.VirtualValue; +import microbat.model.variable.Variable; +import microbat.recommendation.ChosenVariableOption; +import microbat.recommendation.UserFeedback; +import microbat.util.JavaUtil; +import microbat.util.Settings; +import microbat.util.TempVariableInfo; +import microbat.views.ImageUI; +import sav.common.core.Pair; +import sav.strategies.dto.AppJavaClassPath; +import tregression.StepChangeType; + +public class ConcurrentStepDetailUI { + + public static final String RW = "rw"; + public static final String STATE = "state"; + + public UserInterestedVariables interestedVariables = new UserInterestedVariables(); + + private UserFeedback feedback = new UserFeedback(); + + class FeedbackSubmitListener implements MouseListener{ + public void mouseUp(MouseEvent e) {} + public void mouseDoubleClick(MouseEvent e) {} + + private void openChooseFeedbackDialog(){ + MessageBox box = new MessageBox(PlatformUI.getWorkbench() + .getDisplay().getActiveShell()); + box.setMessage("Please tell me whether this step is correct or not!"); + box.open(); + } + + public void mouseDown(MouseEvent e) { + if (feedback == null) { + openChooseFeedbackDialog(); + } + else { + + TraceNode suspiciousNode = null; + if(dataButton.getSelection()){ + Object[] objList = readVariableTreeViewer.getCheckedElements(); + if(objList.length!=0) { + Object obj = objList[0]; + if(obj instanceof VarValue) { + VarValue readVar = (VarValue)obj; + if (currentNode.getBound() != null) { + ConcurrentTrace trace = currentNode.getBound().getConcurrentTrace(); + suspiciousNode = trace.findDataDependency(currentNode, readVar); + + } + } + } + } + else if(controlButton.getSelection()){ + suspiciousNode = currentNode.getBound().getInvocationMethodOrDominator(); + } + + if(suspiciousNode != null){ + traceView.recordVisitedNode(currentNode); + jumpToNode(suspiciousNode.getTrace(), suspiciousNode); + } + } + } + + private void jumpToNode(Trace trace, TraceNode suspiciousNode) { + traceView.jumpToNode(trace, suspiciousNode.getOrder(), true); + } + } + + @SuppressWarnings("unchecked") + class RWVariableContentProvider implements ITreeContentProvider { + /** + * rw is true means read, and rw is false means write. + */ + boolean rw; + + public RWVariableContentProvider(boolean rw) { + this.rw = rw; + } + + @Override + public void dispose() { + + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof ArrayList) { + ArrayList elements = (ArrayList) inputElement; + return elements.toArray(new VarValue[0]); + } + + return null; + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof ReferenceValue) { + ReferenceValue refValue = (ReferenceValue)parentElement; + + if(refValue.getChildren()==null){ + return null; + } + + return refValue.getChildren().toArray(new VarValue[0]); + } + + return null; + } + + @Override + public Object getParent(Object element) { + return null; + } + + @Override + public boolean hasChildren(Object element) { + Object[] children = getChildren(element); + if (children == null || children.length == 0) { + return false; + } else { + return true; + } + } + + } + + class RWVarListener implements ICheckStateListener { + private String RWType; + + public RWVarListener(String RWType) { + this.RWType = RWType; + } + + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + Object obj = event.getElement(); + VarValue value = null; + + if (obj instanceof VarValue) { + Trace trace = traceView.getTrace(); + + value = (VarValue) obj; + String varID = value.getVarID(); + + if (!interestedVariables.contains(value)) { + interestedVariables.add(trace.getCheckTime(), value); + + ChosenVariableOption option = feedback.getOption(); + if (option == null) { + option = new ChosenVariableOption(null, null); + } + + if (this.RWType.equals(Variable.READ)) { + option.setReadVar(value); + } + if (this.RWType.equals(Variable.WRITTEN)) { + option.setWrittenVar(value); + } + feedback.setOption(option); + + TempVariableInfo.variableOption = option; + TempVariableInfo.line = currentNode.getLineNumber(); + String cuName = currentNode.getBreakPoint().getDeclaringCompilationUnitName(); + TempVariableInfo.cu = JavaUtil.findCompilationUnitInProject(cuName, traceView.getTrace().getAppJavaClassPath()); + } else { + interestedVariables.remove(value); + } + + setChecks(writtenVariableTreeViewer, RW); + setChecks(readVariableTreeViewer, RW); + //setChecks(stateTreeViewer, STATE); + + writtenVariableTreeViewer.refresh(); + readVariableTreeViewer.refresh(); + //stateTreeViewer.refresh(); + + } + + } + } + + class VariableCheckStateProvider implements ICheckStateProvider { + + @Override + public boolean isChecked(Object element) { + + VarValue value = null; + if (element instanceof VarValue) { + value = (VarValue) element; + } else if (element instanceof GraphDiff) { + value = (VarValue) ((GraphDiff) element).getChangedNode(); + } + + if (currentNode != null) { + if (interestedVariables.contains(value)) { + return true; + } + } + return false; + } + + @Override + public boolean isGrayed(Object element) { + return false; + } + + } + + class VariableContentProvider implements ITreeContentProvider { + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public Object[] getElements(Object inputElement) { + if (inputElement instanceof BreakPointValue) { + BreakPointValue value = (BreakPointValue) inputElement; + return value.getChildren().toArray(new VarValue[0]); + } else if (inputElement instanceof ReferenceValue) { + ReferenceValue value = (ReferenceValue) inputElement; + VarValue[] list = value.getChildren().toArray(new VarValue[0]); + if (list.length != 0) { + return list; + } else { + return null; + } + } + + return null; + } + + public Object[] getChildren(Object parentElement) { + return getElements(parentElement); + } + + public Object getParent(Object element) { + return null; + } + + public boolean hasChildren(Object element) { + if (element instanceof ReferenceValue) { + ReferenceValue rValue = (ReferenceValue) element; + List children = rValue.getChildren(); + return children != null && !children.isEmpty(); + } + return false; + } + + } + + class VariableLabelProvider implements ITableLabelProvider { + private StepChangeType changeType; + private boolean isOnBefore; + + public VariableLabelProvider(StepChangeType changeType, boolean isOnBefore) { + this.changeType = changeType; + this.isOnBefore = isOnBefore; + } + + public void addListener(ILabelProviderListener listener) { + } + + public void dispose() { + } + + public boolean isLabelProperty(Object element, String property) { + return false; + } + + public void removeListener(ILabelProviderListener listener) { + } + + public Image getColumnImage(Object element, int columnIndex) { + if (element instanceof VarValue && columnIndex==0) { + VarValue varValue = (VarValue) element; + if(changeType.getType()==StepChangeType.DAT) { + for(Pair pair: changeType.getWrongVariableList()) { + VarValue var = (this.isOnBefore) ? pair.first() : pair.second(); + if(var.getVarID().equals(varValue.getVarID())) { + return Settings.imageUI.getImage(ImageUI.QUESTION_MARK); + } + } + } + } + + return null; + } + + public String getColumnText(Object element, int columnIndex) { + if (element instanceof VarValue) { + VarValue varValue = (VarValue) element; + switch (columnIndex) { + case 0: + String type = varValue.getType(); + if (type.contains(".")) { + type = type.substring(type.lastIndexOf(".") + 1, type.length()); + } + return type; + case 1: + String name = varValue.getVarName(); + if (varValue instanceof VirtualValue) { + String methodName = name.substring(name.indexOf(":") + 1); + name = "return from " + methodName + "()"; + } + return name; + case 2: + String value = varValue.getStringValue(); + + return value; + case 3: + String id = varValue.getVarID(); + String aliasVarID = varValue.getAliasVarID(); + if(aliasVarID != null){ + return id + (" aliasID:" + aliasVarID); + } + return id; + } + } + + return null; + } + + } + + //private CheckboxTreeViewer stateTreeViewer; + private CheckboxTreeViewer writtenVariableTreeViewer; + private CheckboxTreeViewer readVariableTreeViewer; + + private ITreeViewerListener treeListener; + private ConcurrentTregressionTraceView traceView; + private boolean isOnBefore; + + public ConcurrentStepDetailUI(ConcurrentTregressionTraceView view, TraceNode node, boolean isOnBefore){ + this.traceView = view; + this.currentNode = node; + this.isOnBefore = isOnBefore; + } + + private void addListener() { + + treeListener = new ITreeViewerListener() { + + @Override + public void treeExpanded(TreeExpansionEvent event) { + + setChecks(readVariableTreeViewer, RW); + setChecks(writtenVariableTreeViewer, RW); + //setChecks(stateTreeViewer, STATE); + + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + readVariableTreeViewer.refresh(); + writtenVariableTreeViewer.refresh(); + //stateTreeViewer.refresh(); + } + }); + + } + + @Override + public void treeCollapsed(TreeExpansionEvent event) { + + } + }; + + this.readVariableTreeViewer.addTreeListener(treeListener); + this.writtenVariableTreeViewer.addTreeListener(treeListener); + //this.stateTreeViewer.addTreeListener(treeListener); + + this.writtenVariableTreeViewer.addCheckStateListener(new RWVarListener(Variable.WRITTEN)); + this.readVariableTreeViewer.addCheckStateListener(new RWVarListener(Variable.READ)); + //this.stateTreeViewer.addCheckStateListener(new RWVarListener(Variable.READ)); + + } + + private CheckboxTreeViewer createVarGroup(Composite variableForm, String groupName) { + Group varGroup = new Group(variableForm, SWT.NONE); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.minimumHeight = 100; + varGroup.setLayoutData(data); + + varGroup.setText(groupName); + varGroup.setLayout(new FillLayout()); + + Tree tree = new Tree(varGroup, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.CHECK); + tree.setHeaderVisible(true); + tree.setLinesVisible(true); + + TreeColumn typeColumn = new TreeColumn(tree, SWT.LEFT); + typeColumn.setAlignment(SWT.LEFT); + typeColumn.setText("Variable Type"); + typeColumn.setWidth(100); + + TreeColumn nameColumn = new TreeColumn(tree, SWT.LEFT); + nameColumn.setAlignment(SWT.LEFT); + nameColumn.setText("Variable Name"); + nameColumn.setWidth(100); + + TreeColumn valueColumn = new TreeColumn(tree, SWT.LEFT); + valueColumn.setAlignment(SWT.LEFT); + valueColumn.setText("Variable Value"); + valueColumn.setWidth(150); + + TreeColumn idColumn = new TreeColumn(tree, SWT.LEFT); + idColumn.setAlignment(SWT.LEFT); + idColumn.setText("ID"); + idColumn.setWidth(200); + + CheckboxTreeViewer viewer = new CheckboxTreeViewer(tree); + createContextMenu(viewer); + return viewer; + } + + /** + * Creates the context menu + * + * @param viewer + */ + protected void createContextMenu(final Viewer viewer) { + MenuManager contextMenu = new MenuManager("#ViewerMenu"); //$NON-NLS-1$ + contextMenu.setRemoveAllWhenShown(true); + contextMenu.addMenuListener(new IMenuListener() { + @Override + public void menuAboutToShow(IMenuManager mgr) { + fillContextMenu(mgr, viewer); + } + }); + + Menu menu = contextMenu.createContextMenu(viewer.getControl()); + viewer.getControl().setMenu(menu); + } + + /** + * Fill dynamic context menu + * + * @param contextMenu + */ + protected void fillContextMenu(IMenuManager contextMenu, final Viewer viewer) { + contextMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + + contextMenu.add(new Action("Search next step reading this variable") { + @Override + public void run() { + IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); + Object obj = selection.getFirstElement(); + if(obj instanceof VarValue){ + VarValue value = (VarValue)obj; + Trace trace = traceView.getTrace(); + List nodes = trace.findNextReadingTraceNodes(value, currentNode.getOrder()); + if(!nodes.isEmpty()){ + TraceNode n = nodes.get(0); + traceView.jumpToNode(trace, n.getOrder(), true); + } +// traceView.jumpToNode(expression, true); + } + } + }); + + contextMenu.add(new Action("Search previous step reading this variable") { + @Override + public void run() { + IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); + Object obj = selection.getFirstElement(); + if(obj instanceof VarValue){ + VarValue value = (VarValue)obj; + Trace trace = traceView.getTrace(); + List nodes = trace.findPrevReadingTraceNodes(value, currentNode.getOrder()); + if(!nodes.isEmpty()){ + TraceNode n = nodes.get(0); + traceView.jumpToNode(trace, n.getOrder(), true); + } + } + } + }); + + } + + public Composite createDetails(Composite panel) { + Composite comp = new Composite(panel, SWT.NONE); + + comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + comp.setLayout(new GridLayout(1, true)); + + createSlicingGroup(comp); + + SashForm sashForm = new SashForm(comp, SWT.VERTICAL); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + sashForm.setLayoutData(data); + + this.readVariableTreeViewer = createVarGroup(sashForm, "Read Variables: "); + this.writtenVariableTreeViewer = createVarGroup(sashForm, "Written Variables: "); + //this.stateTreeViewer = createVarGroup(comp, "States: "); + + sashForm.setWeights(new int[]{50, 50}); + + + + addListener(); + + return comp; + } + + private Button dataButton; + private Button controlButton; + + + + private void createSlicingGroup(Composite panel) { + Group slicingGroup = new Group(panel, SWT.NONE); + GridData data = new GridData(SWT.FILL, SWT.TOP, true, false); + data.minimumHeight = 35; + slicingGroup.setLayoutData(data); + + GridLayout gl = new GridLayout(3, true); + slicingGroup.setLayout(gl); + + dataButton = new Button(slicingGroup, SWT.RADIO); + dataButton.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false)); + dataButton.setText("data "); + + + controlButton = new Button(slicingGroup, SWT.RADIO); + controlButton.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false)); + controlButton.setText("control "); + + Button submitButton = new Button(slicingGroup, SWT.NONE); + submitButton.setText("Go"); + submitButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, true, false)); + FeedbackSubmitListener fListener = new FeedbackSubmitListener(); + submitButton.addMouseListener(fListener); + } + + private void createWrittenVariableContent(List writtenVariables, StepChangeType changeType) { + this.writtenVariableTreeViewer.setContentProvider(new RWVariableContentProvider(false)); + this.writtenVariableTreeViewer.setLabelProvider(new VariableLabelProvider(changeType, isOnBefore)); + this.writtenVariableTreeViewer.setInput(writtenVariables); + + setChecks(this.writtenVariableTreeViewer, RW); + + this.writtenVariableTreeViewer.refresh(true); + + } + + private void createReadVariableContect(List readVariables, StepChangeType changeType) { + this.readVariableTreeViewer.setContentProvider(new RWVariableContentProvider(true)); + this.readVariableTreeViewer.setLabelProvider(new VariableLabelProvider(changeType, isOnBefore)); + this.readVariableTreeViewer.setInput(readVariables); + + setChecks(this.readVariableTreeViewer, RW); + + this.readVariableTreeViewer.refresh(true); + } + +// private void createStateContent(BreakPointValue value){ +// this.stateTreeViewer.setContentProvider(new VariableContentProvider()); +// this.stateTreeViewer.setLabelProvider(new VariableLabelProvider()); +// this.stateTreeViewer.setInput(value); +// +// setChecks(this.stateTreeViewer, STATE); +// +// this.stateTreeViewer.refresh(true); +// } + + private void setChecks(CheckboxTreeViewer treeViewer, String type){ + Tree tree = treeViewer.getTree(); + for(TreeItem item: tree.getItems()){ + setChecks(item, type); + } + } + + private void setChecks(TreeItem item, String type){ + Object element = item.getData(); + if(element == null){ + return; + } + + VarValue ev = (VarValue)element; +// String varID = ev.getVarID(); + + if(interestedVariables.contains(ev)){ + item.setChecked(true); + } + else{ + item.setChecked(false); + } + + for(TreeItem childItem: item.getItems()){ + setChecks(childItem, type); + } + } + + private TraceNode currentNode; + + private void sortVars(List vars){ + List readVars = vars; + Collections.sort(readVars, new Comparator() { + @Override + public int compare(VarValue o1, VarValue o2) { + return o1.getVarName().compareTo(o2.getVarName()); + } + }); + } + + public void refresh(TraceNode node, StepChangeType changeType){ + this.currentNode = node; + + if(node != null){ + //BreakPointValue thisState = node.getProgramState(); + //createStateContent(thisState); + sortVars(node.getWrittenVariables()); + sortVars(node.getReadVariables()); + + createWrittenVariableContent(node.getWrittenVariables(), changeType); + createReadVariableContect(node.getReadVariables(), changeType); + } + else{ + //createStateContent(null); + createWrittenVariableContent(null, changeType); + createReadVariableContect(null, changeType); + } + + this.controlButton.setSelection(false); + this.dataButton.setSelection(false); + if(changeType.getType()==StepChangeType.CTL){ + this.controlButton.setSelection(true); + } + else if(changeType.getType()==StepChangeType.DAT){ + this.dataButton.setSelection(true); + } + + } + +} diff --git a/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java b/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java new file mode 100644 index 00000000..162fe97b --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java @@ -0,0 +1,107 @@ +package tregression.views; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; + +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import microbat.views.TraceView; +import tregression.StepChangeType; +import tregression.StepChangeTypeChecker; +import tregression.model.PairList; +import tregression.separatesnapshots.DiffMatcher; + +public class ConcurrentStepPropertyView extends ViewPart { + + public static final String ID = "tregression.view.concStepProperties"; + + private ConcurrentStepDetailUI buggyDetailUI; + private ConcurrentStepDetailUI correctDetailUI; + + public ConcurrentStepPropertyView() { + } + + @Override + public void createPartControl(Composite parent) { + GridLayout parentLayout = new GridLayout(1, true); + parent.setLayout(parentLayout); + + SashForm sashForm = new SashForm(parent, SWT.HORIZONTAL); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + sashForm.setLayoutData(data); + + createScrolledComposite(sashForm, TregressionViews.getConcBuggyTraceView()); + createScrolledComposite(sashForm, TregressionViews.getConcCorrectTraceView()); + + sashForm.setWeights(new int[]{50, 50}); + } + + private void createScrolledComposite(SashForm sashForm, ConcurrentTregressionTraceView view){ + ScrolledComposite panel = new ScrolledComposite(sashForm, SWT.H_SCROLL | SWT.V_SCROLL); + panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + panel.setExpandHorizontal(true); + panel.setExpandVertical(true); + + Composite comp = createPanel(panel, view); + panel.setContent(comp); +// panel.setAlwaysShowScrollBars(true); +// panel.setMinSize(comp.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + Point point = comp.computeSize(SWT.DEFAULT, SWT.DEFAULT); + panel.setMinHeight(point.y); + } + + private Composite createPanel(Composite panel, ConcurrentTregressionTraceView view) { + GridLayout layout = new GridLayout(); + layout.numColumns = 1; + panel.setLayout(layout); + + if(view instanceof ConcurrentBuggyTraceView){ + buggyDetailUI = new ConcurrentStepDetailUI(view, null, true); + return buggyDetailUI.createDetails(panel); + } + else if(view instanceof ConcurrentCorrectTraceView){ + correctDetailUI = new ConcurrentStepDetailUI(view, null, false); + return correctDetailUI.createDetails(panel); + } + + return null; + } + + public void refreshConc(TraceNode correctNode, TraceNode buggyNode, DiffMatcher diffMatcher, PairList pairList){ + + Trace buggyTrace = null; + if (buggyNode != null) { + buggyTrace = buggyNode.getTrace(); + } + Trace correctTrace = null; + if (correctNode != null) { + correctTrace = correctNode.getTrace(); + } + StepChangeTypeChecker checker = new StepChangeTypeChecker(buggyTrace, correctTrace); + + if(buggyDetailUI != null && buggyNode != null) { + StepChangeType changeType = checker.getType(buggyNode, true, pairList, diffMatcher); + buggyDetailUI.refresh(buggyNode, changeType); + } + + if(correctDetailUI != null && correctNode != null) { + StepChangeType changeType = checker.getType(correctNode, false, pairList, diffMatcher); + correctDetailUI.refresh(correctNode, changeType); + } + } + + + @Override + public void setFocus() { + + } + +} diff --git a/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java b/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java new file mode 100644 index 00000000..fc237638 --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java @@ -0,0 +1,83 @@ +package tregression.views; + +import java.util.Stack; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; + +import microbat.Activator; +import microbat.model.trace.TraceNode; +import microbat.views.ConcurrentTraceView; +import microbat.views.ImageUI; +import tregression.model.PairList; +import tregression.separatesnapshots.DiffMatcher; + +public abstract class ConcurrentTregressionTraceView extends ConcurrentTraceView { + protected PairList pairList; + protected DiffMatcher diffMatcher; + + public void setPairList(final PairList pairList) { + this.pairList = pairList; + } + + public void setDiffMatcher(final DiffMatcher diffMatcher) { + this.diffMatcher = diffMatcher; + } + + @Override + protected void appendMenuForTraceStep() { + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + @Override + public void menuAboutToShow(IMenuManager manager) { + Action forSearchAction = createForSearchAction(); + Action controlMendingAction = createControlMendingAction(); + menuMgr.add(forSearchAction); + menuMgr.add(controlMendingAction); + } + }); + + curTreeViewer.getTree().setMenu(menuMgr.createContextMenu(listViewer.getTree())); + } + + protected abstract Action createControlMendingAction(); + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + hookActionsOnToolBar(); + } + + private Stack visitedNodeStack = new Stack<>(); + + private void hookActionsOnToolBar() { + IActionBars actionBars = getViewSite().getActionBars(); + IToolBarManager toolBar = actionBars.getToolBarManager(); + + Action undoAction = new Action("Undo"){ + public void run(){ + if(!visitedNodeStack.isEmpty()) { + TraceNode node = visitedNodeStack.pop(); + jumpToNode(trace, node.getOrder(), true); + } + } + }; + undoAction.setImageDescriptor(Activator.getDefault().getImageRegistry().getDescriptor(ImageUI.UNDO_MARK)); + + + toolBar.add(undoAction); + + } + + public Stack getVisitedNodeStack() { + return visitedNodeStack; + } + + public void recordVisitedNode(TraceNode node) { + this.visitedNodeStack.push(node); + } +} diff --git a/tregression/src/main/tregression/views/ConcurrentVisualiser.java b/tregression/src/main/tregression/views/ConcurrentVisualiser.java new file mode 100644 index 00000000..7b8c1bd3 --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentVisualiser.java @@ -0,0 +1,68 @@ +package tregression.views; + +import java.util.List; +import java.util.Map; + +import org.eclipse.swt.widgets.Display; + +import microbat.model.trace.ConcurrentTrace; +import microbat.model.trace.Trace; +import tregression.model.PairList; +import tregression.separatesnapshots.DiffMatcher; + +/** + * Class representing the visualiser for concurrent programs + */ +public class ConcurrentVisualiser implements Runnable { + + private final List correctTraces; + private final List bugTraces; + private PairList pairList; + private DiffMatcher diffMatcher; + private ConcurrentTrace buggyTrace; + private ConcurrentTrace correctTrace; + /** + * Concurrent visualiser for showing concurrent programs in diff + * @param correctTraces + * @param bugTraces + * @param pairList + * @param diffMatcher + */ + public ConcurrentVisualiser(List correctTraces, List bugTraces, + ConcurrentTrace buggyTrace, ConcurrentTrace correctTrace, + PairList pairList, DiffMatcher diffMatcher) { + this.pairList = pairList; + this.diffMatcher = diffMatcher; + this.correctTraces = correctTraces; + this.bugTraces = bugTraces; + this.buggyTrace = buggyTrace; + this.correctTrace = correctTrace; + } + + public void visualise() { + Display.getDefault().asyncExec(this); + } + + /** + * Should only be called in the display call + */ + @Override + public void run() { + ConcurrentTregressionTraceView view = TregressionViews.getConcBuggyTraceView(); + view.setTraceList(bugTraces); + view.setDiffMatcher(diffMatcher); + view.setPairList(pairList); + view.updateData(); + view.setMainTrace(buggyTrace); + + + ConcurrentCorrectTraceView correctView = TregressionViews.getConcCorrectTraceView(); + correctView.setTraceList(correctTraces); + correctView.setPairList(this.pairList); + correctView.setDiffMatcher(diffMatcher); + correctView.updateData(); + correctView.setMainTrace(correctTrace); + + } + +} diff --git a/tregression/src/main/tregression/views/StepDetailUI.java b/tregression/src/main/tregression/views/StepDetailUI.java index 9c29da5c..ba8da41c 100644 --- a/tregression/src/main/tregression/views/StepDetailUI.java +++ b/tregression/src/main/tregression/views/StepDetailUI.java @@ -44,6 +44,7 @@ import microbat.algorithm.graphdiff.GraphDiff; import microbat.model.BreakPointValue; import microbat.model.UserInterestedVariables; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import microbat.model.value.ReferenceValue; @@ -95,7 +96,6 @@ public void mouseDown(MouseEvent e) { openChooseFeedbackDialog(); } else { - Trace trace = traceView.getTrace(); TraceNode suspiciousNode = null; if(dataButton.getSelection()){ @@ -104,7 +104,10 @@ public void mouseDown(MouseEvent e) { Object obj = objList[0]; if(obj instanceof VarValue) { VarValue readVar = (VarValue)obj; - suspiciousNode = trace.findDataDependency(currentNode, readVar); + ConcurrentTraceNode concurrentTraceNode = currentNode.getBound(); + if (concurrentTraceNode != null) { + suspiciousNode = concurrentTraceNode.getConcurrentTrace().findDataDependency(currentNode, readVar); + } } } } @@ -114,7 +117,7 @@ else if(controlButton.getSelection()){ if(suspiciousNode != null){ traceView.recordVisitedNode(currentNode); - jumpToNode(trace, suspiciousNode); + jumpToNode(suspiciousNode.getTrace(), suspiciousNode); } } } @@ -201,7 +204,7 @@ public void checkStateChanged(CheckStateChangedEvent event) { if (obj instanceof VarValue) { Trace trace = traceView.getTrace(); - + value = (VarValue) obj; String varID = value.getVarID(); diff --git a/tregression/src/main/tregression/views/StepPropertyView.java b/tregression/src/main/tregression/views/StepPropertyView.java index e56675b0..866dee49 100644 --- a/tregression/src/main/tregression/views/StepPropertyView.java +++ b/tregression/src/main/tregression/views/StepPropertyView.java @@ -109,6 +109,27 @@ public void refresh(TraceNode correctNode, TraceNode buggyNode, DiffMatcher diff } } + + public void refreshConc(TraceNode correctNode, TraceNode buggyNode, DiffMatcher diffMatcher, PairList pairList){ + if (buggyNode == null || correctNode == null) { + return; + } + Trace buggyTrace = buggyNode.getTrace(); + Trace correctTrace = correctNode.getTrace(); + StepChangeTypeChecker checker = new StepChangeTypeChecker(buggyTrace, correctTrace); + + if(buggyDetailUI != null && buggyNode != null){ + StepChangeType changeType = checker.getType(buggyNode, true, pairList, diffMatcher); + buggyDetailUI.refresh(buggyNode, changeType); + } + + if(correctDetailUI != null && correctNode != null){ + StepChangeType changeType = checker.getType(correctNode, false, pairList, diffMatcher); + correctDetailUI.refresh(correctNode, changeType); + } + } + + @Override public void setFocus() { diff --git a/tregression/src/main/tregression/views/TregressionViews.java b/tregression/src/main/tregression/views/TregressionViews.java index f7257d74..190f1627 100644 --- a/tregression/src/main/tregression/views/TregressionViews.java +++ b/tregression/src/main/tregression/views/TregressionViews.java @@ -17,6 +17,28 @@ public static CorrectTraceView getCorrectTraceView(){ return view; } + public static ConcurrentCorrectTraceView getConcCorrectTraceView() { + ConcurrentCorrectTraceView view = null; + try { + view = (ConcurrentCorrectTraceView) PlatformUI.getWorkbench(). + getActiveWorkbenchWindow().getActivePage().showView(ConcurrentCorrectTraceView.ID); + } catch (PartInitException e) { + e.printStackTrace(); + } + return view; + } + + public static ConcurrentBuggyTraceView getConcBuggyTraceView() { + ConcurrentBuggyTraceView view = null; + try { + view = (ConcurrentBuggyTraceView) PlatformUI.getWorkbench(). + getActiveWorkbenchWindow().getActivePage().showView(ConcurrentBuggyTraceView.ID); + } catch (PartInitException e) { + e.printStackTrace(); + } + return view; + } + public static BuggyTraceView getBuggyTraceView(){ BuggyTraceView view = null; try { @@ -40,4 +62,16 @@ public static StepPropertyView getStepPropertyView(){ return view; } + + public static ConcurrentStepPropertyView getConcStepPropertyView(){ + ConcurrentStepPropertyView view = null; + try { + view = (ConcurrentStepPropertyView)PlatformUI.getWorkbench(). + getActiveWorkbenchWindow().getActivePage().showView(ConcurrentStepPropertyView.ID); + } catch (PartInitException e) { + e.printStackTrace(); + } + + return view; + } }