From d0a271e13c65bfcbca1e0b6447d40125e7e8b440 Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Wed, 13 Mar 2024 14:05:23 +0800 Subject: [PATCH 01/22] Temporary changes --- .../handler/RunAllDefects4jHandler.java | 82 +++++++++++++++++-- .../handler/RunSingleTestcaseHandler.java | 3 +- .../empiricalstudy/Regression.java | 3 +- .../config/Defects4jProjectConfig.java | 38 ++++++++- .../handler/RegressionRetrieveHandler.java | 7 +- .../model/TregressionTestCase.java | 31 +++++++ .../util/ConcurrentTregressionRunner.java | 33 ++++++++ .../views/ConcurrentTregressionTraceView.java | 75 +++++++++++++++++ 8 files changed, 258 insertions(+), 14 deletions(-) create mode 100644 tregression/src/main/tregression/model/TregressionTestCase.java create mode 100644 tregression/src/main/tregression/util/ConcurrentTregressionRunner.java create mode 100644 tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java 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/tregression/empiricalstudy/Regression.java b/tregression/src/main/tregression/empiricalstudy/Regression.java index 018bc5bb..ff3ae392 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; @@ -53,7 +54,7 @@ public void setPairList(PairList pairList) { this.pairList = pairList; } - public void fillMissingInfo(Defects4jProjectConfig config, String buggyPath, String fixPath) { + public void fillMissingInfo(ProjectConfig 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)); } diff --git a/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java b/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java index 0bebfd09..54586429 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,36 @@ 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); } 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/RegressionRetrieveHandler.java b/tregression/src/main/tregression/handler/RegressionRetrieveHandler.java index ddf02e8b..fb783678 100644 --- a/tregression/src/main/tregression/handler/RegressionRetrieveHandler.java +++ b/tregression/src/main/tregression/handler/RegressionRetrieveHandler.java @@ -35,6 +35,7 @@ import tregression.empiricalstudy.TestCase; import tregression.empiricalstudy.TrialGenerator; import tregression.empiricalstudy.config.Defects4jProjectConfig; +import tregression.empiricalstudy.config.ProjectConfig; import tregression.empiricalstudy.solutionpattern.PatternIdentifier; import tregression.empiricalstudy.training.DED; import tregression.model.PairList; @@ -140,7 +141,7 @@ private Result parseResult(String projectName, String bugId) throws IOException String buggyPath = PathConfiguration.getBuggyPath(projectName, bugId); String fixPath = PathConfiguration.getCorrectPath(projectName, bugId); - Defects4jProjectConfig config = Defects4jProjectConfig.getConfig(projectName, bugId); + ProjectConfig config = Defects4jProjectConfig.getConfig(projectName, bugId); DiffMatcher diffMatcher = new DiffMatcher(config.srcSourceFolder, config.srcTestFolder, buggyPath, fixPath); @@ -185,7 +186,7 @@ private Result parseResult(String projectName, String bugId) throws IOException return new Result(buggyTrace, correctTrace, pairList, diffMatcher); } - private void fillingMissingInfo(String buggyPath, String fixPath, Defects4jProjectConfig config, + private void fillingMissingInfo(String buggyPath, String fixPath, ProjectConfig config, Regression regression) { for (TraceNode node : regression.getBuggyTrace().getExecutionList()) { BreakPoint point = node.getBreakPoint(); @@ -250,7 +251,7 @@ private EmpiricalTrial simulate(Trace buggyTrace, Trace correctTrace, PairList p return trial; } - private Regression retrieveRegression(Defects4jProjectConfig config, String buggyPath, String fixPath) { + private Regression retrieveRegression(ProjectConfig config, String buggyPath, String fixPath) { String projectName = config.projectName; String bugId = config.regressionID; ExecTraceFileReader execTraceReader = new ExecTraceFileReader(); 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/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/views/ConcurrentTregressionTraceView.java b/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java new file mode 100644 index 00000000..bea2dcb3 --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java @@ -0,0 +1,75 @@ +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; + + @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); + } +} From 3918327013f633d35dff7d4ef009879ada97af06 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Wed, 20 Mar 2024 00:57:52 +0800 Subject: [PATCH 02/22] Add initial trace matching over threads --- tregression/plugin.xml | 7 + .../empiricalstudy/TrialGenerator0.java | 26 ++- .../src/main/tregression/model/BipGraph.java | 100 ++++++++++ .../src/main/tregression/model/MCMF.java | 175 ++++++++++++++++++ .../separatesnapshots/TraceCollector0.java | 2 +- .../ControlPathBasedTraceMatcher.java | 28 +++ .../util/ConcurrentTraceMatcher.java | 161 ++++++++++++++++ .../main/tregression/util/TraceMatcher.java | 10 + .../views/ConcurrentBuggyTraceView.java | 47 +++++ .../views/ConcurrentVisualiser.java | 44 +++++ .../tregression/views/TregressionViews.java | 11 ++ 11 files changed, 606 insertions(+), 5 deletions(-) create mode 100644 tregression/src/main/tregression/model/BipGraph.java create mode 100644 tregression/src/main/tregression/model/MCMF.java create mode 100644 tregression/src/main/tregression/util/ConcurrentTraceMatcher.java create mode 100644 tregression/src/main/tregression/util/TraceMatcher.java create mode 100644 tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java create mode 100644 tregression/src/main/tregression/views/ConcurrentVisualiser.java diff --git a/tregression/plugin.xml b/tregression/plugin.xml index 0de0ed22..d90127f6 100644 --- a/tregression/plugin.xml +++ b/tregression/plugin.xml @@ -84,6 +84,13 @@ name="Step Properties" restorable="true"> + + diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 60baf437..83cd7d53 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -5,6 +5,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Scanner; import microbat.model.trace.Trace; @@ -27,6 +28,8 @@ 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 { @@ -44,6 +47,7 @@ public class TrialGenerator0 { private DiffMatcher cachedDiffMatcher; private PairList cachedPairList; + private List cachedPairLists; public static String getProblemType(int type) { switch (type) { @@ -186,9 +190,10 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean DiffMatcher diffMatcher = null; PairList pairList = null; - + + List basePairLists = null; int matchTime = -1; - if (cachedBuggyRS != null && cachedCorrectRS != null && isReuse) { + if (cachedBuggyRS != null && cachedCorrectRS != null && basePairLists != null && isReuse) { buggyRS = cachedBuggyRS; correctRs = cachedCorrectRS; @@ -209,7 +214,7 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean diffMatcher = cachedDiffMatcher; pairList = cachedPairList; - + basePairLists = cachedPairLists; EmpiricalTrial trial = simulateDebuggingWithCatchedObjects(buggyRS.getRunningTrace(), correctRs.getRunningTrace(), pairList, diffMatcher, requireVisualization, useSliceBreaker, enableRandom, breakLimit); @@ -242,6 +247,9 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean trial = EmpiricalTrial.createDumpTrial(getProblemType(correctRs.getRunningType())); return trial; } + + List buggyTraces = buggyRS.getRunningInfo().getTraceList(); + List correctTraces = correctRs.getRunningInfo().getTraceList(); if (buggyRS != null && correctRs != null) { cachedBuggyRS = buggyRS; @@ -259,7 +267,11 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean time2 = System.currentTimeMillis(); matchTime = (int) (time2 - time1); System.out.println("finish matching trace, taking " + matchTime + "ms"); - + + Map traceMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); + basePairLists = traceMatcher.matchConcurrentTraceNodePair(buggyTraces, correctTraces, diffMatcher, traceMap); + System.out.println("Finish matching concurrent trace"); + cachedPairLists = basePairLists; cachedDiffMatcher = diffMatcher; cachedPairList = pairList; } @@ -271,6 +283,12 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean Visualizer visualizer = new Visualizer(); visualizer.visualize(buggyTrace, correctTrace, pairList, diffMatcher); } + if (buggyTraces.size() > 1 && requireVisualization) { + // TODO(Gab): update the trace map + ConcurrentVisualiser vizConcurrentVisualiser = + new ConcurrentVisualiser(buggyTraces, correctTraces, null, diffMatcher); + vizConcurrentVisualiser.visualise(); + } RootCauseFinder rootcauseFinder = new RootCauseFinder(); rootcauseFinder.setRootCauseBasedOnDefects4J(pairList, diffMatcher, buggyTrace, correctTrace); diff --git a/tregression/src/main/tregression/model/BipGraph.java b/tregression/src/main/tregression/model/BipGraph.java new file mode 100644 index 00000000..2808cb75 --- /dev/null +++ b/tregression/src/main/tregression/model/BipGraph.java @@ -0,0 +1,100 @@ +package tregression.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * Implementation of hopcroft-karp from + * geeksforgeeks + * https://www.geeksforgeeks.org/hopcroft-karp-algorithm-for-maximum-matching-set-2-implementation/ + */ +public class BipGraph { + + private static final int NIL = 0; + private static final int INF = Integer.MAX_VALUE; + int m, n; + List[] 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/separatesnapshots/TraceCollector0.java b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java index 681761b1..752dbaa2 100644 --- a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java +++ b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java @@ -80,7 +80,7 @@ public RunningResult run(String workingDir, TestCase tc, // rs.setFailureType(TrialGenerator0.EXPECTED_STEP_NOT_MET); // return rs; // } - + List traces = info.getTraceList(); Trace trace = info.getMainTrace(); trace.constructLoopParentRelation(); trace.setSourceVersion(isBuggy); diff --git a/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java b/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java index 96f95e10..b63b4d49 100644 --- a/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java +++ b/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -16,6 +17,33 @@ 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) { + if (threadIdMap.containsKey(trace.getThreadId())) { + Long nextThreadId = threadIdMap.get(trace.getThreadId()); + 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..140f5d17 --- /dev/null +++ b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java @@ -0,0 +1,161 @@ +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<>(); + HashMap traceThreadIdHashMap = new HashMap(); + for (Trace trace: trace1) { + notMatchedT1.add(trace.getThreadId()); + traceThreadIdHashMap.put(trace.getInnerThreadId(), trace.getThreadId()); + } + for (Trace trace: trace2) { + if (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(), 0, traces2.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()); + 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); + // use this weight to differentiate + // between matching small to superset and small to equal set + double score = weight / Math.max(trace.size(), trace2.size()); + 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]; + } + } + } + + /** + * 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 = 0; i < t1.size(); ++i) { + BreakPoint bp1 = t1.getTraceNode(i).getBreakPoint(); + for (int j = 0; j < t2.size(); ++j) { + BreakPoint bp2 = t2.getTraceNode(i).getBreakPoint(); + if (diffMatcher.isMatch(bp1, bp2)) { + bipGraph.addEdge(i, j); + } + } + } + return bipGraph.hopcroftKarp(); + } +} 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..c0c94558 --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java @@ -0,0 +1,47 @@ +package tregression.views; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.viewers.IStructuredSelection; + +import microbat.model.ClassLocation; +import microbat.model.trace.TraceNode; +import tregression.empiricalstudy.RootCauseFinder; + +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(); + + CorrectTraceView correctTraceView = TregressionViews.getCorrectTraceView(); + 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; + } + +} diff --git a/tregression/src/main/tregression/views/ConcurrentVisualiser.java b/tregression/src/main/tregression/views/ConcurrentVisualiser.java new file mode 100644 index 00000000..e0c6b5aa --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentVisualiser.java @@ -0,0 +1,44 @@ +package tregression.views; + +import java.util.List; + +import org.eclipse.swt.widgets.Display; + +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 List pairLists; + private DiffMatcher diffMatcher; + + public ConcurrentVisualiser(List correctTraces, List bugTraces, + List pairList, DiffMatcher diffMatcher) { + this.pairLists = pairList; + this.diffMatcher = diffMatcher; + this.correctTraces = correctTraces; + this.bugTraces = bugTraces; + } + + 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.updateData(); + + } + +} diff --git a/tregression/src/main/tregression/views/TregressionViews.java b/tregression/src/main/tregression/views/TregressionViews.java index f7257d74..a7c863b6 100644 --- a/tregression/src/main/tregression/views/TregressionViews.java +++ b/tregression/src/main/tregression/views/TregressionViews.java @@ -17,6 +17,17 @@ public static CorrectTraceView getCorrectTraceView(){ 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 { From d834a9c3fcf8bfc65bf4873d52951333385ec057 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Thu, 21 Mar 2024 12:40:16 +0800 Subject: [PATCH 03/22] Attempt to map concurrent to trace for data dep resolution --- tregression/.classpath | 2 +- .../.settings/org.eclipse.jdt.core.prefs | 6 +- tregression/plugin.xml | 19 + .../empiricalstudy/ConcurrentSimulator.java | 129 +++++ .../ConcurrentTrialGenerator.java | 83 ++++ .../empiricalstudy/RootCauseFinder.java | 23 + .../tregression/empiricalstudy/Simulator.java | 21 +- .../empiricalstudy/TrialGenerator0.java | 249 +++++++++- .../handler/SeperateVersionConcHandler.java | 122 +++++ .../tregression/model/ConcurrentTrace.java | 442 ++++++++++++++++++ .../model/ConcurrentTraceNode.java | 305 ++++++++++++ .../views/ConcurrentCorrectTraceView.java | 178 +++++++ .../views/ConcurrentVisualiser.java | 4 + .../tregression/views/TregressionViews.java | 11 + 14 files changed, 1566 insertions(+), 28 deletions(-) create mode 100644 tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java create mode 100644 tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java create mode 100644 tregression/src/main/tregression/handler/SeperateVersionConcHandler.java create mode 100644 tregression/src/main/tregression/model/ConcurrentTrace.java create mode 100644 tregression/src/main/tregression/model/ConcurrentTraceNode.java create mode 100644 tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java 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 d90127f6..1289cfbf 100644 --- a/tregression/plugin.xml +++ b/tregression/plugin.xml @@ -53,6 +53,11 @@ id="traceagent.command.runSingleDefects4jBugs" name="Run Single Defect4j Bug"> + + @@ -87,10 +92,19 @@ + + @@ -146,6 +160,11 @@ label="Retrieve All Defect4j Regressions" style="push"> + + diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java new file mode 100644 index 00000000..fe8ccf4c --- /dev/null +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -0,0 +1,129 @@ +package tregression.empiricalstudy; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import tregression.SimulationFailException; +import tregression.StepChangeTypeChecker; +import tregression.model.ConcurrentTrace; +import tregression.model.PairList; +import tregression.model.StepOperationTuple; +import tregression.separatesnapshots.DiffMatcher; + +/** + * Class containing logic for running erase + * on concurrent programs. + */ +public class ConcurrentSimulator extends Simulator { + + public ConcurrentSimulator(boolean useSlicerBreaker, boolean enableRandom, int breakerTrialLimit) { + super(useSlicerBreaker, enableRandom, breakerTrialLimit); + } + + public void prepareConc(List buggyTraces, + List correctTraces, + PairList combinedPairList, + Map threadIdMap, + DiffMatcher matcher) { + Map correctTraceMap = new HashMap<>(); + 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, Trace buggyTrace, Trace correctTrace, + PairList pairList, DiffMatcher matcher, RootCauseFinder rootCauseFinder) { + + StepChangeTypeChecker typeChecker = new StepChangeTypeChecker(buggyTrace, correctTrace); + List trials = new ArrayList<>(); + TraceNode currentNode = observedFaultNode; + + EmpiricalTrial trial = workSingleTrial(buggyTrace, correctTrace, pairList, matcher, + rootCauseFinder, typeChecker, currentNode); + trials.add(trial); + + return trials; + } + + 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; + } + + 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.checkRootCause(observedFault, buggyTrace, 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, buggyTrace, 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/ConcurrentTrialGenerator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java new file mode 100644 index 00000000..19b4bb88 --- /dev/null +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java @@ -0,0 +1,83 @@ +package tregression.empiricalstudy; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import microbat.model.trace.Trace; +import microbat.preference.AnalysisScopePreference; +import microbat.util.Settings; +import tregression.empiricalstudy.config.ProjectConfig; +import tregression.model.PairList; +import tregression.model.TraceNodePair; +import tregression.separatesnapshots.DiffMatcher; +import tregression.separatesnapshots.RunningResult; +import tregression.separatesnapshots.TraceCollector; +import tregression.separatesnapshots.TraceCollector0; +import tregression.tracematch.ControlPathBasedTraceMatcher; +import tregression.util.ConcurrentTraceMatcher; +import tregression.views.ConcurrentVisualiser; + +/** + * Trial generator used for concurrent programs. + * Used to perform tregression on concurrent programs + */ +public class ConcurrentTrialGenerator { + + protected EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, + TestCase tc, ProjectConfig config, boolean isRunInTestMode, + boolean useSliceBreaker, boolean enableRandom, int breakLimit) { + TraceCollector0 buggyCollector = new TraceCollector0(true); + TraceCollector0 correctCollector0 = new TraceCollector0(false); + RunningResult buggyRsResult = null; + RunningResult correctRs = null; + + DiffMatcher diffMatcher = null; + List pairLists = null; + + int trialLimit = 10; + int trialNum = 0; + boolean isDataFlowComplete = false; + EmpiricalTrial trial = null; + List includedClassNames = AnalysisScopePreference.getIncludedLibList(); + List excludedClassNames = AnalysisScopePreference.getExcludedLibList(); + + List buggyTraces = buggyRsResult.getRunningInfo().getTraceList(); + List correctTraces = correctRs.getRunningInfo().getTraceList(); + diffMatcher = new DiffMatcher(config.srcSourceFolder, config.srcTestFolder, buggyPath, fixPath); + diffMatcher.matchCode(); + + ControlPathBasedTraceMatcher traceMatcher = new ControlPathBasedTraceMatcher(); + + while (!isDataFlowComplete && trialNum < trialLimit) { + trialNum++; + Settings.compilationUnitMap.clear(); + Settings.iCompilationUnitMap.clear(); + + buggyRsResult = buggyCollector.run(buggyPath, tc, config, isRunInTestMode, true, + includedClassNames, excludedClassNames); + correctRs = correctCollector0.run(fixPath, tc, config, isRunInTestMode, true, includedClassNames, excludedClassNames); + + ConcurrentVisualiser vizConcurrentVisualiser = + new ConcurrentVisualiser(buggyTraces, correctTraces, pairLists, diffMatcher); + vizConcurrentVisualiser.visualise(); + + Map traceMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); + pairLists = traceMatcher.matchConcurrentTraceNodePair(buggyTraces, correctTraces, diffMatcher, traceMap); + List tnPair = new LinkedList<>(); + + for (PairList pairList : pairLists) { + tnPair.addAll(pairList.getPairList()); + } + PairList basePairList = new PairList(tnPair); + + + RootCauseFinder rootCauseFinder = new RootCauseFinder(); + rootCauseFinder.setRootCauseBasedOnDefects4JConc(pairLists, diffMatcher, buggyTraces, correctTraces); + ConcurrentSimulator simulator = new ConcurrentSimulator(useSliceBreaker, enableRandom, breakLimit); + simulator.prepareConc(buggyTraces, correctTraces, basePairList, traceMap, diffMatcher); + } + + return null; + } +} diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java index 84303541..327852cf 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java @@ -123,6 +123,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--) { diff --git a/tregression/src/main/tregression/empiricalstudy/Simulator.java b/tregression/src/main/tregression/empiricalstudy/Simulator.java index 23e5f8ac..33391dcb 100644 --- a/tregression/src/main/tregression/empiricalstudy/Simulator.java +++ b/tregression/src/main/tregression/empiricalstudy/Simulator.java @@ -2,7 +2,9 @@ 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; @@ -19,6 +21,8 @@ import tregression.empiricalstudy.recommendation.BreakerRecommender; import tregression.empiricalstudy.training.DED; import tregression.empiricalstudy.training.TrainingDataTransfer; +import tregression.model.ConcurrentTrace; +import tregression.model.ConcurrentTraceNode; import tregression.model.PairList; import tregression.model.StepOperationTuple; import tregression.model.TraceNodePair; @@ -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,7 +173,7 @@ 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; @@ -177,7 +181,7 @@ public void prepare(Trace buggyTrace, Trace correctTrace, PairList pairList, Dif TraceNode initialStep = buggyTrace.getLatestNode(); TraceNode lastObservableFault = findObservedFault(initialStep, buggyTrace, correctTrace); - if(lastObservableFault!=null){ + if(lastObservableFault!=null) { observedFaultList.add(lastObservableFault); StepChangeTypeChecker checker = new StepChangeTypeChecker(buggyTrace, correctTrace); @@ -189,8 +193,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 +237,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 +298,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 +450,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, diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 83cd7d53..1bdc88cb 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -21,6 +21,7 @@ import tregression.empiricalstudy.config.ProjectConfig; import tregression.empiricalstudy.solutionpattern.PatternIdentifier; import tregression.io.RegressionRecorder; +import tregression.model.ConcurrentTrace; import tregression.model.PairList; import tregression.model.StepOperationTuple; import tregression.separatesnapshots.AppClassPathInitializer; @@ -70,6 +71,46 @@ public static String getProblemType(int type) { } return "I don't know"; } + + + public List generateTrialsConcurrent(String buggyPath, String fixPath, boolean isReuse, boolean useSliceBreaker, + boolean enableRandom, int breakLimit, boolean requireVisualization, ProjectConfig config, String testcase) { + SingleTimer timer = SingleTimer.start("generateTrial"); + List tcList; + EmpiricalTrial trial = null; + TestCase workingTC = null; + try { + tcList = retrieveD4jFailingTestCase(buggyPath); + + if(testcase!=null){ + tcList = filterSpecificTestCase(testcase, tcList); + } + + for (TestCase tc : tcList) { + System.out.println("#####working on test case " + tc.testClass + "#" + tc.testMethod); + workingTC = tc; + + trial = analyzeConcurrentTestCase(buggyPath, fixPath, isReuse, + tc, config, requireVisualization, true, useSliceBreaker, enableRandom, breakLimit); + if(!trial.isDump()){ + break; + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + + if (trial == null) { + trial = EmpiricalTrial.createDumpTrial("runtime exception occurs"); + trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); + } + trial.setExecutionTime(timer.getExecutionTime()); + List list = new ArrayList<>(); + list.add(trial); + return list; + } + public List generateTrials(String buggyPath, String fixPath, boolean isReuse, boolean useSliceBreaker, boolean enableRandom, int breakLimit, boolean requireVisualization, @@ -92,7 +133,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; } } @@ -177,7 +218,7 @@ private void generateMainMethod(String workingPath, TestCase tc, Defects4jProjec System.currentTimeMillis(); } - private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean isReuse, boolean allowMultiThread, + 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 TraceCollector0(true); @@ -192,8 +233,196 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean 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(); + + Map threadIdMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); + 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(); + + ControlPathBasedTraceMatcher traceMatcher = new ControlPathBasedTraceMatcher(); + pairList = traceMatcher.matchTraceNodePair(buggyRS.getRunningTrace(), correctRs.getRunningTrace(), + diffMatcher); + basePairLists = traceMatcher.matchConcurrentTraceNodePair(buggyTraces, correctTraces, diffMatcher, threadIdMap); + + 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; + } + + if (requireVisualization) { + ConcurrentVisualiser visualizer = new ConcurrentVisualiser(correctTraces, buggyTraces, basePairLists, 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(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; + } + + ConcurrentTrace buggyTrace = ConcurrentTrace.fromTimeStampOrder(buggyTraces); + ConcurrentTrace correctTrace = ConcurrentTrace.fromTimeStampOrder(correctTraces); + rootcauseFinder.checkRootCause(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 newIncludedBuggyClassNames = RegressionUtil.identifyIncludedClassNames(buggySteps, buggyRS.getPrecheckInfo(), rootcauseFinder.getRegressionNodeList()); + List newIncludedCorrectClassNames = RegressionUtil.identifyIncludedClassNames(correctSteps, correctRs.getPrecheckInfo(), rootcauseFinder.getCorrectNodeList()); + 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); + + 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 { + TraceCollector0 buggyCollector = new TraceCollector0(true); + TraceCollector0 correctCollector = new TraceCollector0(false); + long time1 = 0; + long time2 = 0; + + RunningResult buggyRS = null; + RunningResult correctRs = null; + + DiffMatcher diffMatcher = null; + PairList pairList = null; + int matchTime = -1; - if (cachedBuggyRS != null && cachedCorrectRS != null && basePairLists != null && isReuse) { + if (cachedBuggyRS != null && cachedCorrectRS != null && cachedPairList != null && isReuse) { buggyRS = cachedBuggyRS; correctRs = cachedCorrectRS; @@ -214,7 +443,6 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean diffMatcher = cachedDiffMatcher; pairList = cachedPairList; - basePairLists = cachedPairLists; EmpiricalTrial trial = simulateDebuggingWithCatchedObjects(buggyRS.getRunningTrace(), correctRs.getRunningTrace(), pairList, diffMatcher, requireVisualization, useSliceBreaker, enableRandom, breakLimit); @@ -267,11 +495,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"); - - Map traceMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); - basePairLists = traceMatcher.matchConcurrentTraceNodePair(buggyTraces, correctTraces, diffMatcher, traceMap); System.out.println("Finish matching concurrent trace"); - cachedPairLists = basePairLists; cachedDiffMatcher = diffMatcher; cachedPairList = pairList; } @@ -283,24 +507,17 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean Visualizer visualizer = new Visualizer(); visualizer.visualize(buggyTrace, correctTrace, pairList, diffMatcher); } - if (buggyTraces.size() > 1 && requireVisualization) { - // TODO(Gab): update the trace map - ConcurrentVisualiser vizConcurrentVisualiser = - new ConcurrentVisualiser(buggyTraces, correctTraces, null, diffMatcher); - vizConcurrentVisualiser.visualise(); - } RootCauseFinder rootcauseFinder = new RootCauseFinder(); rootcauseFinder.setRootCauseBasedOnDefects4J(pairList, diffMatcher, buggyTrace, correctTrace); 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/handler/SeperateVersionConcHandler.java b/tregression/src/main/tregression/handler/SeperateVersionConcHandler.java new file mode 100644 index 00000000..78c9d013 --- /dev/null +++ b/tregression/src/main/tregression/handler/SeperateVersionConcHandler.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 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 SeperateVersionConcHandler extends AbstractHandler { + TrialGenerator generator = new TrialGenerator(); + TrialGenerator0 generator0 = new TrialGenerator0(); + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + JavaUtil.sourceFile2CUMap.clear(); + + Job job = new Job("Do evaluation") { + @Override + protected IStatus run(IProgressMonitor monitor) { + 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) { + PlayRegressionLocalizationHandler.finder = trials.get(0).getRootCauseFinder(); + } + + System.out.println("all the trials"); + for(int i=0; i originalTraces; + // temporary storage for processing + private List generatedTraceNodes; + // the non sequential concurrent trace nodes + private ArrayList> traces + = new ArrayList<>(); + + private ConcurrentTraceNode linkedTraceNode; + + public List getTraceList() { + return originalTraces; + } + + public Trace getMainTrace() { + return originalTraces.get(0); + } + + public List getSequentialTrace() { + return generatedTraceNodes; + } + + public ConcurrentTrace(AppJavaClassPath appJavaClassPath) { + super(appJavaClassPath); + // TODO Auto-generated constructor stub + } + + /** + * Technique to update trace nodes values + */ + private void postProcess() { + for (int i = 0; i < generatedTraceNodes.size(); ++i) { + generatedTraceNodes.get(i).setOrder(i + 1); + this.addTraceNode(generatedTraceNodes.get(i)); + } + } + + /** + * Function used to generate concurrent read write nodes. + * Need to split the trace nodes into read and write. + */ + private void generateTraces() { + if (traces.size() != 0) throw new RuntimeException("Should not generate more than once"); + if (originalTraces == null) throw new RuntimeException("Original traces not set"); + traces.ensureCapacity(originalTraces.size()); + int ctr = 0; + for (Trace trace: originalTraces) { + ArrayList result = new ArrayList<>(); + // reserve double the size than expected + result.ensureCapacity(trace.getExecutionList().size() * 2); + for (int i = 0; i < trace.getExecutionList().size(); ++i) { + TraceNode traceNode = trace.getExecutionList().get(i); + result.addAll(ConcurrentTraceNode.splitTraceNode(traceNode, ctr, trace.getThreadId())); + } + ctr += 1; + traces.add(result); + } + // update the step in previous and step in next + for (ArrayList trace: traces) { + ConcurrentTraceNode previous = null; + for (int i = 0; i < trace.size(); ++i) { + if (previous != null) { + trace.get(i).setStepInPrevious(trace.get(i-1)); + } + if (i != trace.size() - 1) { + trace.get(i).setStepInNext(trace.get(i+1)); + } + previous = trace.get(i); + } + } + } + + @Override + public TraceNode findProducer(VarValue varValue, TraceNode startNode) { + + // check if it is on heap + String s = varValue.getAliasVarID(); + boolean isLocalVar = varValue.isLocalVariable(); + boolean isOnHeap = !isLocalVar; + if (!(startNode instanceof ConcurrentTraceNode)) { + startNode = startNode.getBound(); + } + ConcurrentTraceNode concNode = (ConcurrentTraceNode) startNode; + int j = concNode.getOrder(); +// if (!concNode.isAtomic() && concNode.getWrittenVariables().size() > 0) { +// return concNode.getLinkedTraceNode().initialTraceNode; +// } +// + // find the individual trace to use the find data dependenccy + String varID = Variable.truncateSimpleID(varValue.getVarID()); + String headID = Variable.truncateSimpleID(varValue.getAliasVarID()); + + + for(int i=j-2; i>=1; i--) { + ConcurrentTraceNode node = this.getSequentialTrace().get(i); + for(VarValue writtenValue: node.getWrittenVariables()) { + + if (isOnHeap && writtenValue.getAliasVarID() != null + && writtenValue.getAliasVarID().equals(varValue.getAliasVarID())) { + return node; + } + if (!isOnHeap && concNode.getCurrentThread() != node.getCurrentThread()) { + // when the value is on a different thread + continue; + } + + String wVarID = Variable.truncateSimpleID(writtenValue.getVarID()); + String wHeadID = Variable.truncateSimpleID(writtenValue.getAliasVarID()); + + if(wVarID != null && wVarID.equals(varID) && node.getCurrentTraceId() + == concNode.getCurrentTraceId()) { + return node.initialTraceNode; + } + + if(wHeadID != null && wHeadID.equals(headID)) { + return node.initialTraceNode; + } + + VarValue childValue = writtenValue.findVarValue(varID, headID); + if(childValue != null) { + return node.initialTraceNode; + } + + } + } + return null; + } + + /** + * Generates a concurrent trace from the given trace by timestamp order. + * End goal is to remove timestamp synchronisation - aka deprecate this. + * @param traces The trace to generate the trace from + * @return + */ + public static ConcurrentTrace fromTimeStampOrder(List inputTraces) { + ConcurrentTrace resultTrace = new ConcurrentTrace(""); + resultTrace.originalTraces = inputTraces; + resultTrace.generateTraces(); + ArrayList> traces = resultTrace.traces; + + ArrayList result = new ArrayList<>(); + resultTrace.generatedTraceNodes = result; + List sharedVarIds = getSharedVarIDs(inputTraces); + HashSet sharedVarAliasIds = new HashSet<>(); + for (VarValue val: sharedVarIds) { + sharedVarAliasIds.add(val.getAliasVarID()); + } + HashMap sharedVarValues = new HashMap<>(); + ArrayList tracesPtr = new ArrayList<>(); + tracesPtr.ensureCapacity(traces.size()); + for (int i = 0; i < traces.size(); ++i) { + tracesPtr.add(0); // point to the first trace node + } + while (true) { + // select the first trace based off of time stamp order + // if there is a tie, break tie based off of current shared variables status + ArrayList possibleNodes = new ArrayList<>(); + for (int i = 0; i < traces.size(); ++i) { + ArrayList trace = traces.get(i); + int currentPoint = tracesPtr.get(i); + if (currentPoint >= trace.size()) { + // deal with case when all the pointers are at the end of the trace + continue; + } + ConcurrentTraceNode m = trace.get(currentPoint); + if (possibleNodes.size() == 0) { + possibleNodes.add(m); + } else { + if (possibleNodes.get(0).getTimestamp() < m.getTimestamp()) { + continue; + } + if (possibleNodes.get(0).getTimestamp() == m.getTimestamp()) { + possibleNodes.add(m); + continue; + } + // when all possible nodes are larger + possibleNodes.clear(); + possibleNodes.add(m); + } + } + if (possibleNodes.size() == 0) { + break; + } + + // greedy resolution -> pick the first + result.add(possibleNodes.get(0)); + int id = possibleNodes.get(0).getCurrentTraceId(); + tracesPtr.set(id, tracesPtr.get(id) + 1); + // todo: proper resolution + // deal with possible nodes. + // allocate the first possible node + // will be the bulk of the logic without timestamps + //ConcurrentTraceNode selected = extractPossibleTraceNode(result, sharedVarAliasIds, sharedVarValues, possibleNodes); + //tracesPtr.set(selected.getCurrentTraceId(), tracesPtr.get(selected.getCurrentTraceId()) + 1); + } + + resultTrace.postProcess(); + + return resultTrace; + } + + /** + * Extracts a tracenode + * @param result + * @param sharedVarAliasIds + * @param sharedVarValues + * @param possibleNodes + * @return + */ + private static ConcurrentTraceNode extractPossibleTraceNode(ArrayList result, + HashSet sharedVarAliasIds, HashMap sharedVarValues, + ArrayList possibleNodes) { + ConcurrentTraceNode selected = null; + for (int i = 0; i < possibleNodes.size(); ++i) { + ConcurrentTraceNode current = possibleNodes.get(i); + if (current.getWrittenVariables().size() > 0) { + continue; + } + List readValues = current.getReadVariables(); + // check the string value to if satis + boolean satis = true; + for (VarValue val: readValues) { + assert(val.getAliasVarID() == null || (!sharedVarAliasIds.contains(val.getAliasVarID()) + || sharedVarValues.containsKey(val.getAliasVarID()))); + // when there isn't a match + if (val.getAliasVarID() != null && sharedVarAliasIds.contains(val.getAliasVarID()) + && !val.getStringValue().equals(sharedVarValues.get(val.getAliasVarID()))) { + satis = false; + break; + } + } + if (satis) { + selected = current; + } + } + if (selected != null ) { + result.add(selected); + return selected; + } + // todo: this resolution is too greedy + // it doesn't work as we do not preserve W -> R + // may need to use some kind of constraint solving + // may not be possible until we indicate in the instrumentation + // to record RC vector (To determine what reads must occur before this write) + for (int i = 0; i < possibleNodes.size(); ++i) { + ConcurrentTraceNode current = possibleNodes.get(i); + if (current.getWrittenVariables().size() > 0) { + // take the first write + selected = current; + break; + } + } + if (selected == null) { + throw new RuntimeException("Failed to allocate trace node to concurrent trace"); + } + return selected; + } + + + + + + @Override + public TraceNode getTraceNode(int order) { + // TODO Auto-generated method stub + return this.getSequentialTrace().get(order); + } + + + + /** + * Finds data dependency relative to the concurrent trace + */ + @Override + public TraceNode findDataDependency(TraceNode checkingNode, VarValue readVar) { + return this.findProducer(readVar, checkingNode); + } + + + + @Override + public List findDataDependentee(TraceNode traceNode, VarValue writtenVar) { + List consumers = new ArrayList(); + if (!(traceNode instanceof ConcurrentTraceNode)) { + traceNode = traceNode.getBound(); + } + + ConcurrentTraceNode cnode = (ConcurrentTraceNode) traceNode; + String varID = Variable.truncateSimpleID(writtenVar.getVarID()); + String headID = Variable.truncateSimpleID(writtenVar.getAliasVarID()); + + for(int i=cnode.getOrder() + 1; i <= this.getSequentialTrace().size(); i++) { + TraceNode node = this.getSequentialTrace().get(i); + for(VarValue readVar: node.getReadVariables()) { + + String rVarID = Variable.truncateSimpleID(readVar.getVarID()); + String rHeadID = Variable.truncateSimpleID(readVar.getAliasVarID()); + + if(rVarID != null && rVarID.equals(varID)) { + consumers.add(node); + } + + if(rHeadID != null && rHeadID.equals(headID)) { + consumers.add(node); + } + + VarValue childValue = readVar.findVarValue(varID, headID); + if(childValue != null) { + consumers.add(node); + } + + } + } + return consumers; + + } + + + + public ConcurrentTrace(String id) { + super(id); + } + + public static ConcurrentTrace fromTraces(List traces) { + return null; + } + + private List generateSequential(List traces) { + return null; + } + + // convert the trace nodes to have read only and write only + private static List convertTraceNodes(Trace trace) { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < trace.size(); ++i) { + TraceNode current = trace.getTraceNode(i); + } + return null; + } + + private static List getSharedVarIDs(List traces) { + HashSet sharedVariables = new HashSet<>(); + List result = new ArrayList<>(); + for (Trace trace: traces) { + for (TraceNode tnode: trace.getExecutionList()) { + List writtenValues = tnode.getWrittenVariables(); + List readValues = tnode.getReadVariables(); + List combined = new ArrayList<>(); + for (VarValue wVal: writtenValues) { + combined.add(wVal); + } + for (VarValue rVal: readValues) { + combined.add(rVal); + } + for (VarValue value: combined) { + if (value.getAliasVarID() == null) continue; + if (sharedVariables.contains(value.getAliasVarID())) { + result.add(value); + continue; + } + sharedVariables.add(value.getAliasVarID()); + } + } + } + return result; + } + + /** + * Creates a virtual trace given a concurrent trace + * @return + */ + private static List constructSequentialTrace(List traces) { + Set sharedVariables = new HashSet<>(); + HashMap valueMap = new HashMap<>(); + + sharedVariables.addAll(getSharedVarIDs(traces)); + for (VarValue sharedVar: sharedVariables) { + valueMap.put(sharedVar.getAliasVarID(), ""); + } + + ArrayList sequentialTrace = new ArrayList<>(); + // split all the traces into read + write trace nodes + + int[] startingPtr = new int[traces.size()]; + for (int i = 0; i < traces.size(); ++i) { + startingPtr[i] = 0; + } + + while (true) { + // keep track of all traces -> if none of them have a matching node -> we can make no progress + boolean allNotStatis = true; + for (int i = 0; i < traces.size(); ++i) { + TraceNode current = traces.get(i).getTraceNode(startingPtr[i]); + List readValues = current.getReadVariables(); + List writeValues = current.getWrittenVariables(); + boolean satis = true; + // check if the read value matches the current variables value + for (VarValue val: readValues) { + if (sharedVariables.contains(val) + && valueMap.get(val) != val.getStringValue()) { + satis = false; + break; + } + } + if (!satis) continue; + for (int k = 0; k < traces.size(); ++k) { + if (k == i) continue; + + } + // todo: check if this is blocking the other points + startingPtr[i] += 1; + sequentialTrace.add(current); + break; + } + boolean completed = true; + for (int i = 0; i < traces.size(); ++i) { + if (startingPtr[i] < traces.get(i).size()) { + completed = false; + break; + } + } + if (completed) break; + } + return sequentialTrace; + + } +} \ No newline at end of file diff --git a/tregression/src/main/tregression/model/ConcurrentTraceNode.java b/tregression/src/main/tregression/model/ConcurrentTraceNode.java new file mode 100644 index 00000000..968ab3be --- /dev/null +++ b/tregression/src/main/tregression/model/ConcurrentTraceNode.java @@ -0,0 +1,305 @@ +package tregression.model; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationModel; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.editors.text.TextFileDocumentProvider; +import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.ui.texteditor.ITextEditor; + +import microbat.model.BreakPoint; +import microbat.model.BreakPointValue; +import microbat.model.UserInterestedVariables; +import microbat.model.trace.Trace; +import microbat.model.trace.TraceNode; +import microbat.model.value.VarValue; +import microbat.model.variable.Variable; +import microbat.util.JavaUtil; +import microbat.views.ReferenceAnnotation; + +/** + * Represents a concurrent trace node + * + * Adds additional logic for determining dependencies + * @author Gabau + * + */ +public class ConcurrentTraceNode extends TraceNode { + + + /** + * The index of the trace that this trace node is in + */ + protected int currentTraceId = 0; + protected boolean isAtomic = false; + protected TraceNode initialTraceNode; + // the sequential order it is in + protected int concurrentOrder; + /** + * The thread id + */ + protected long threadId = 0; + + + public long getCurrentThread() { + return initialTraceNode.getTrace().getThreadId(); + } + + + + + @Override + public TraceNode getBound() { + return this; + } + + + + + @Override + public TraceNode getStepInNext() { + return initialTraceNode.getStepInNext(); + } + + + + + @Override + public TraceNode getStepInPrevious() { + return initialTraceNode.getStepInPrevious(); + } + + + + + @Override + public TraceNode getStepOverNext() { + return initialTraceNode.getStepOverNext(); + } + + + + + @Override + public TraceNode getStepOverPrevious() { + return initialTraceNode.getStepOverPrevious(); + } + + + + + @Override + public int getOrder() { + return concurrentOrder; + } + + @Override + public void setOrder(int concurrentOrder) { + this.concurrentOrder = concurrentOrder; + } + + + /** + * Pointer to the trace node which writes to this trace node / reads to this trace node + * nullable + */ + private ConcurrentTraceNode linkedTraceNode; + public int getCurrentTraceId() { + return currentTraceId; + } + + /** + * Link the read and write trace nodes + * @return + */ + public ConcurrentTraceNode getLinkedTraceNode() { + return linkedTraceNode; + } + + + public ConcurrentTraceNode(BreakPoint breakPoint, BreakPointValue programState, int order, Trace trace, + String bytecode, long threadId) { + super(breakPoint, programState, order, trace, bytecode); + this.threadId = threadId; + // TODO Auto-generated constructor stub + } + + public ConcurrentTraceNode(TraceNode node, int currentTraceId, long threadId) { + super(node.getBreakPoint(), node.getProgramState(), + node.getOrder(), node.getTrace(), node.getBytecode()); + this.setTimestamp(node.getTimestamp()); + this.currentTraceId = currentTraceId; + this.threadId = threadId; + } + + /** + * Due to the way concurrency works, we separate the read and the + * writes, unless there is a synchronisation step. + * @return + */ + public boolean isWrite() { + return this.writtenVariables.size() > 0; + } + + public boolean isAtomic() { + return isAtomic; + } + + + /** + * This implementation currently means that if this + * node only has write, we get the written VarValues that match the selection. + * + */ + @Override + public List getWrongReadVars(UserInterestedVariables interestedVariables) { + if (this.isAtomic()) { + return super.getWrongReadVars(interestedVariables); + } + if (this.isWrite()) { + + List vars = new ArrayList<>(); + for(VarValue var: getWrittenVariables()){ + if(interestedVariables.contains(var)){ + vars.add(var); + } + List children = var.getAllDescedentChildren(); + for(VarValue child: children){ + if(interestedVariables.contains(child)){ + if(!vars.contains(child)){ + vars.add(child); + } + } + } + } + + return vars; + } + return super.getWrongReadVars(interestedVariables); + } + + public TraceNode getInitialTraceNode() { + return this.initialTraceNode; + } + +// +// @Override +// public TraceNode findProducer(VarValue varValue, TraceNode startNode) { +// +// // check if it is on heap +// String s = varValue.getAliasVarID(); +// boolean isLocalVar = varValue.isLocalVariable(); +// boolean isOnHeap = !isLocalVar; +// if (!(startNode instanceof ConcurrentTraceNode)) { +// throw new RuntimeException("Wrong checking node type"); +// } +// ConcurrentTraceNode concNode = (ConcurrentTraceNode) startNode; +// int j = concNode.getOrder(); +// if (!concNode.isAtomic() && concNode.getWrittenVariables().size() > 0) { +// return concNode.getLinkedTraceNode(); +// } +// +// // find the individual trace to use the find data dependenccy +// String varID = Variable.truncateSimpleID(varValue.getVarID()); +// String headID = Variable.truncateSimpleID(varValue.getAliasVarID()); +// +// +// for(int i=j-2; i>=1; i--) { +// ConcurrentTraceNode node = this.getSequentialTrace().get(i); +// for(VarValue writtenValue: node.getWrittenVariables()) { +// +// if (isOnHeap && writtenValue.getAliasVarID() != null +// && writtenValue.getAliasVarID().equals(varValue.getAliasVarID())) { +// return node; +// } +// if (!isOnHeap && concNode.getCurrentThread() != node.getCurrentThread()) { +// // when the value is on a different thread +// continue; +// } +// +// String wVarID = Variable.truncateSimpleID(writtenValue.getVarID()); +// String wHeadID = Variable.truncateSimpleID(writtenValue.getAliasVarID()); +// +// if(wVarID != null && wVarID.equals(varID) && node.getCurrentTraceId() +// == concNode.getCurrentTraceId()) { +// return node; +// } +// +// if(wHeadID != null && wHeadID.equals(headID)) { +// return node; +// } +// +// VarValue childValue = writtenValue.findVarValue(varID, headID); +// if(childValue != null) { +// return node; +// } +// +// } +// } +// return null; +// } +// +// + /** + * Split a given trace node into read and write concurrent + * @param node + * @return + */ + public static List splitTraceNode(TraceNode node, int traceId, long threadId) { + ArrayList result = new ArrayList<>(); + ConcurrentTraceNode r = new ConcurrentTraceNode(node, traceId, threadId); + node.setBoundTraceNode(r); + r.setReadVariables(node.getReadVariables()); + r.setWrittenVariables(node.getWrittenVariables()); + r.initialTraceNode = node; + r.isAtomic = true; + return List.of(r); + +// if (node.getReadVariables().size() == 0 && node.getWrittenVariables().size() == 0) { +// ConcurrentTraceNode r = new ConcurrentTraceNode(node, threadId); +// node.setConcurrentTraceNode(r); +// return List.of(r); +// } +// if (node.getReadVariables().size() > 0) { +// ConcurrentTraceNode readVariables = new ConcurrentTraceNode(node, threadId); +// readVariables.setReadVariables(node.getReadVariables()); +// node.setConcurrentTraceNode(readVariables); +// result.add(readVariables); +// } +// if (node.getWrittenVariables().size() > 0) { +// ConcurrentTraceNode writeVariables = new ConcurrentTraceNode(node, threadId); +// writeVariables.setWrittenVariables(node.getWrittenVariables()); +// result.add(writeVariables); +// if (result.size() == 2) { +// result.get(1).linkedTraceNode = result.get(0); +// result.get(0).linkedTraceNode = result.get(1); +// } +// } +// return result; + } + + @Override + public String toString() { + // TODO Auto-generated method stub + return "Current threadId: " + this.currentTraceId + " " + super.toString(); + } + + + + + +} \ No newline at end of file diff --git a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java new file mode 100644 index 00000000..0ac5ece4 --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java @@ -0,0 +1,178 @@ +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(); + + BuggyTraceView buggyTraceView = TregressionViews.getBuggyTraceView(); + 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 + protected void otherViewsBehavior(TraceNode correctNode) { + if (this.refreshProgramState) { + + StepPropertyView stepPropertyView = null; + try { + stepPropertyView = (StepPropertyView)PlatformUI.getWorkbench(). + getActiveWorkbenchWindow().getActivePage().showView(StepPropertyView.ID); + } catch (PartInitException e) { + e.printStackTrace(); + } + + 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(buggyTraceView.getTrace(), buggyNode.getOrder(), false); + } + } + + stepPropertyView.refresh(correctNode, buggyNode, diffMatcher, pairList); + } + + markJavaEditor(correctNode); + } + + public PairList getPairList() { + return pairList; + } + + public void setPairList(PairList pairList) { + this.pairList = pairList; + } + + public DiffMatcher getDiffMatcher() { + return diffMatcher; + } + + public void setDiffMatcher(DiffMatcher diffMatcher) { + this.diffMatcher = diffMatcher; + } + +} diff --git a/tregression/src/main/tregression/views/ConcurrentVisualiser.java b/tregression/src/main/tregression/views/ConcurrentVisualiser.java index e0c6b5aa..016b86d5 100644 --- a/tregression/src/main/tregression/views/ConcurrentVisualiser.java +++ b/tregression/src/main/tregression/views/ConcurrentVisualiser.java @@ -39,6 +39,10 @@ public void run() { view.setTraceList(bugTraces); view.updateData(); + ConcurrentTregressionTraceView correctView = TregressionViews.getConcCorrectTraceView(); + correctView.setTraceList(correctTraces); + correctView.updateData(); + } } diff --git a/tregression/src/main/tregression/views/TregressionViews.java b/tregression/src/main/tregression/views/TregressionViews.java index a7c863b6..df94b9f2 100644 --- a/tregression/src/main/tregression/views/TregressionViews.java +++ b/tregression/src/main/tregression/views/TregressionViews.java @@ -17,6 +17,17 @@ 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 { From 396311e1cd696999ef9ac387f0186388cfa77395 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Thu, 21 Mar 2024 15:15:23 +0800 Subject: [PATCH 04/22] Add all concurrent bug handler --- tregression/plugin.xml | 7 +- .../tregression/empiricalstudy/Simulator.java | 1 + .../empiricalstudy/TrialGenerator0.java | 9 +- .../handler/AllDefects4jConcHandler.java | 182 ++++++++++++++++++ ...r.java => SeparateVersionConcHandler.java} | 7 +- .../separatesnapshots/TraceCollector0.java | 26 ++- .../ControlPathBasedTraceMatcher.java | 7 + 7 files changed, 228 insertions(+), 11 deletions(-) create mode 100644 tregression/src/main/tregression/handler/AllDefects4jConcHandler.java rename tregression/src/main/tregression/handler/{SeperateVersionConcHandler.java => SeparateVersionConcHandler.java} (96%) diff --git a/tregression/plugin.xml b/tregression/plugin.xml index 1289cfbf..5d6acdae 100644 --- a/tregression/plugin.xml +++ b/tregression/plugin.xml @@ -54,10 +54,15 @@ name="Run Single Defect4j Bug"> + + diff --git a/tregression/src/main/tregression/empiricalstudy/Simulator.java b/tregression/src/main/tregression/empiricalstudy/Simulator.java index 33391dcb..cc69cf3c 100644 --- a/tregression/src/main/tregression/empiricalstudy/Simulator.java +++ b/tregression/src/main/tregression/empiricalstudy/Simulator.java @@ -179,6 +179,7 @@ public void prepare(Trace buggyTrace, Trace correctTrace, PairList pairList, Dif this.pairList = pairList; this.matcher = matcher; TraceNode initialStep = buggyTrace.getLatestNode(); + if (initialStep == null) return; TraceNode lastObservableFault = findObservedFault(initialStep, buggyTrace, correctTrace); if(lastObservableFault!=null) { diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 1bdc88cb..c8a77ead 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -42,6 +42,7 @@ 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; private RunningResult cachedBuggyRS; private RunningResult cachedCorrectRS; @@ -66,6 +67,8 @@ 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"; default: break; } @@ -273,8 +276,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat Settings.compilationUnitMap.clear(); Settings.iCompilationUnitMap.clear(); - buggyRS = buggyCollector.run(buggyPath, tc, config, isRunInTestCaseMode, - true, includedClassNames, excludedClassNames); + buggyRS = buggyCollector.runForceMultithreaded(buggyPath, tc, config, isRunInTestCaseMode, includedClassNames, excludedClassNames); if (buggyRS.getRunningType() != NORMAL) { trial = EmpiricalTrial.createDumpTrial(getProblemType(buggyRS.getRunningType())); return trial; @@ -282,8 +284,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat Settings.compilationUnitMap.clear(); Settings.iCompilationUnitMap.clear(); - correctRs = correctCollector.run(fixPath, tc, config, isRunInTestCaseMode, - true, includedClassNames, excludedClassNames); + correctRs = correctCollector.runForceMultithreaded(fixPath, tc, config, isRunInTestCaseMode, includedClassNames, excludedClassNames); if (correctRs.getRunningType() != NORMAL) { trial = EmpiricalTrial.createDumpTrial(getProblemType(correctRs.getRunningType())); return trial; diff --git a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java new file mode 100644 index 00000000..c6e7cc2f --- /dev/null +++ b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java @@ -0,0 +1,182 @@ +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 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.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) { + int skippedNum = 0; + int endNum = 500; + +// 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 = {"Closure"}; + int[] bugNum = {47}; + +// 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(); + + ProjectConfig d4jConfig = Defects4jProjectConfig.getConfig(projects[i], String.valueOf(j)); + List trials = generator0.generateTrialsConcurrent(buggyPath, fixPath, + false, false, false, 3, true, 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); + } + } + +// System.out.println("all the trials"); +// for(int j=0; j includeLibs, List excludeLibs){ AppJavaClassPath appClassPath = AppClassPathInitializer.initialize(workingDir, tc, config); @@ -67,6 +69,13 @@ public RunningResult run(String workingDir, TestCase tc, boolean isMultiThread = precheckInfo.getThreadNum()!=1; + if(!isMultiThread && mustBeMultiThread) { + System.out.println("It is multi-thread program!"); + RunningResult rs = new RunningResult(); + rs.setFailureType(TrialGenerator0.NOT_MULTI_THREAD); + return rs; + } + if(isMultiThread && !allowMultiThread) { System.out.println("It is multi-thread program!"); RunningResult rs = new RunningResult(); @@ -91,4 +100,17 @@ public RunningResult run(String workingDir, TestCase tc, return rs; } + + 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 b63b4d49..7d6d100a 100644 --- a/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java +++ b/tregression/src/main/tregression/tracematch/ControlPathBasedTraceMatcher.java @@ -6,6 +6,7 @@ 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; @@ -37,8 +38,14 @@ public List matchConcurrentTraceNodePair(List trace1, List Date: Thu, 28 Mar 2024 15:27:25 +0800 Subject: [PATCH 05/22] Initial fix for concurrent regression analysis --- .../tregression/StepChangeTypeChecker.java | 5 +++ .../empiricalstudy/ConcurrentSimulator.java | 23 +++++++++- .../ConcurrentTrialGenerator.java | 8 ++-- .../empiricalstudy/Regression.java | 25 ++++++++++- .../tregression/empiricalstudy/Simulator.java | 42 +++++++++++++++++++ .../empiricalstudy/TrialGenerator0.java | 27 ++++++++++-- .../config/Defects4jProjectConfig.java | 4 ++ .../handler/RegressionRetrieveHandler.java | 3 ++ .../tregression/model/ConcurrentTrace.java | 1 + .../model/ConcurrentTraceNode.java | 12 ++++++ .../views/ConcurrentBuggyTraceView.java | 7 +++- .../views/ConcurrentCorrectTraceView.java | 14 ++----- .../views/ConcurrentTregressionTraceView.java | 8 ++++ .../views/ConcurrentVisualiser.java | 20 +++++++-- 14 files changed, 172 insertions(+), 27 deletions(-) diff --git a/tregression/src/main/tregression/StepChangeTypeChecker.java b/tregression/src/main/tregression/StepChangeTypeChecker.java index f495e0e5..4849a33d 100644 --- a/tregression/src/main/tregression/StepChangeTypeChecker.java +++ b/tregression/src/main/tregression/StepChangeTypeChecker.java @@ -14,6 +14,7 @@ import microbat.util.PrimitiveUtils; import sav.common.core.Pair; import tregression.empiricalstudy.MatchStepFinder; +import tregression.model.ConcurrentTraceNode; import tregression.model.PairList; import tregression.model.TraceNodePair; import tregression.separatesnapshots.DiffMatcher; @@ -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 index fe8ccf4c..e6f6dfeb 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -8,6 +8,7 @@ import java.util.Set; import java.util.Stack; +import microbat.instrumentation.instr.aggreplay.shared.ParseData; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import tregression.SimulationFailException; @@ -29,7 +30,7 @@ public ConcurrentSimulator(boolean useSlicerBreaker, boolean enableRandom, int b public void prepareConc(List buggyTraces, List correctTraces, - PairList combinedPairList, + PairList combinedPairList, Map threadIdMap, DiffMatcher matcher) { Map correctTraceMap = new HashMap<>(); @@ -84,6 +85,26 @@ private List startSimulationWithCachedState(TraceNode observedFa 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; diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java index 19b4bb88..006d9ae5 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java @@ -58,9 +58,7 @@ protected EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, includedClassNames, excludedClassNames); correctRs = correctCollector0.run(fixPath, tc, config, isRunInTestMode, true, includedClassNames, excludedClassNames); - ConcurrentVisualiser vizConcurrentVisualiser = - new ConcurrentVisualiser(buggyTraces, correctTraces, pairLists, diffMatcher); - vizConcurrentVisualiser.visualise(); + Map traceMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); pairLists = traceMatcher.matchConcurrentTraceNodePair(buggyTraces, correctTraces, diffMatcher, traceMap); @@ -70,7 +68,9 @@ protected EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, tnPair.addAll(pairList.getPairList()); } PairList basePairList = new PairList(tnPair); - + ConcurrentVisualiser vizConcurrentVisualiser = + new ConcurrentVisualiser(correctTraces, buggyTraces, basePairList, diffMatcher); + vizConcurrentVisualiser.visualise(); RootCauseFinder rootCauseFinder = new RootCauseFinder(); rootCauseFinder.setRootCauseBasedOnDefects4JConc(pairLists, diffMatcher, buggyTraces, correctTraces); diff --git a/tregression/src/main/tregression/empiricalstudy/Regression.java b/tregression/src/main/tregression/empiricalstudy/Regression.java index ff3ae392..55f272ea 100644 --- a/tregression/src/main/tregression/empiricalstudy/Regression.java +++ b/tregression/src/main/tregression/empiricalstudy/Regression.java @@ -21,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) { @@ -29,6 +31,7 @@ public Regression(Trace buggyTrace, Trace correctTrace, PairList pairList) { this.correctTrace = correctTrace; this.pairList = pairList; } + public Trace getBuggyTrace() { return buggyTrace; @@ -38,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; } @@ -55,10 +63,23 @@ public void setPairList(PairList pairList) { } public void fillMissingInfo(ProjectConfig 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)); + 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/Simulator.java b/tregression/src/main/tregression/empiricalstudy/Simulator.java index cc69cf3c..16616858 100644 --- a/tregression/src/main/tregression/empiricalstudy/Simulator.java +++ b/tregression/src/main/tregression/empiricalstudy/Simulator.java @@ -786,6 +786,10 @@ private TraceNode findLatestControlDifferent(TraceNode currentNode, TraceNode co private 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(); @@ -812,6 +816,44 @@ private List createControlRecord(TraceNode currentNode, TraceNode return deadEndRecords; } + /** + * 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; + + } + + private List findTheNearestCorrespondence(TraceNode domOnRef, PairList pairList, Trace buggyTrace, Trace correctTrace) { List list = new ArrayList<>(); diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index c8a77ead..b7a9f610 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Scanner; @@ -24,6 +25,7 @@ import tregression.model.ConcurrentTrace; import tregression.model.PairList; import tregression.model.StepOperationTuple; +import tregression.model.TraceNodePair; import tregression.separatesnapshots.AppClassPathInitializer; import tregression.separatesnapshots.DiffMatcher; import tregression.separatesnapshots.RunningResult; @@ -292,6 +294,20 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat List 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); + } + } + Map threadIdMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); if (buggyRS != null && correctRs != null) { @@ -305,9 +321,12 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat diffMatcher.matchCode(); ControlPathBasedTraceMatcher traceMatcher = new ControlPathBasedTraceMatcher(); - pairList = traceMatcher.matchTraceNodePair(buggyRS.getRunningTrace(), correctRs.getRunningTrace(), - diffMatcher); 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); @@ -318,8 +337,10 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat cachedPairList = pairList; } + + if (requireVisualization) { - ConcurrentVisualiser visualizer = new ConcurrentVisualiser(correctTraces, buggyTraces, basePairLists, diffMatcher); + ConcurrentVisualiser visualizer = new ConcurrentVisualiser(correctTraces, buggyTraces, pairList, diffMatcher); visualizer.visualise(); } diff --git a/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java b/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java index 54586429..6bfabdf0 100644 --- a/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java +++ b/tregression/src/main/tregression/empiricalstudy/config/Defects4jProjectConfig.java @@ -89,6 +89,10 @@ else if (projectName.equals("Time")) { projectName, regressionID); } + if (projectName.equals("simple_defects")) { + config = generateMaventProjectConfig(DEFAULT_MAVEN_TEST, MAIN_JAVA_DIR, TARGET_DIR, "test-classes", projectName, regressionID); + } + return config; } diff --git a/tregression/src/main/tregression/handler/RegressionRetrieveHandler.java b/tregression/src/main/tregression/handler/RegressionRetrieveHandler.java index fb783678..1ba62b15 100644 --- a/tregression/src/main/tregression/handler/RegressionRetrieveHandler.java +++ b/tregression/src/main/tregression/handler/RegressionRetrieveHandler.java @@ -264,9 +264,12 @@ private Regression retrieveRegression(ProjectConfig config, String buggyPath, St return null; } Trace buggyTrace = execTraceReader.read(buggyExec); + List 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/model/ConcurrentTrace.java b/tregression/src/main/tregression/model/ConcurrentTrace.java index dbc7ffe8..6b08b016 100644 --- a/tregression/src/main/tregression/model/ConcurrentTrace.java +++ b/tregression/src/main/tregression/model/ConcurrentTrace.java @@ -46,6 +46,7 @@ public ConcurrentTrace(AppJavaClassPath appJavaClassPath) { private void postProcess() { for (int i = 0; i < generatedTraceNodes.size(); ++i) { generatedTraceNodes.get(i).setOrder(i + 1); + generatedTraceNodes.get(i).setConcurrentTrace(this); this.addTraceNode(generatedTraceNodes.get(i)); } } diff --git a/tregression/src/main/tregression/model/ConcurrentTraceNode.java b/tregression/src/main/tregression/model/ConcurrentTraceNode.java index 968ab3be..86d128d9 100644 --- a/tregression/src/main/tregression/model/ConcurrentTraceNode.java +++ b/tregression/src/main/tregression/model/ConcurrentTraceNode.java @@ -53,7 +53,15 @@ public class ConcurrentTraceNode extends TraceNode { * The thread id */ protected long threadId = 0; + private ConcurrentTrace concurrentTrace; + public void setConcurrentTrace(ConcurrentTrace concurrentTrace) { + this.concurrentTrace = concurrentTrace; + } + + public ConcurrentTrace getConcurrentTrace() { + return this.concurrentTrace; + } public long getCurrentThread() { return initialTraceNode.getTrace().getThreadId(); @@ -107,6 +115,10 @@ public int getOrder() { return concurrentOrder; } + public int getInitialOrder() { + return initialTraceNode.getOrder(); + } + @Override public void setOrder(int concurrentOrder) { this.concurrentOrder = concurrentOrder; diff --git a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java index c0c94558..40ad1ed0 100644 --- a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java @@ -1,15 +1,18 @@ package tregression.views; +import java.util.Map; + import org.eclipse.jface.action.Action; import org.eclipse.jface.viewers.IStructuredSelection; import microbat.model.ClassLocation; +import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import tregression.empiricalstudy.RootCauseFinder; public class ConcurrentBuggyTraceView extends ConcurrentTregressionTraceView { public static final String ID = "tregression.evalView.buggyConcTraceView"; - + @Override protected Action createControlMendingAction() { Action action = new Action() { @@ -22,7 +25,7 @@ public void run() { IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); TraceNode node = (TraceNode) selection.getFirstElement(); - CorrectTraceView correctTraceView = TregressionViews.getCorrectTraceView(); + ConcurrentCorrectTraceView correctTraceView = TregressionViews.getConcCorrectTraceView(); ClassLocation correspondingLocation = diffMatcher.findCorrespondingLocation(node.getBreakPoint(), false); TraceNode otherControlDom = new RootCauseFinder().findControlMendingNodeOnOtherTrace(node, pairList, correctTraceView.getTrace(), false, correspondingLocation, diffMatcher); diff --git a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java index 0ac5ece4..594f849d 100644 --- a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java @@ -40,7 +40,7 @@ public void run() { IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); TraceNode node = (TraceNode) selection.getFirstElement(); - BuggyTraceView buggyTraceView = TregressionViews.getBuggyTraceView(); + ConcurrentBuggyTraceView buggyTraceView = TregressionViews.getConcBuggyTraceView(); ClassLocation correspondingLocation = diffMatcher.findCorrespondingLocation(node.getBreakPoint(), true); TraceNode otherControlDom = new RootCauseFinder().findControlMendingNodeOnOtherTrace(node, pairList, buggyTraceView.getTrace(), true, correspondingLocation, diffMatcher); @@ -131,7 +131,7 @@ protected void markJavaEditor(TraceNode node) { } @Override - protected void otherViewsBehavior(TraceNode correctNode) { + public void otherViewsBehavior(TraceNode correctNode) { if (this.refreshProgramState) { StepPropertyView stepPropertyView = null; @@ -149,7 +149,7 @@ protected void otherViewsBehavior(TraceNode correctNode) { buggyNode = pair.getBeforeNode(); if (buggyNode != null) { ConcurrentBuggyTraceView buggyTraceView = TregressionViews.getConcBuggyTraceView(); - buggyTraceView.jumpToNode(buggyTraceView.getTrace(), buggyNode.getOrder(), false); + buggyTraceView.jumpToNode(buggyNode.getTrace(), buggyNode.getOrder(), false); } } @@ -163,16 +163,8 @@ public PairList getPairList() { return pairList; } - public void setPairList(PairList pairList) { - this.pairList = pairList; - } public DiffMatcher getDiffMatcher() { return diffMatcher; } - - public void setDiffMatcher(DiffMatcher diffMatcher) { - this.diffMatcher = diffMatcher; - } - } diff --git a/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java b/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java index bea2dcb3..fc237638 100644 --- a/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentTregressionTraceView.java @@ -20,6 +20,14 @@ 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); diff --git a/tregression/src/main/tregression/views/ConcurrentVisualiser.java b/tregression/src/main/tregression/views/ConcurrentVisualiser.java index 016b86d5..fb156db5 100644 --- a/tregression/src/main/tregression/views/ConcurrentVisualiser.java +++ b/tregression/src/main/tregression/views/ConcurrentVisualiser.java @@ -1,6 +1,7 @@ package tregression.views; import java.util.List; +import java.util.Map; import org.eclipse.swt.widgets.Display; @@ -15,12 +16,19 @@ public class ConcurrentVisualiser implements Runnable { private final List correctTraces; private final List bugTraces; - private List pairLists; + private PairList pairList; private DiffMatcher diffMatcher; + /** + * Concurrent visualiser for showing concurrent programs in diff + * @param correctTraces + * @param bugTraces + * @param pairList + * @param diffMatcher + */ public ConcurrentVisualiser(List correctTraces, List bugTraces, - List pairList, DiffMatcher diffMatcher) { - this.pairLists = pairList; + PairList pairList, DiffMatcher diffMatcher) { + this.pairList = pairList; this.diffMatcher = diffMatcher; this.correctTraces = correctTraces; this.bugTraces = bugTraces; @@ -37,10 +45,14 @@ public void visualise() { public void run() { ConcurrentTregressionTraceView view = TregressionViews.getConcBuggyTraceView(); view.setTraceList(bugTraces); + view.setDiffMatcher(diffMatcher); + view.setPairList(pairList); view.updateData(); - ConcurrentTregressionTraceView correctView = TregressionViews.getConcCorrectTraceView(); + ConcurrentCorrectTraceView correctView = TregressionViews.getConcCorrectTraceView(); correctView.setTraceList(correctTraces); + correctView.setPairList(this.pairList); + correctView.setDiffMatcher(diffMatcher); correctView.updateData(); } From cee6b4e1de4a9954bd6722eb18c904edd45f9c9f Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Thu, 28 Mar 2024 21:20:30 +0800 Subject: [PATCH 06/22] Add regression localisation + views to concurrent tregression --- tregression/plugin.xml | 5 + ...PlayRegressionLocalizationHandlerConc.java | 97 +++++++++++++++++++ .../empiricalstudy/EmpiricalTrial.java | 2 +- .../empiricalstudy/RootCauseNode.java | 10 +- .../handler/SeparateVersionConcHandler.java | 3 +- .../model/ConcurrentTraceNode.java | 8 +- .../src/main/tregression/model/PairList.java | 34 +++++-- .../views/ConcurrentBuggyTraceView.java | 32 ++++++ .../views/ConcurrentCorrectTraceView.java | 2 +- .../tregression/views/StepPropertyView.java | 21 ++++ 10 files changed, 201 insertions(+), 13 deletions(-) create mode 100644 tregression/src/main/traceagent/handler/PlayRegressionLocalizationHandlerConc.java diff --git a/tregression/plugin.xml b/tregression/plugin.xml index 5d6acdae..c9f34ddc 100644 --- a/tregression/plugin.xml +++ b/tregression/plugin.xml @@ -63,6 +63,11 @@ id="tregression.command.runAllDefects4jConcurrent" name="Run all defects 4j concurrent"> + + 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/tregression/empiricalstudy/EmpiricalTrial.java b/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java index 361279ab..dbdb7345 100644 --- a/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java +++ b/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java @@ -109,7 +109,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/RootCauseNode.java b/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java index 1dde75be..517e8326 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java @@ -1,6 +1,7 @@ package tregression.empiricalstudy; import microbat.model.trace.TraceNode; +import tregression.model.ConcurrentTraceNode; 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/handler/SeparateVersionConcHandler.java b/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java index 35e0a998..c0c61143 100644 --- a/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java +++ b/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java @@ -15,6 +15,7 @@ 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; @@ -66,7 +67,7 @@ protected IStatus run(IProgressMonitor monitor) { false, false, false, 3, true, config, testcase); if(trials.size() != 0) { - PlayRegressionLocalizationHandler.finder = trials.get(0).getRootCauseFinder(); + PlayRegressionLocalizationHandlerConc.finder = trials.get(0).getRootCauseFinder(); } System.out.println("all the trials"); diff --git a/tregression/src/main/tregression/model/ConcurrentTraceNode.java b/tregression/src/main/tregression/model/ConcurrentTraceNode.java index 86d128d9..4d85ada8 100644 --- a/tregression/src/main/tregression/model/ConcurrentTraceNode.java +++ b/tregression/src/main/tregression/model/ConcurrentTraceNode.java @@ -109,12 +109,18 @@ public TraceNode getStepOverPrevious() { - + /** + * Returns the order this node is in in the global order. + */ @Override public int getOrder() { return concurrentOrder; } + /** + * Returns the order of this trace node within the trace + * @return + */ public int getInitialOrder() { return initialTraceNode.getOrder(); } 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/views/ConcurrentBuggyTraceView.java b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java index 40ad1ed0..a9bba207 100644 --- a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java @@ -4,11 +4,14 @@ import org.eclipse.jface.action.Action; import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; import microbat.model.ClassLocation; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import tregression.empiricalstudy.RootCauseFinder; +import tregression.model.TraceNodePair; public class ConcurrentBuggyTraceView extends ConcurrentTregressionTraceView { public static final String ID = "tregression.evalView.buggyConcTraceView"; @@ -47,4 +50,33 @@ public String getText() { return action; } + @Override + public void otherViewsBehavior(TraceNode buggyNode) { + if (this.refreshProgramState) { + + StepPropertyView stepPropertyView = null; + try { + stepPropertyView = (StepPropertyView)PlatformUI.getWorkbench(). + getActiveWorkbenchWindow().getActivePage().showView(StepPropertyView.ID); + } catch (PartInitException e) { + e.printStackTrace(); + } + + TraceNodePair pair = pairList.findByAfterNode(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(buggyNode, correctNode, diffMatcher, pairList); + } + + markJavaEditor(buggyNode); + } + } diff --git a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java index 594f849d..132015f8 100644 --- a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java @@ -153,7 +153,7 @@ public void otherViewsBehavior(TraceNode correctNode) { } } - stepPropertyView.refresh(correctNode, buggyNode, diffMatcher, pairList); + stepPropertyView.refreshConc(correctNode, buggyNode, diffMatcher, pairList); } markJavaEditor(correctNode); 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() { From 9f50bcc6f11749e11f28392b5170b68a224c8249 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Sun, 31 Mar 2024 00:37:21 +0800 Subject: [PATCH 07/22] Setup for concurrent experiment --- .../tregression/StepChangeTypeChecker.java | 2 +- .../empiricalstudy/ConcurrentSimulator.java | 2 +- .../empiricalstudy/RegressionUtil.java | 1 + .../empiricalstudy/RootCauseNode.java | 2 +- .../tregression/empiricalstudy/Simulator.java | 4 +- .../empiricalstudy/TrialGenerator0.java | 75 +-- .../empiricalstudy/TrialRecorder.java | 15 +- .../handler/AllDefects4jConcHandler.java | 7 +- .../tregression/model/ConcurrentTrace.java | 443 ------------------ .../model/ConcurrentTraceNode.java | 323 ------------- .../separatesnapshots/TraceCollector0.java | 6 - .../main/tregression/views/StepDetailUI.java | 2 +- 12 files changed, 69 insertions(+), 813 deletions(-) delete mode 100644 tregression/src/main/tregression/model/ConcurrentTrace.java delete mode 100644 tregression/src/main/tregression/model/ConcurrentTraceNode.java diff --git a/tregression/src/main/tregression/StepChangeTypeChecker.java b/tregression/src/main/tregression/StepChangeTypeChecker.java index 4849a33d..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; @@ -14,7 +15,6 @@ import microbat.util.PrimitiveUtils; import sav.common.core.Pair; import tregression.empiricalstudy.MatchStepFinder; -import tregression.model.ConcurrentTraceNode; import tregression.model.PairList; import tregression.model.TraceNodePair; import tregression.separatesnapshots.DiffMatcher; diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index e6f6dfeb..f1b5e7bb 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -9,11 +9,11 @@ import java.util.Stack; import microbat.instrumentation.instr.aggreplay.shared.ParseData; +import microbat.model.trace.ConcurrentTrace; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import tregression.SimulationFailException; import tregression.StepChangeTypeChecker; -import tregression.model.ConcurrentTrace; import tregression.model.PairList; import tregression.model.StepOperationTuple; import tregression.separatesnapshots.DiffMatcher; diff --git a/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java b/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java index 4729ae3b..17ed55fd 100644 --- a/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java +++ b/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java @@ -74,6 +74,7 @@ private static TraceNode findClosestStep(TraceNode stopStep, List vis TraceNode closestStep = null; int distance = -1; for(TraceNode step: visitedSteps) { + if (step.getTrace().getThreadId() != stopStep.getTrace().getThreadId()) continue; if(step.getOrder()>stopStep.getOrder()) { if(closestStep==null) { closestStep = step; diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java b/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java index 517e8326..daf1bb3b 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseNode.java @@ -1,7 +1,7 @@ package tregression.empiricalstudy; +import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.TraceNode; -import tregression.model.ConcurrentTraceNode; public class RootCauseNode { diff --git a/tregression/src/main/tregression/empiricalstudy/Simulator.java b/tregression/src/main/tregression/empiricalstudy/Simulator.java index 16616858..657acd11 100644 --- a/tregression/src/main/tregression/empiricalstudy/Simulator.java +++ b/tregression/src/main/tregression/empiricalstudy/Simulator.java @@ -9,6 +9,8 @@ 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; @@ -21,8 +23,6 @@ import tregression.empiricalstudy.recommendation.BreakerRecommender; import tregression.empiricalstudy.training.DED; import tregression.empiricalstudy.training.TrainingDataTransfer; -import tregression.model.ConcurrentTrace; -import tregression.model.ConcurrentTraceNode; import tregression.model.PairList; import tregression.model.StepOperationTuple; import tregression.model.TraceNodePair; diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index b7a9f610..63dfd57f 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -9,6 +9,8 @@ import java.util.Map; import java.util.Scanner; +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,7 +24,6 @@ import tregression.empiricalstudy.config.ProjectConfig; import tregression.empiricalstudy.solutionpattern.PatternIdentifier; import tregression.io.RegressionRecorder; -import tregression.model.ConcurrentTrace; import tregression.model.PairList; import tregression.model.StepOperationTuple; import tregression.model.TraceNodePair; @@ -80,40 +81,52 @@ public static String getProblemType(int type) { public List generateTrialsConcurrent(String buggyPath, String fixPath, boolean isReuse, boolean useSliceBreaker, boolean enableRandom, int breakLimit, boolean requireVisualization, ProjectConfig config, String testcase) { - SingleTimer timer = SingleTimer.start("generateTrial"); List tcList; EmpiricalTrial trial = null; TestCase workingTC = null; + LinkedList result = new LinkedList<>(); try { tcList = retrieveD4jFailingTestCase(buggyPath); - - if(testcase!=null){ - tcList = filterSpecificTestCase(testcase, tcList); - } - - for (TestCase tc : tcList) { - System.out.println("#####working on test case " + tc.testClass + "#" + tc.testMethod); - workingTC = tc; - + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return new LinkedList<>(); + } + + if(testcase!=null){ + tcList = filterSpecificTestCase(testcase, tcList); + } + + for (TestCase tc : tcList) { + 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); - if(!trial.isDump()){ - break; - } + 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); } - - } catch (Exception e) { - e.printStackTrace(); + +// if(!trial.isDump()){ +// break; +// } } - if (trial == null) { - trial = EmpiricalTrial.createDumpTrial("runtime exception occurs"); - trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); - } - trial.setExecutionTime(timer.getExecutionTime()); - List list = new ArrayList<>(); - list.add(trial); - return list; + + +// if (trial == null) { +// trial = EmpiricalTrial.createDumpTrial("runtime exception occurs"); +// trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); +// } +// List list = new ArrayList<>(); +// list.add(trial); + return result; } @@ -376,8 +389,16 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat List correctSteps = rootcauseFinder.getStopStepsOnCorrectTrace(); List newIncludedClassNames = new ArrayList<>(); - List newIncludedBuggyClassNames = RegressionUtil.identifyIncludedClassNames(buggySteps, buggyRS.getPrecheckInfo(), rootcauseFinder.getRegressionNodeList()); - List newIncludedCorrectClassNames = RegressionUtil.identifyIncludedClassNames(correctSteps, correctRs.getPrecheckInfo(), rootcauseFinder.getCorrectNodeList()); + + 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; diff --git a/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java b/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java index 04497068..3588a6ae 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); diff --git a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java index c6e7cc2f..0d86bc95 100644 --- a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java +++ b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java @@ -25,6 +25,7 @@ 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; @@ -52,8 +53,8 @@ protected IStatus run(IProgressMonitor monitor) { e1.printStackTrace(); } - String[] projects = {"Closure"}; - int[] bugNum = {47}; + String[] projects = {"simple_defects"}; + int[] bugNum = {1}; // String[] projects = {"Lang"}; // int[] bugNum = {65}; @@ -110,7 +111,7 @@ protected IStatus run(IProgressMonitor monitor) { TrialGenerator0 generator0 = new TrialGenerator0(); - ProjectConfig d4jConfig = Defects4jProjectConfig.getConfig(projects[i], String.valueOf(j)); + ProjectConfig d4jConfig = ConfigFactory.createConfig(projects[i], i + "", buggyPath, fixPath); List trials = generator0.generateTrialsConcurrent(buggyPath, fixPath, false, false, false, 3, true, d4jConfig, null); diff --git a/tregression/src/main/tregression/model/ConcurrentTrace.java b/tregression/src/main/tregression/model/ConcurrentTrace.java deleted file mode 100644 index 6b08b016..00000000 --- a/tregression/src/main/tregression/model/ConcurrentTrace.java +++ /dev/null @@ -1,443 +0,0 @@ -package tregression.model; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import microbat.model.trace.Trace; -import microbat.model.trace.TraceNode; -import microbat.model.value.VarValue; -import microbat.model.variable.Variable; -import sav.strategies.dto.AppJavaClassPath; - -public class ConcurrentTrace extends Trace { - - private List originalTraces; - // temporary storage for processing - private List generatedTraceNodes; - // the non sequential concurrent trace nodes - private ArrayList> traces - = new ArrayList<>(); - - private ConcurrentTraceNode linkedTraceNode; - - public List getTraceList() { - return originalTraces; - } - - public Trace getMainTrace() { - return originalTraces.get(0); - } - - public List getSequentialTrace() { - return generatedTraceNodes; - } - - public ConcurrentTrace(AppJavaClassPath appJavaClassPath) { - super(appJavaClassPath); - // TODO Auto-generated constructor stub - } - - /** - * Technique to update trace nodes values - */ - private void postProcess() { - for (int i = 0; i < generatedTraceNodes.size(); ++i) { - generatedTraceNodes.get(i).setOrder(i + 1); - generatedTraceNodes.get(i).setConcurrentTrace(this); - this.addTraceNode(generatedTraceNodes.get(i)); - } - } - - /** - * Function used to generate concurrent read write nodes. - * Need to split the trace nodes into read and write. - */ - private void generateTraces() { - if (traces.size() != 0) throw new RuntimeException("Should not generate more than once"); - if (originalTraces == null) throw new RuntimeException("Original traces not set"); - traces.ensureCapacity(originalTraces.size()); - int ctr = 0; - for (Trace trace: originalTraces) { - ArrayList result = new ArrayList<>(); - // reserve double the size than expected - result.ensureCapacity(trace.getExecutionList().size() * 2); - for (int i = 0; i < trace.getExecutionList().size(); ++i) { - TraceNode traceNode = trace.getExecutionList().get(i); - result.addAll(ConcurrentTraceNode.splitTraceNode(traceNode, ctr, trace.getThreadId())); - } - ctr += 1; - traces.add(result); - } - // update the step in previous and step in next - for (ArrayList trace: traces) { - ConcurrentTraceNode previous = null; - for (int i = 0; i < trace.size(); ++i) { - if (previous != null) { - trace.get(i).setStepInPrevious(trace.get(i-1)); - } - if (i != trace.size() - 1) { - trace.get(i).setStepInNext(trace.get(i+1)); - } - previous = trace.get(i); - } - } - } - - @Override - public TraceNode findProducer(VarValue varValue, TraceNode startNode) { - - // check if it is on heap - String s = varValue.getAliasVarID(); - boolean isLocalVar = varValue.isLocalVariable(); - boolean isOnHeap = !isLocalVar; - if (!(startNode instanceof ConcurrentTraceNode)) { - startNode = startNode.getBound(); - } - ConcurrentTraceNode concNode = (ConcurrentTraceNode) startNode; - int j = concNode.getOrder(); -// if (!concNode.isAtomic() && concNode.getWrittenVariables().size() > 0) { -// return concNode.getLinkedTraceNode().initialTraceNode; -// } -// - // find the individual trace to use the find data dependenccy - String varID = Variable.truncateSimpleID(varValue.getVarID()); - String headID = Variable.truncateSimpleID(varValue.getAliasVarID()); - - - for(int i=j-2; i>=1; i--) { - ConcurrentTraceNode node = this.getSequentialTrace().get(i); - for(VarValue writtenValue: node.getWrittenVariables()) { - - if (isOnHeap && writtenValue.getAliasVarID() != null - && writtenValue.getAliasVarID().equals(varValue.getAliasVarID())) { - return node; - } - if (!isOnHeap && concNode.getCurrentThread() != node.getCurrentThread()) { - // when the value is on a different thread - continue; - } - - String wVarID = Variable.truncateSimpleID(writtenValue.getVarID()); - String wHeadID = Variable.truncateSimpleID(writtenValue.getAliasVarID()); - - if(wVarID != null && wVarID.equals(varID) && node.getCurrentTraceId() - == concNode.getCurrentTraceId()) { - return node.initialTraceNode; - } - - if(wHeadID != null && wHeadID.equals(headID)) { - return node.initialTraceNode; - } - - VarValue childValue = writtenValue.findVarValue(varID, headID); - if(childValue != null) { - return node.initialTraceNode; - } - - } - } - return null; - } - - /** - * Generates a concurrent trace from the given trace by timestamp order. - * End goal is to remove timestamp synchronisation - aka deprecate this. - * @param traces The trace to generate the trace from - * @return - */ - public static ConcurrentTrace fromTimeStampOrder(List inputTraces) { - ConcurrentTrace resultTrace = new ConcurrentTrace(""); - resultTrace.originalTraces = inputTraces; - resultTrace.generateTraces(); - ArrayList> traces = resultTrace.traces; - - ArrayList result = new ArrayList<>(); - resultTrace.generatedTraceNodes = result; - List sharedVarIds = getSharedVarIDs(inputTraces); - HashSet sharedVarAliasIds = new HashSet<>(); - for (VarValue val: sharedVarIds) { - sharedVarAliasIds.add(val.getAliasVarID()); - } - HashMap sharedVarValues = new HashMap<>(); - ArrayList tracesPtr = new ArrayList<>(); - tracesPtr.ensureCapacity(traces.size()); - for (int i = 0; i < traces.size(); ++i) { - tracesPtr.add(0); // point to the first trace node - } - while (true) { - // select the first trace based off of time stamp order - // if there is a tie, break tie based off of current shared variables status - ArrayList possibleNodes = new ArrayList<>(); - for (int i = 0; i < traces.size(); ++i) { - ArrayList trace = traces.get(i); - int currentPoint = tracesPtr.get(i); - if (currentPoint >= trace.size()) { - // deal with case when all the pointers are at the end of the trace - continue; - } - ConcurrentTraceNode m = trace.get(currentPoint); - if (possibleNodes.size() == 0) { - possibleNodes.add(m); - } else { - if (possibleNodes.get(0).getTimestamp() < m.getTimestamp()) { - continue; - } - if (possibleNodes.get(0).getTimestamp() == m.getTimestamp()) { - possibleNodes.add(m); - continue; - } - // when all possible nodes are larger - possibleNodes.clear(); - possibleNodes.add(m); - } - } - if (possibleNodes.size() == 0) { - break; - } - - // greedy resolution -> pick the first - result.add(possibleNodes.get(0)); - int id = possibleNodes.get(0).getCurrentTraceId(); - tracesPtr.set(id, tracesPtr.get(id) + 1); - // todo: proper resolution - // deal with possible nodes. - // allocate the first possible node - // will be the bulk of the logic without timestamps - //ConcurrentTraceNode selected = extractPossibleTraceNode(result, sharedVarAliasIds, sharedVarValues, possibleNodes); - //tracesPtr.set(selected.getCurrentTraceId(), tracesPtr.get(selected.getCurrentTraceId()) + 1); - } - - resultTrace.postProcess(); - - return resultTrace; - } - - /** - * Extracts a tracenode - * @param result - * @param sharedVarAliasIds - * @param sharedVarValues - * @param possibleNodes - * @return - */ - private static ConcurrentTraceNode extractPossibleTraceNode(ArrayList result, - HashSet sharedVarAliasIds, HashMap sharedVarValues, - ArrayList possibleNodes) { - ConcurrentTraceNode selected = null; - for (int i = 0; i < possibleNodes.size(); ++i) { - ConcurrentTraceNode current = possibleNodes.get(i); - if (current.getWrittenVariables().size() > 0) { - continue; - } - List readValues = current.getReadVariables(); - // check the string value to if satis - boolean satis = true; - for (VarValue val: readValues) { - assert(val.getAliasVarID() == null || (!sharedVarAliasIds.contains(val.getAliasVarID()) - || sharedVarValues.containsKey(val.getAliasVarID()))); - // when there isn't a match - if (val.getAliasVarID() != null && sharedVarAliasIds.contains(val.getAliasVarID()) - && !val.getStringValue().equals(sharedVarValues.get(val.getAliasVarID()))) { - satis = false; - break; - } - } - if (satis) { - selected = current; - } - } - if (selected != null ) { - result.add(selected); - return selected; - } - // todo: this resolution is too greedy - // it doesn't work as we do not preserve W -> R - // may need to use some kind of constraint solving - // may not be possible until we indicate in the instrumentation - // to record RC vector (To determine what reads must occur before this write) - for (int i = 0; i < possibleNodes.size(); ++i) { - ConcurrentTraceNode current = possibleNodes.get(i); - if (current.getWrittenVariables().size() > 0) { - // take the first write - selected = current; - break; - } - } - if (selected == null) { - throw new RuntimeException("Failed to allocate trace node to concurrent trace"); - } - return selected; - } - - - - - - @Override - public TraceNode getTraceNode(int order) { - // TODO Auto-generated method stub - return this.getSequentialTrace().get(order); - } - - - - /** - * Finds data dependency relative to the concurrent trace - */ - @Override - public TraceNode findDataDependency(TraceNode checkingNode, VarValue readVar) { - return this.findProducer(readVar, checkingNode); - } - - - - @Override - public List findDataDependentee(TraceNode traceNode, VarValue writtenVar) { - List consumers = new ArrayList(); - if (!(traceNode instanceof ConcurrentTraceNode)) { - traceNode = traceNode.getBound(); - } - - ConcurrentTraceNode cnode = (ConcurrentTraceNode) traceNode; - String varID = Variable.truncateSimpleID(writtenVar.getVarID()); - String headID = Variable.truncateSimpleID(writtenVar.getAliasVarID()); - - for(int i=cnode.getOrder() + 1; i <= this.getSequentialTrace().size(); i++) { - TraceNode node = this.getSequentialTrace().get(i); - for(VarValue readVar: node.getReadVariables()) { - - String rVarID = Variable.truncateSimpleID(readVar.getVarID()); - String rHeadID = Variable.truncateSimpleID(readVar.getAliasVarID()); - - if(rVarID != null && rVarID.equals(varID)) { - consumers.add(node); - } - - if(rHeadID != null && rHeadID.equals(headID)) { - consumers.add(node); - } - - VarValue childValue = readVar.findVarValue(varID, headID); - if(childValue != null) { - consumers.add(node); - } - - } - } - return consumers; - - } - - - - public ConcurrentTrace(String id) { - super(id); - } - - public static ConcurrentTrace fromTraces(List traces) { - return null; - } - - private List generateSequential(List traces) { - return null; - } - - // convert the trace nodes to have read only and write only - private static List convertTraceNodes(Trace trace) { - ArrayList result = new ArrayList<>(); - for (int i = 0; i < trace.size(); ++i) { - TraceNode current = trace.getTraceNode(i); - } - return null; - } - - private static List getSharedVarIDs(List traces) { - HashSet sharedVariables = new HashSet<>(); - List result = new ArrayList<>(); - for (Trace trace: traces) { - for (TraceNode tnode: trace.getExecutionList()) { - List writtenValues = tnode.getWrittenVariables(); - List readValues = tnode.getReadVariables(); - List combined = new ArrayList<>(); - for (VarValue wVal: writtenValues) { - combined.add(wVal); - } - for (VarValue rVal: readValues) { - combined.add(rVal); - } - for (VarValue value: combined) { - if (value.getAliasVarID() == null) continue; - if (sharedVariables.contains(value.getAliasVarID())) { - result.add(value); - continue; - } - sharedVariables.add(value.getAliasVarID()); - } - } - } - return result; - } - - /** - * Creates a virtual trace given a concurrent trace - * @return - */ - private static List constructSequentialTrace(List traces) { - Set sharedVariables = new HashSet<>(); - HashMap valueMap = new HashMap<>(); - - sharedVariables.addAll(getSharedVarIDs(traces)); - for (VarValue sharedVar: sharedVariables) { - valueMap.put(sharedVar.getAliasVarID(), ""); - } - - ArrayList sequentialTrace = new ArrayList<>(); - // split all the traces into read + write trace nodes - - int[] startingPtr = new int[traces.size()]; - for (int i = 0; i < traces.size(); ++i) { - startingPtr[i] = 0; - } - - while (true) { - // keep track of all traces -> if none of them have a matching node -> we can make no progress - boolean allNotStatis = true; - for (int i = 0; i < traces.size(); ++i) { - TraceNode current = traces.get(i).getTraceNode(startingPtr[i]); - List readValues = current.getReadVariables(); - List writeValues = current.getWrittenVariables(); - boolean satis = true; - // check if the read value matches the current variables value - for (VarValue val: readValues) { - if (sharedVariables.contains(val) - && valueMap.get(val) != val.getStringValue()) { - satis = false; - break; - } - } - if (!satis) continue; - for (int k = 0; k < traces.size(); ++k) { - if (k == i) continue; - - } - // todo: check if this is blocking the other points - startingPtr[i] += 1; - sequentialTrace.add(current); - break; - } - boolean completed = true; - for (int i = 0; i < traces.size(); ++i) { - if (startingPtr[i] < traces.get(i).size()) { - completed = false; - break; - } - } - if (completed) break; - } - return sequentialTrace; - - } -} \ No newline at end of file diff --git a/tregression/src/main/tregression/model/ConcurrentTraceNode.java b/tregression/src/main/tregression/model/ConcurrentTraceNode.java deleted file mode 100644 index 4d85ada8..00000000 --- a/tregression/src/main/tregression/model/ConcurrentTraceNode.java +++ /dev/null @@ -1,323 +0,0 @@ -package tregression.model; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.ui.JavaUI; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.Position; -import org.eclipse.jface.text.source.Annotation; -import org.eclipse.jface.text.source.AnnotationModel; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.editors.text.TextFileDocumentProvider; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.eclipse.ui.texteditor.ITextEditor; - -import microbat.model.BreakPoint; -import microbat.model.BreakPointValue; -import microbat.model.UserInterestedVariables; -import microbat.model.trace.Trace; -import microbat.model.trace.TraceNode; -import microbat.model.value.VarValue; -import microbat.model.variable.Variable; -import microbat.util.JavaUtil; -import microbat.views.ReferenceAnnotation; - -/** - * Represents a concurrent trace node - * - * Adds additional logic for determining dependencies - * @author Gabau - * - */ -public class ConcurrentTraceNode extends TraceNode { - - - /** - * The index of the trace that this trace node is in - */ - protected int currentTraceId = 0; - protected boolean isAtomic = false; - protected TraceNode initialTraceNode; - // the sequential order it is in - protected int concurrentOrder; - /** - * The thread id - */ - protected long threadId = 0; - private ConcurrentTrace concurrentTrace; - - public void setConcurrentTrace(ConcurrentTrace concurrentTrace) { - this.concurrentTrace = concurrentTrace; - } - - public ConcurrentTrace getConcurrentTrace() { - return this.concurrentTrace; - } - - public long getCurrentThread() { - return initialTraceNode.getTrace().getThreadId(); - } - - - - - @Override - public TraceNode getBound() { - return this; - } - - - - - @Override - public TraceNode getStepInNext() { - return initialTraceNode.getStepInNext(); - } - - - - - @Override - public TraceNode getStepInPrevious() { - return initialTraceNode.getStepInPrevious(); - } - - - - - @Override - public TraceNode getStepOverNext() { - return initialTraceNode.getStepOverNext(); - } - - - - - @Override - public TraceNode getStepOverPrevious() { - return initialTraceNode.getStepOverPrevious(); - } - - - - /** - * Returns the order this node is in in the global order. - */ - @Override - public int getOrder() { - return concurrentOrder; - } - - /** - * Returns the order of this trace node within the trace - * @return - */ - public int getInitialOrder() { - return initialTraceNode.getOrder(); - } - - @Override - public void setOrder(int concurrentOrder) { - this.concurrentOrder = concurrentOrder; - } - - - /** - * Pointer to the trace node which writes to this trace node / reads to this trace node - * nullable - */ - private ConcurrentTraceNode linkedTraceNode; - public int getCurrentTraceId() { - return currentTraceId; - } - - /** - * Link the read and write trace nodes - * @return - */ - public ConcurrentTraceNode getLinkedTraceNode() { - return linkedTraceNode; - } - - - public ConcurrentTraceNode(BreakPoint breakPoint, BreakPointValue programState, int order, Trace trace, - String bytecode, long threadId) { - super(breakPoint, programState, order, trace, bytecode); - this.threadId = threadId; - // TODO Auto-generated constructor stub - } - - public ConcurrentTraceNode(TraceNode node, int currentTraceId, long threadId) { - super(node.getBreakPoint(), node.getProgramState(), - node.getOrder(), node.getTrace(), node.getBytecode()); - this.setTimestamp(node.getTimestamp()); - this.currentTraceId = currentTraceId; - this.threadId = threadId; - } - - /** - * Due to the way concurrency works, we separate the read and the - * writes, unless there is a synchronisation step. - * @return - */ - public boolean isWrite() { - return this.writtenVariables.size() > 0; - } - - public boolean isAtomic() { - return isAtomic; - } - - - /** - * This implementation currently means that if this - * node only has write, we get the written VarValues that match the selection. - * - */ - @Override - public List getWrongReadVars(UserInterestedVariables interestedVariables) { - if (this.isAtomic()) { - return super.getWrongReadVars(interestedVariables); - } - if (this.isWrite()) { - - List vars = new ArrayList<>(); - for(VarValue var: getWrittenVariables()){ - if(interestedVariables.contains(var)){ - vars.add(var); - } - List children = var.getAllDescedentChildren(); - for(VarValue child: children){ - if(interestedVariables.contains(child)){ - if(!vars.contains(child)){ - vars.add(child); - } - } - } - } - - return vars; - } - return super.getWrongReadVars(interestedVariables); - } - - public TraceNode getInitialTraceNode() { - return this.initialTraceNode; - } - -// -// @Override -// public TraceNode findProducer(VarValue varValue, TraceNode startNode) { -// -// // check if it is on heap -// String s = varValue.getAliasVarID(); -// boolean isLocalVar = varValue.isLocalVariable(); -// boolean isOnHeap = !isLocalVar; -// if (!(startNode instanceof ConcurrentTraceNode)) { -// throw new RuntimeException("Wrong checking node type"); -// } -// ConcurrentTraceNode concNode = (ConcurrentTraceNode) startNode; -// int j = concNode.getOrder(); -// if (!concNode.isAtomic() && concNode.getWrittenVariables().size() > 0) { -// return concNode.getLinkedTraceNode(); -// } -// -// // find the individual trace to use the find data dependenccy -// String varID = Variable.truncateSimpleID(varValue.getVarID()); -// String headID = Variable.truncateSimpleID(varValue.getAliasVarID()); -// -// -// for(int i=j-2; i>=1; i--) { -// ConcurrentTraceNode node = this.getSequentialTrace().get(i); -// for(VarValue writtenValue: node.getWrittenVariables()) { -// -// if (isOnHeap && writtenValue.getAliasVarID() != null -// && writtenValue.getAliasVarID().equals(varValue.getAliasVarID())) { -// return node; -// } -// if (!isOnHeap && concNode.getCurrentThread() != node.getCurrentThread()) { -// // when the value is on a different thread -// continue; -// } -// -// String wVarID = Variable.truncateSimpleID(writtenValue.getVarID()); -// String wHeadID = Variable.truncateSimpleID(writtenValue.getAliasVarID()); -// -// if(wVarID != null && wVarID.equals(varID) && node.getCurrentTraceId() -// == concNode.getCurrentTraceId()) { -// return node; -// } -// -// if(wHeadID != null && wHeadID.equals(headID)) { -// return node; -// } -// -// VarValue childValue = writtenValue.findVarValue(varID, headID); -// if(childValue != null) { -// return node; -// } -// -// } -// } -// return null; -// } -// -// - /** - * Split a given trace node into read and write concurrent - * @param node - * @return - */ - public static List splitTraceNode(TraceNode node, int traceId, long threadId) { - ArrayList result = new ArrayList<>(); - ConcurrentTraceNode r = new ConcurrentTraceNode(node, traceId, threadId); - node.setBoundTraceNode(r); - r.setReadVariables(node.getReadVariables()); - r.setWrittenVariables(node.getWrittenVariables()); - r.initialTraceNode = node; - r.isAtomic = true; - return List.of(r); - -// if (node.getReadVariables().size() == 0 && node.getWrittenVariables().size() == 0) { -// ConcurrentTraceNode r = new ConcurrentTraceNode(node, threadId); -// node.setConcurrentTraceNode(r); -// return List.of(r); -// } -// if (node.getReadVariables().size() > 0) { -// ConcurrentTraceNode readVariables = new ConcurrentTraceNode(node, threadId); -// readVariables.setReadVariables(node.getReadVariables()); -// node.setConcurrentTraceNode(readVariables); -// result.add(readVariables); -// } -// if (node.getWrittenVariables().size() > 0) { -// ConcurrentTraceNode writeVariables = new ConcurrentTraceNode(node, threadId); -// writeVariables.setWrittenVariables(node.getWrittenVariables()); -// result.add(writeVariables); -// if (result.size() == 2) { -// result.get(1).linkedTraceNode = result.get(0); -// result.get(0).linkedTraceNode = result.get(1); -// } -// } -// return result; - } - - @Override - public String toString() { - // TODO Auto-generated method stub - return "Current threadId: " + this.currentTraceId + " " + super.toString(); - } - - - - - -} \ No newline at end of file diff --git a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java index 3b99c225..d429c71d 100644 --- a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java +++ b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java @@ -69,12 +69,6 @@ public RunningResult runInner(String workingDir, TestCase tc, boolean isMultiThread = precheckInfo.getThreadNum()!=1; - if(!isMultiThread && mustBeMultiThread) { - System.out.println("It is multi-thread program!"); - RunningResult rs = new RunningResult(); - rs.setFailureType(TrialGenerator0.NOT_MULTI_THREAD); - return rs; - } if(isMultiThread && !allowMultiThread) { System.out.println("It is multi-thread program!"); diff --git a/tregression/src/main/tregression/views/StepDetailUI.java b/tregression/src/main/tregression/views/StepDetailUI.java index 9c29da5c..2b5e3586 100644 --- a/tregression/src/main/tregression/views/StepDetailUI.java +++ b/tregression/src/main/tregression/views/StepDetailUI.java @@ -201,7 +201,7 @@ public void checkStateChanged(CheckStateChangedEvent event) { if (obj instanceof VarValue) { Trace trace = traceView.getTrace(); - + value = (VarValue) obj; String varID = value.getVarID(); From c53f8568197ee86f5ef5a76858697d266e93403d Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Sun, 31 Mar 2024 22:32:42 +0800 Subject: [PATCH 08/22] Add log size recording experiment --- tregression/plugin.xml | 5 + .../empiricalstudy/RegressionUtil.java | 6 +- .../empiricalstudy/TrialGenerator0.java | 7 +- .../handler/RunRecordingExperiment.java | 266 ++++++++++++++++++ .../util/ConcurrentTraceMatcher.java | 6 +- 5 files changed, 283 insertions(+), 7 deletions(-) create mode 100644 tregression/src/main/tregression/handler/RunRecordingExperiment.java diff --git a/tregression/plugin.xml b/tregression/plugin.xml index c9f34ddc..d59b9e18 100644 --- a/tregression/plugin.xml +++ b/tregression/plugin.xml @@ -68,6 +68,11 @@ id="tregression.command.regressionLocalConc" name="Play the process of regession localisation (Concurrent)"> + + diff --git a/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java b/tregression/src/main/tregression/empiricalstudy/RegressionUtil.java index 17ed55fd..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,8 @@ 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) { @@ -100,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/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 63dfd57f..88d61ee0 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -111,6 +112,7 @@ public List generateTrialsConcurrent(String buggyPath, String fi trial.setTestcase(workingTC.testClass + "::" + workingTC.testMethod); trial.setExecutionTime(timer.getExecutionTime()); result.add(trial); + e.printStackTrace(); } // if(!trial.isDump()){ @@ -302,6 +304,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat correctRs = correctCollector.runForceMultithreaded(fixPath, tc, config, isRunInTestCaseMode, includedClassNames, excludedClassNames); if (correctRs.getRunningType() != NORMAL) { trial = EmpiricalTrial.createDumpTrial(getProblemType(correctRs.getRunningType())); + trial.setTestcase(tc.toString()); return trial; } @@ -321,8 +324,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat } } - - Map threadIdMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); + Map threadIdMap = new HashMap<>(); if (buggyRS != null && correctRs != null) { cachedBuggyRS = buggyRS; cachedCorrectRS = correctRs; @@ -333,6 +335,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat 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<>(); diff --git a/tregression/src/main/tregression/handler/RunRecordingExperiment.java b/tregression/src/main/tregression/handler/RunRecordingExperiment.java new file mode 100644 index 00000000..4027683d --- /dev/null +++ b/tregression/src/main/tregression/handler/RunRecordingExperiment.java @@ -0,0 +1,266 @@ +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; + 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) { + 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); + } + + 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(); + 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(); + executor.runSharedVariable(fileName, Settings.stepLimit); + SingleTimer timer = SingleTimer.start("execute record"); + 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); + cancelThread.stopMonitoring(); + return null; + } + + + +} diff --git a/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java index 140f5d17..2f66c15d 100644 --- a/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java +++ b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java @@ -147,10 +147,10 @@ private void initCapCostForMCMF(List traces1, List traces2, int s, private int computeWeight(Trace t1, Trace t2) { BipGraph bipGraph = new BipGraph(t1.size(), t2.size()); int sameLines = 0; - for (int i = 0; i < t1.size(); ++i) { + for (int i = 1; i <= t1.size(); ++i) { BreakPoint bp1 = t1.getTraceNode(i).getBreakPoint(); - for (int j = 0; j < t2.size(); ++j) { - BreakPoint bp2 = t2.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); } From fbb3ca1df0b550e5b982724c6cf48f2bb66576d1 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Mon, 1 Apr 2024 22:23:50 +0800 Subject: [PATCH 09/22] Fix some concurrent simulator issues --- .../empiricalstudy/ConcurrentSimulator.java | 271 +++++++++++++++++- .../empiricalstudy/RootCauseFinder.java | 127 ++++++++ .../tregression/empiricalstudy/Simulator.java | 10 +- .../empiricalstudy/TrialGenerator0.java | 6 +- .../handler/RunRecordingExperiment.java | 22 +- .../model/TregressionConcurrentContext.java | 208 ++++++++++++++ .../preference/TregressionPreference.java | 9 + .../views/ConcurrentBuggyTraceView.java | 4 +- 8 files changed, 640 insertions(+), 17 deletions(-) create mode 100644 tregression/src/main/tregression/model/TregressionConcurrentContext.java diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index f1b5e7bb..06f5deac 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -12,15 +12,17 @@ import microbat.model.trace.ConcurrentTrace; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; +import microbat.model.value.VarValue; +import microbat.recommendation.UserFeedback; import tregression.SimulationFailException; +import tregression.StepChangeType; import tregression.StepChangeTypeChecker; import tregression.model.PairList; import tregression.model.StepOperationTuple; import tregression.separatesnapshots.DiffMatcher; /** - * Class containing logic for running erase - * on concurrent programs. + * Class containing logic for simulating debugging in concurrent programs */ public class ConcurrentSimulator extends Simulator { @@ -52,14 +54,275 @@ private List startSimulationConc(TraceNode observedFaultNode, Tr StepChangeTypeChecker typeChecker = new StepChangeTypeChecker(buggyTrace, correctTrace); List trials = new ArrayList<>(); TraceNode currentNode = observedFaultNode; - - EmpiricalTrial trial = workSingleTrial(buggyTrace, correctTrace, pairList, matcher, + EmpiricalTrial trial = workSingleTrialConc(buggyTrace, correctTrace, pairList, matcher, rootCauseFinder, typeChecker, currentNode); trials.add(trial); return trials; } + protected EmpiricalTrial workSingleTrialConc(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); + 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(); + } + + 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; + } + + } + + } + + 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(); + } + + 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); diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java index 327852cf..a8f23e98 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java @@ -10,6 +10,7 @@ import microbat.model.BreakPoint; import microbat.model.ClassLocation; import microbat.model.ControlScope; +import microbat.model.trace.ConcurrentTrace; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; import microbat.model.trace.TraceNodeOrderComparator; @@ -167,6 +168,123 @@ public void setRootCauseBasedOnDefects4J(PairList pairList, DiffMatcher matcher, private CausalityGraph causalityGraph; + + public void checkRootCauseConc(TraceNode observedFaultNode, ConcurrentTrace buggyTrace, ConcurrentTrace correctTrace, + PairList pairList, DiffMatcher matcher){ + 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; + + 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); + + TraceNode matchedStep = changeType.getMatchingStep(); + addWorkNode(workList, matchedStep, !stepW.isOnBefore); + 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); + addWorkNode(workList, otherDataDom, !stepW.isOnBefore); + addCausality(otherDataDom, !stepW.isOnBefore, causalityGraph, cNode, matchedVar); + } + + } + + } + else if(changeType.getType()==StepChangeType.CTL){ + TraceNode controlDom = step.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); + 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); + addCausality(otherControlDom, !stepW.isOnBefore, causalityGraph, cNode, null); + } + else if(changeType.getType()==StepChangeType.IDT){ + if(step.isException()){ + TraceNode nextStep = step.getStepInPrevious(); + 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); @@ -632,6 +750,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/Simulator.java b/tregression/src/main/tregression/empiricalstudy/Simulator.java index 657acd11..517df2b0 100644 --- a/tregression/src/main/tregression/empiricalstudy/Simulator.java +++ b/tregression/src/main/tregression/empiricalstudy/Simulator.java @@ -768,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); @@ -784,7 +784,7 @@ 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); @@ -909,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<>(); @@ -991,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); @@ -1000,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 88d61ee0..d066d89b 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -238,6 +238,9 @@ private void generateMainMethod(String workingPath, TestCase tc, Defects4jProjec System.currentTimeMillis(); } + /** + * 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 { @@ -296,6 +299,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat buggyRS = buggyCollector.runForceMultithreaded(buggyPath, tc, config, isRunInTestCaseMode, includedClassNames, excludedClassNames); if (buggyRS.getRunningType() != NORMAL) { trial = EmpiricalTrial.createDumpTrial(getProblemType(buggyRS.getRunningType())); + trial.setTestcase(tc.testClass + "#" + tc.testMethod); return trial; } @@ -381,7 +385,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat ConcurrentTrace buggyTrace = ConcurrentTrace.fromTimeStampOrder(buggyTraces); ConcurrentTrace correctTrace = ConcurrentTrace.fromTimeStampOrder(correctTraces); - rootcauseFinder.checkRootCause(simulator.getObservedFault(), buggyTrace, correctTrace, pairList, diffMatcher); + rootcauseFinder.checkRootCauseConc(simulator.getObservedFault(), buggyTrace, correctTrace, pairList, diffMatcher); TraceNode rootCause = rootcauseFinder.retrieveRootCause(pairList, diffMatcher, buggyTrace, correctTrace); if(rootCause==null){ diff --git a/tregression/src/main/tregression/handler/RunRecordingExperiment.java b/tregression/src/main/tregression/handler/RunRecordingExperiment.java index 4027683d..6c556b3a 100644 --- a/tregression/src/main/tregression/handler/RunRecordingExperiment.java +++ b/tregression/src/main/tregression/handler/RunRecordingExperiment.java @@ -55,7 +55,15 @@ enum RecordHeaders implements ExcelHeader { EXECUTION_TIME, ORIGINAL_MEMORY_SIZE, MEMEORY_SIZE, - LOG_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(); } @@ -84,7 +92,8 @@ public RecordingReport(File file) throws Exception { super(file); } - public void writeRow(String testCaseName, long executionTime, long originalMem, long memorySize, long logSize) { + 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); @@ -93,6 +102,7 @@ public void writeRow(String testCaseName, long executionTime, long originalMem, 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) { @@ -194,6 +204,8 @@ private Object executeAggrRecord(ExecutionEvent event, final AppJavaClassPath ap 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); @@ -235,9 +247,9 @@ private Object executeAggrRecord(ExecutionEvent event, final AppJavaClassPath ap CancelThread ctThread = new CancelThread(monitor, executor); ctThread.start(); - executor.runSharedVariable(fileName, Settings.stepLimit); + sharedMemError = executor.runSharedVariable(fileName, Settings.stepLimit); SingleTimer timer = SingleTimer.start("execute record"); - executor.runRecordConc(fileName, concFileNameString, Settings.stepLimit); + processMemError = executor.runRecordConc(fileName, concFileNameString, Settings.stepLimit); ctThread.stopMonitoring(); long logSize = concDumpFile.length(); long timeTaken = timer.getExecutionTime(); @@ -256,7 +268,7 @@ private Object executeAggrRecord(ExecutionEvent event, final AppJavaClassPath ap e.printStackTrace(); } - report.writeRow(Settings.launchClass, timeTaken, origMemSize, memoryUsed, logSize); + report.writeRow(Settings.launchClass, timeTaken, origMemSize, memoryUsed, logSize, processMemError, sharedMemError); cancelThread.stopMonitoring(); return null; } 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/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/views/ConcurrentBuggyTraceView.java b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java index a9bba207..4eb6374b 100644 --- a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java @@ -62,7 +62,7 @@ public void otherViewsBehavior(TraceNode buggyNode) { e.printStackTrace(); } - TraceNodePair pair = pairList.findByAfterNode(buggyNode); + TraceNodePair pair = pairList.findByBeforeNode(buggyNode); buggyNode.toString(); TraceNode correctNode = null; if(pair != null){ @@ -73,7 +73,7 @@ public void otherViewsBehavior(TraceNode buggyNode) { } } - stepPropertyView.refreshConc(buggyNode, correctNode, diffMatcher, pairList); + stepPropertyView.refreshConc(correctNode, buggyNode, diffMatcher, pairList); } markJavaEditor(buggyNode); From a6186086b37f2e32e127e79a0c8dea293a6f3a3d Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Tue, 2 Apr 2024 02:13:12 +0800 Subject: [PATCH 10/22] Add step detail ui for concurrent programs --- tregression/plugin.xml | 8 + .../ConcurrentTrialGenerator.java | 83 --- .../empiricalstudy/TrialGenerator0.java | 9 +- .../views/ConcurrentBuggyTraceView.java | 10 +- .../views/ConcurrentCorrectTraceView.java | 10 +- .../views/ConcurrentStepDetailUI.java | 693 ++++++++++++++++++ .../views/ConcurrentStepPropertyView.java | 121 +++ .../views/ConcurrentVisualiser.java | 10 +- .../main/tregression/views/StepDetailUI.java | 9 +- .../tregression/views/TregressionViews.java | 12 + 10 files changed, 857 insertions(+), 108 deletions(-) delete mode 100644 tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java create mode 100644 tregression/src/main/tregression/views/ConcurrentStepDetailUI.java create mode 100644 tregression/src/main/tregression/views/ConcurrentStepPropertyView.java diff --git a/tregression/plugin.xml b/tregression/plugin.xml index d59b9e18..cb3ca8d1 100644 --- a/tregression/plugin.xml +++ b/tregression/plugin.xml @@ -120,6 +120,14 @@ name="Concurrent Correct Trace" restorable="true"> + + diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java deleted file mode 100644 index 006d9ae5..00000000 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentTrialGenerator.java +++ /dev/null @@ -1,83 +0,0 @@ -package tregression.empiricalstudy; - -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import microbat.model.trace.Trace; -import microbat.preference.AnalysisScopePreference; -import microbat.util.Settings; -import tregression.empiricalstudy.config.ProjectConfig; -import tregression.model.PairList; -import tregression.model.TraceNodePair; -import tregression.separatesnapshots.DiffMatcher; -import tregression.separatesnapshots.RunningResult; -import tregression.separatesnapshots.TraceCollector; -import tregression.separatesnapshots.TraceCollector0; -import tregression.tracematch.ControlPathBasedTraceMatcher; -import tregression.util.ConcurrentTraceMatcher; -import tregression.views.ConcurrentVisualiser; - -/** - * Trial generator used for concurrent programs. - * Used to perform tregression on concurrent programs - */ -public class ConcurrentTrialGenerator { - - protected EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, - TestCase tc, ProjectConfig config, boolean isRunInTestMode, - boolean useSliceBreaker, boolean enableRandom, int breakLimit) { - TraceCollector0 buggyCollector = new TraceCollector0(true); - TraceCollector0 correctCollector0 = new TraceCollector0(false); - RunningResult buggyRsResult = null; - RunningResult correctRs = null; - - DiffMatcher diffMatcher = null; - List pairLists = null; - - int trialLimit = 10; - int trialNum = 0; - boolean isDataFlowComplete = false; - EmpiricalTrial trial = null; - List includedClassNames = AnalysisScopePreference.getIncludedLibList(); - List excludedClassNames = AnalysisScopePreference.getExcludedLibList(); - - List buggyTraces = buggyRsResult.getRunningInfo().getTraceList(); - List correctTraces = correctRs.getRunningInfo().getTraceList(); - diffMatcher = new DiffMatcher(config.srcSourceFolder, config.srcTestFolder, buggyPath, fixPath); - diffMatcher.matchCode(); - - ControlPathBasedTraceMatcher traceMatcher = new ControlPathBasedTraceMatcher(); - - while (!isDataFlowComplete && trialNum < trialLimit) { - trialNum++; - Settings.compilationUnitMap.clear(); - Settings.iCompilationUnitMap.clear(); - - buggyRsResult = buggyCollector.run(buggyPath, tc, config, isRunInTestMode, true, - includedClassNames, excludedClassNames); - correctRs = correctCollector0.run(fixPath, tc, config, isRunInTestMode, true, includedClassNames, excludedClassNames); - - - - Map traceMap = new ConcurrentTraceMatcher(diffMatcher).matchTraces(buggyTraces, correctTraces); - pairLists = traceMatcher.matchConcurrentTraceNodePair(buggyTraces, correctTraces, diffMatcher, traceMap); - List tnPair = new LinkedList<>(); - - for (PairList pairList : pairLists) { - tnPair.addAll(pairList.getPairList()); - } - PairList basePairList = new PairList(tnPair); - ConcurrentVisualiser vizConcurrentVisualiser = - new ConcurrentVisualiser(correctTraces, buggyTraces, basePairList, diffMatcher); - vizConcurrentVisualiser.visualise(); - - RootCauseFinder rootCauseFinder = new RootCauseFinder(); - rootCauseFinder.setRootCauseBasedOnDefects4JConc(pairLists, diffMatcher, buggyTraces, correctTraces); - ConcurrentSimulator simulator = new ConcurrentSimulator(useSliceBreaker, enableRandom, breakLimit); - simulator.prepareConc(buggyTraces, correctTraces, basePairList, traceMap, diffMatcher); - } - - return null; - } -} diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index d066d89b..20ab201b 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -357,16 +357,21 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat cachedPairList = pairList; } + ConcurrentTrace buggyTrace = ConcurrentTrace.fromTimeStampOrder(buggyTraces); + ConcurrentTrace correctTrace = ConcurrentTrace.fromTimeStampOrder(correctTraces); if (requireVisualization) { - ConcurrentVisualiser visualizer = new ConcurrentVisualiser(correctTraces, buggyTraces, pairList, diffMatcher); + 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); @@ -383,8 +388,6 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat return trial; } - ConcurrentTrace buggyTrace = ConcurrentTrace.fromTimeStampOrder(buggyTraces); - ConcurrentTrace correctTrace = ConcurrentTrace.fromTimeStampOrder(correctTraces); rootcauseFinder.checkRootCauseConc(simulator.getObservedFault(), buggyTrace, correctTrace, pairList, diffMatcher); TraceNode rootCause = rootcauseFinder.retrieveRootCause(pairList, diffMatcher, buggyTrace, correctTrace); diff --git a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java index 4eb6374b..8e40365c 100644 --- a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java @@ -53,15 +53,7 @@ public String getText() { @Override public void otherViewsBehavior(TraceNode buggyNode) { if (this.refreshProgramState) { - - StepPropertyView stepPropertyView = null; - try { - stepPropertyView = (StepPropertyView)PlatformUI.getWorkbench(). - getActiveWorkbenchWindow().getActivePage().showView(StepPropertyView.ID); - } catch (PartInitException e) { - e.printStackTrace(); - } - + ConcurrentStepPropertyView stepPropertyView = TregressionViews.getConcStepPropertyView(); TraceNodePair pair = pairList.findByBeforeNode(buggyNode); buggyNode.toString(); TraceNode correctNode = null; diff --git a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java index 132015f8..b701813c 100644 --- a/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentCorrectTraceView.java @@ -133,15 +133,7 @@ protected void markJavaEditor(TraceNode node) { @Override public void otherViewsBehavior(TraceNode correctNode) { if (this.refreshProgramState) { - - StepPropertyView stepPropertyView = null; - try { - stepPropertyView = (StepPropertyView)PlatformUI.getWorkbench(). - getActiveWorkbenchWindow().getActivePage().showView(StepPropertyView.ID); - } catch (PartInitException e) { - e.printStackTrace(); - } - + ConcurrentStepPropertyView stepPropertyView = TregressionViews.getConcStepPropertyView(); TraceNodePair pair = pairList.findByAfterNode(correctNode); correctNode.toString(); TraceNode buggyNode = null; diff --git a/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java b/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java new file mode 100644 index 00000000..f4d28683 --- /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.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..35c8bc7f --- /dev/null +++ b/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java @@ -0,0 +1,121 @@ +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 refresh(TraceNode correctNode, TraceNode buggyNode, DiffMatcher diffMatcher, PairList pairList){ + Trace buggyTrace = TregressionViews.getBuggyTraceView().getTrace(); + Trace correctTrace = TregressionViews.getCorrectTraceView().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); + } + } + + + 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/ConcurrentVisualiser.java b/tregression/src/main/tregression/views/ConcurrentVisualiser.java index fb156db5..7b8c1bd3 100644 --- a/tregression/src/main/tregression/views/ConcurrentVisualiser.java +++ b/tregression/src/main/tregression/views/ConcurrentVisualiser.java @@ -5,6 +5,7 @@ import org.eclipse.swt.widgets.Display; +import microbat.model.trace.ConcurrentTrace; import microbat.model.trace.Trace; import tregression.model.PairList; import tregression.separatesnapshots.DiffMatcher; @@ -18,7 +19,8 @@ public class ConcurrentVisualiser implements Runnable { 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 @@ -27,11 +29,14 @@ public class ConcurrentVisualiser implements Runnable { * @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() { @@ -48,12 +53,15 @@ public void run() { 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 2b5e3586..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); } } } diff --git a/tregression/src/main/tregression/views/TregressionViews.java b/tregression/src/main/tregression/views/TregressionViews.java index df94b9f2..190f1627 100644 --- a/tregression/src/main/tregression/views/TregressionViews.java +++ b/tregression/src/main/tregression/views/TregressionViews.java @@ -62,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; + } } From 806f9e64cae2fb6ed79e90d2de4f0632353d7199 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Wed, 3 Apr 2024 00:23:00 +0800 Subject: [PATCH 11/22] Add deadlock detection method --- .../src/main/tregression/StepChangeType.java | 7 +- .../empiricalstudy/ConcurrentSimulator.java | 7 +- .../empiricalstudy/EmpiricalTrial.java | 4 +- .../empiricalstudy/TrialGenerator0.java | 67 ++++++++++++++++++- .../handler/AllDefects4jConcHandler.java | 19 ++++-- .../views/ConcurrentStepPropertyView.java | 24 +------ 6 files changed, 92 insertions(+), 36 deletions(-) diff --git a/tregression/src/main/tregression/StepChangeType.java b/tregression/src/main/tregression/StepChangeType.java index 0f8cf54f..c7b9c7df 100644 --- a/tregression/src/main/tregression/StepChangeType.java +++ b/tregression/src/main/tregression/StepChangeType.java @@ -83,9 +83,10 @@ 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; } } diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index 06f5deac..a8d9b710 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -26,6 +26,7 @@ */ public class ConcurrentSimulator extends Simulator { + boolean isMultiThread = false; public ConcurrentSimulator(boolean useSlicerBreaker, boolean enableRandom, int breakerTrialLimit) { super(useSlicerBreaker, enableRandom, breakerTrialLimit); } @@ -36,6 +37,7 @@ public void prepareConc(List buggyTraces, 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); } @@ -50,7 +52,6 @@ public void prepareConc(List buggyTraces, private List startSimulationConc(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; @@ -66,7 +67,7 @@ protected EmpiricalTrial workSingleTrialConc(Trace buggyTrace, Trace correctTrac TraceNode currentNode) { List checkingList = new ArrayList<>(); TraceNode rootcauseNode = rootCauseFinder.retrieveRootCause(pairList, matcher, buggyTrace, correctTrace); - boolean isMultiThread = false; + rootCauseFinder.setRootCauseBasedOnDefects4J(pairList, matcher, buggyTrace, correctTrace); long startTime = System.currentTimeMillis(); @@ -390,7 +391,7 @@ public List detectMutatedBug(Trace buggyTrace, Trace correctTrac if(trials!=null) { boolean rootcauseFind = false; for(EmpiricalTrial trial: trials) { - if(!rootcauseFind && trial.getRootcauseNode()!=null){ + if(!rootcauseFind && trial.getRootcauseNode()!=null) { rootcauseFind = true; } trial.setSimulationTime(checkTime); diff --git a/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java b/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java index dbdb7345..0783f4d9 100644 --- a/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java +++ b/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java @@ -100,7 +100,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){ diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 20ab201b..513904e3 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -4,12 +4,18 @@ 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.handler.CancelThread; +import microbat.instrumentation.instr.aggreplay.TimeoutThread; import microbat.model.trace.ConcurrentTrace; import microbat.model.trace.ConcurrentTraceNode; import microbat.model.trace.Trace; @@ -54,7 +60,12 @@ public class TrialGenerator0 { 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: @@ -99,6 +110,7 @@ public List generateTrialsConcurrent(String buggyPath, String fi } 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"); @@ -238,6 +250,56 @@ 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 */ @@ -327,6 +389,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat correctTrace.setAppJavaClassPath(correctAppJavaClassPath); } } + boolean isTimeout = buggyRS.getRunningInfo().getProgramMsg().equals(TimeoutThread.TIMEOUT_MSG); Map threadIdMap = new HashMap<>(); if (buggyRS != null && correctRs != null) { @@ -372,6 +435,8 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat + + ConcurrentSimulator simulator = new ConcurrentSimulator(useSliceBreaker, enableRandom, breakLimit); simulator.prepareConc(buggyTraces, correctTraces, pairList, threadIdMap, diffMatcher); diff --git a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java index 0d86bc95..c117e9b9 100644 --- a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java +++ b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java @@ -18,6 +18,7 @@ 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; @@ -40,7 +41,8 @@ public Object execute(ExecutionEvent event) throws ExecutionException { protected IStatus run(IProgressMonitor monitor) { 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}; @@ -53,8 +55,10 @@ protected IStatus run(IProgressMonitor monitor) { e1.printStackTrace(); } - String[] projects = {"simple_defects"}; - int[] bugNum = {1}; +// String[] projects = {"simple_defects"}; +// int[] bugNum = {1}; + String[] projects = {"Closure"}; + int[] bugNum = {50}; // String[] projects = {"Lang"}; // int[] bugNum = {65}; @@ -68,9 +72,9 @@ protected IStatus run(IProgressMonitor monitor) { File defects4jFile = null; try { for(int i=0; i trials = generator0.generateTrialsConcurrent(buggyPath, fixPath, - false, false, false, 3, true, d4jConfig, null); + false, false, false, 3, false, d4jConfig, null); TrialRecorder recorder; try { @@ -156,7 +161,7 @@ && new File(oldDefects4jFile).exists()) { Arrays.asList(new TextComparisonRule(null), new SimulatorComparisonRule()), keys); } } - + cancelThread.stopMonitoring(); // System.out.println("all the trials"); // for(int j=0; j Date: Wed, 3 Apr 2024 22:05:40 +0800 Subject: [PATCH 12/22] Add deadlock check to the program --- .../report/AgentDefects4jHeaders.java | 2 ++ .../empiricalstudy/ConcurrentSimulator.java | 4 +++ .../empiricalstudy/EmpiricalTrial.java | 20 ++++++++++++++- .../tregression/empiricalstudy/Header.java | 2 ++ .../empiricalstudy/TrialGenerator0.java | 25 ++++++++++++++++++- .../empiricalstudy/TrialRecorder.java | 2 ++ .../util/ConcurrentTraceMatcher.java | 2 +- 7 files changed, 54 insertions(+), 3 deletions(-) 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/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index a8d9b710..6ce15f16 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -30,6 +30,10 @@ public class ConcurrentSimulator extends Simulator { 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, diff --git a/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java b/tregression/src/main/tregression/empiricalstudy/EmpiricalTrial.java index 0783f4d9..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(); } 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/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 513904e3..db499f9d 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -390,6 +390,12 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat } } 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) { @@ -420,6 +426,17 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat cachedPairList = pairList; } + System.out.println("Wrong traces"); + + for (Trace trace : buggyTraces) { + System.out.println(trace.getInnerThreadId().printRootListNode()); + } + + System.out.println("Correct traces"); + for (Trace trace : correctTraces) { + System.out.println(trace.getInnerThreadId().printRootListNode()); + } +// ConcurrentTrace buggyTrace = ConcurrentTrace.fromTimeStampOrder(buggyTraces); ConcurrentTrace correctTrace = ConcurrentTrace.fromTimeStampOrder(correctTraces); @@ -440,6 +457,12 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat 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(), @@ -509,7 +532,7 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat t.setFixedTrace(correctTrace); t.setPairList(pairList); t.setDiffMatcher(diffMatcher); - + t.setDeadLock(deadLockThreads.size() > 0); PatternIdentifier identifier = new PatternIdentifier(); identifier.identifyPattern(t); } diff --git a/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java b/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java index 3588a6ae..032075af 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialRecorder.java @@ -158,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/util/ConcurrentTraceMatcher.java b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java index 2f66c15d..72b3b5ed 100644 --- a/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java +++ b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java @@ -116,7 +116,7 @@ private void initCapCostForMCMF(List traces1, List traces2, int s, int weight = computeWeight(trace, trace2); // use this weight to differentiate // between matching small to superset and small to equal set - double score = weight / Math.max(trace.size(), trace2.size()); + 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) { From 47c0d049fd3695c8907bc104b0e33cdcb53496be Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Thu, 4 Apr 2024 20:06:52 +0800 Subject: [PATCH 13/22] Add continuous trial generator --- .../empiricalstudy/TrialGenerator0.java | 6 +- .../BuggyRnRTraceCollector.java | 84 +++++++++++++++++++ .../BuggyTraceCollector.java | 48 +++++++++++ .../separatesnapshots/RunningResult.java | 7 ++ .../separatesnapshots/TraceCollector0.java | 42 ++++++---- 5 files changed, 168 insertions(+), 19 deletions(-) create mode 100644 tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java create mode 100644 tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index db499f9d..3877594c 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -35,6 +35,7 @@ import tregression.model.StepOperationTuple; import tregression.model.TraceNodePair; import tregression.separatesnapshots.AppClassPathInitializer; +import tregression.separatesnapshots.BuggyTraceCollector; import tregression.separatesnapshots.DiffMatcher; import tregression.separatesnapshots.RunningResult; import tregression.separatesnapshots.TraceCollector0; @@ -306,7 +307,7 @@ private Set hasDeadlock(List traces) { 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 TraceCollector0(true); + TraceCollector0 buggyCollector = new BuggyTraceCollector(10); TraceCollector0 correctCollector = new TraceCollector0(false); long time1 = 0; long time2 = 0; @@ -616,9 +617,6 @@ private EmpiricalTrial analyzeTestCase(String buggyPath, String fixPath, boolean trial = EmpiricalTrial.createDumpTrial(getProblemType(correctRs.getRunningType())); return trial; } - - List buggyTraces = buggyRS.getRunningInfo().getTraceList(); - List correctTraces = correctRs.getRunningInfo().getTraceList(); if (buggyRS != null && correctRs != null) { cachedBuggyRS = buggyRS; diff --git a/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java b/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java new file mode 100644 index 00000000..bb905429 --- /dev/null +++ b/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java @@ -0,0 +1,84 @@ +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.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); + + try { + File precheckInfoFile = File.createTempFile("precheck", ".txt"); + File recording = File.createTempFile("var", ".txt"); + File concDumpFile = File.createTempFile("recording", ".txt"); + String concDumpFileString = concDumpFile.getAbsolutePath(); + executor.runPrecheck(precheckInfoFile.getAbsolutePath(), Settings.stepLimit); + PreCheckInformation precheckInfo = executor.getPrecheckInfo(); + + executor.runSharedVariable(recording.getPath(), Settings.stepLimit); + for (int i = 0; i < limit; ++i) { + executor.runRecordConc(recording.getPath(), concDumpFile.getAbsolutePath(), Settings.stepLimit); + StorableReader reader = new StorableReader(concDumpFile); + reader.read(); + String programMsgString = reader.getProgramMsg(); + // when it is a fail + if (!MicrobatUtils.checkTestResult(programMsgString)) { + firstIter = i + 1; + break; + } + } + RunningInfo resultInfo = null; + for (int i = 0; i < limit; ++i) { + resultInfo = executor.runReplayTracer(workingDir, concDumpFileString, Settings.stepLimit); + if (!MicrobatUtils.checkTestResult(resultInfo.getProgramMsg())) { + secondIter = i + 1; + break; + } + } + updateTraceInfo(resultInfo); + + RunningResult result = new RunningResult(resultInfo.getMainTrace(), + null, null, precheckInfo, executor.getAppPath()); + 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..adccccdc --- /dev/null +++ b/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java @@ -0,0 +1,48 @@ +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); + 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) { + return super.run(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); + } + + @Override + public RunningResult run(String workingDir, TestCase tc, ProjectConfig config, boolean isRunInTestCaseMode, + boolean allowMultiThread, List includeLibs, List excludeLibs) { + RunningResult tmpResult = null; + for (int i = 0; i < limit; ++i) { + tmpResult = generateResult(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); + if (!tmpResult.hasPassedTest()) { + numOfIter = i + 1; + return tmpResult; + } + } + return tmpResult; + } + + +} 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 d429c71d..80e2a0e4 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; @@ -20,12 +21,8 @@ public TraceCollector0(boolean buggy) { this.isBuggy = buggy; } - - public RunningResult runInner(String workingDir, TestCase tc, - ProjectConfig config, boolean isRunInTestCaseMode, boolean mustBeMultiThread, - 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()); @@ -33,17 +30,26 @@ public RunningResult runInner(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); 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!"); @@ -83,17 +89,23 @@ public RunningResult runInner(String workingDir, TestCase tc, // rs.setFailureType(TrialGenerator0.EXPECTED_STEP_NOT_MET); // return rs; // } - List traces = info.getTraceList(); - Trace trace = info.getMainTrace(); - trace.constructLoopParentRelation(); - trace.setSourceVersion(isBuggy); + updateTraceInfo(info); + Trace mainTrace = info.getMainTrace(); - 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, From 9602c5280217cdbe96100cc1d50a56e2b9e24f2d Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Sat, 6 Apr 2024 02:19:52 +0800 Subject: [PATCH 14/22] Change behaviour of root cause finder with node --- .../empiricalstudy/ConcurrentSimulator.java | 1 + .../empiricalstudy/RootCauseFinder.java | 3 +- .../empiricalstudy/TrialGenerator0.java | 75 +++++++++++++++++- .../handler/AllDefects4jConcHandler.java | 13 ++-- .../separatesnapshots/TraceCollector0.java | 23 ++++++ .../util/ConcurrentTraceMatcher.java | 31 ++++++-- .../views/ConcurrentBuggyTraceView.java | 77 +++++++++++++++++++ 7 files changed, 210 insertions(+), 13 deletions(-) diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index 6ce15f16..195eb6ff 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -216,6 +216,7 @@ protected EmpiricalTrial workSingleTrial(Trace buggyTrace, Trace correctTrace, P 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())){ diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java index a8f23e98..63668ca9 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java @@ -185,7 +185,8 @@ public void checkRootCauseConc(TraceNode observedFaultNode, ConcurrentTrace bugg while(!workList.isEmpty()){ TraceNodeW stepW = workList.remove(0); TraceNode step = stepW.node; - + + if (step.getBound() != null) step = step.getBound(); CausalityNode resultNode = causalityGraph.findOrCreate(step, stepW.isOnBefore); StepChangeType changeType = typeChecker.getType(step, stepW.isOnBefore, pairList, matcher); diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 3877594c..2c6060b9 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -14,8 +14,10 @@ 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; @@ -35,6 +37,7 @@ 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; @@ -54,6 +57,7 @@ public class TrialGenerator0 { 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; @@ -85,6 +89,8 @@ public static String getProblemType(int type) { 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; } @@ -92,6 +98,65 @@ public static String getProblemType(int type) { } + 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; @@ -307,7 +372,7 @@ private Set hasDeadlock(List traces) { 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(10); + TraceCollector0 buggyCollector = new BuggyTraceCollector(100); TraceCollector0 correctCollector = new TraceCollector0(false); long time1 = 0; long time2 = 0; @@ -430,11 +495,19 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat 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()); } // diff --git a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java index c117e9b9..24aefaea 100644 --- a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java +++ b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java @@ -55,11 +55,11 @@ protected IStatus run(IProgressMonitor monitor) { e1.printStackTrace(); } -// String[] projects = {"simple_defects"}; -// int[] bugNum = {1}; - String[] projects = {"Closure"}; - int[] bugNum = {50}; - + String[] projects = {"simple_defects"}; + int[] bugNum = {1}; +// String[] projects = {"Pool"}; +// int[] bugNum = {6}; +// // String[] projects = {"Lang"}; // int[] bugNum = {65}; // @@ -119,7 +119,8 @@ protected IStatus run(IProgressMonitor monitor) { 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(); diff --git a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java index 80e2a0e4..834c87e4 100644 --- a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java +++ b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java @@ -36,6 +36,22 @@ protected InstrumentationExecutor generateExecutor(String workingDir, TestCase t } + 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()); + } + + String traceDir = MicroBatUtil.generateTraceDir(config.projectName, config.regressionID); + String traceName = isBuggy ? "bug" : "fix"; + return new InstrumentationExecutor(appClassPath, + traceDir, traceName, includeLibs, excludeLibs); + + } + + + public RunningResult runInner(String workingDir, TestCase tc, ProjectConfig config, boolean isRunInTestCaseMode, boolean mustBeMultiThread, boolean allowMultiThread, @@ -83,6 +99,13 @@ public RunningResult runInner(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(); diff --git a/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java index 72b3b5ed..f0127414 100644 --- a/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java +++ b/tregression/src/main/tregression/util/ConcurrentTraceMatcher.java @@ -32,13 +32,16 @@ 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 (traceThreadIdHashMap.containsKey(trace.getInnerThreadId())) { +// if (false) { + if (trace.getInnerThreadId() != null && traceThreadIdHashMap.containsKey(trace.getInnerThreadId())) { Long prevTrace = traceThreadIdHashMap.get(trace.getInnerThreadId()); notMatchedT1.remove(prevTrace); resultMap.put(prevTrace, trace.getThreadId()); @@ -73,13 +76,13 @@ private Map heuristicMatcher(List traces1, List traces initCapCostForMCMF(traces1, traces2, s, cap, cost); mcmf.getMaxFlow(cap, cost, s-2, s-1); - List> matchEdgeList = mcmf.getSTEdgeList(0, traces1.size(), 0, traces2.size()); - + 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()); + Trace t2 = tempTraces2.get(pair.second() - traces1.size()); resultMap.put(t1.getThreadId(), t2.getThreadId()); } return resultMap; @@ -113,7 +116,8 @@ private void initCapCostForMCMF(List traces1, List traces2, int s, for (Trace trace : traces1) { int j = traces1.size(); for (Trace trace2: traces2) { - int weight = computeWeight(trace, trace2); +// 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); @@ -137,6 +141,23 @@ private void initCapCostForMCMF(List traces1, List traces2, int s, } } + 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 diff --git a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java index 8e40365c..0c8f7a5c 100644 --- a/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java +++ b/tregression/src/main/tregression/views/ConcurrentBuggyTraceView.java @@ -1,17 +1,28 @@ 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"; @@ -50,6 +61,72 @@ public String getText() { 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) { From 2c9a2a8bd69acd5eb8dadeec6465a336d34fb331 Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Sat, 6 Apr 2024 17:22:25 +0800 Subject: [PATCH 15/22] Update control dependency handling inter thread --- .../empiricalstudy/ConcurrentSimulator.java | 126 ++++++++++++++++++ .../tregression/empiricalstudy/Simulator.java | 2 +- .../handler/AllDefects4jConcHandler.java | 1 + .../handler/SeparateVersionConcHandler.java | 32 ++--- .../views/ConcurrentStepDetailUI.java | 2 +- .../views/ConcurrentStepPropertyView.java | 12 +- 6 files changed, 153 insertions(+), 22 deletions(-) diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index 195eb6ff..b83d9a7d 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -19,6 +19,7 @@ import tregression.StepChangeTypeChecker; import tregression.model.PairList; import tregression.model.StepOperationTuple; +import tregression.model.TraceNodePair; import tregression.separatesnapshots.DiffMatcher; /** @@ -195,6 +196,131 @@ else if(prevChangeType.getType()==StepChangeType.DAT){ } + + + @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) { diff --git a/tregression/src/main/tregression/empiricalstudy/Simulator.java b/tregression/src/main/tregression/empiricalstudy/Simulator.java index 517df2b0..1d0887d7 100644 --- a/tregression/src/main/tregression/empiricalstudy/Simulator.java +++ b/tregression/src/main/tregression/empiricalstudy/Simulator.java @@ -854,7 +854,7 @@ private List concurrentCreateControlRecord(TraceNode currentNode, } - private List findTheNearestCorrespondence(TraceNode domOnRef, PairList pairList, Trace buggyTrace, Trace correctTrace) { + protected List findTheNearestCorrespondence(TraceNode domOnRef, PairList pairList, Trace buggyTrace, Trace correctTrace) { List list = new ArrayList<>(); List sameLineSteps = findSameLineSteps(domOnRef); diff --git a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java index 24aefaea..651a23b3 100644 --- a/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java +++ b/tregression/src/main/tregression/handler/AllDefects4jConcHandler.java @@ -39,6 +39,7 @@ 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); diff --git a/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java b/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java index c0c61143..81d34286 100644 --- a/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java +++ b/tregression/src/main/tregression/handler/SeparateVersionConcHandler.java @@ -75,22 +75,22 @@ protected IStatus run(IProgressMonitor monitor) { System.out.println("Trial " + (i+1)); System.out.println(trials.get(i)); - EmpiricalTrial t = trials.get(i); - Trace trace = t.getBuggyTrace(); - - if(!t.getDeadEndRecordList().isEmpty()){ - Repository.clearCache(); - DeadEndRecord record = t.getDeadEndRecordList().get(0); - DED datas = record.getTransformedData(trace); -// DED datas = new TrainingDataTransfer().transfer(record, trace); - setTestCase(datas, t.getTestcase()); - try { -// new DeadEndReporter().export(datas.getAllData(), projectName, Integer.valueOf(id)); - new DeadEndCSVWriter("_d4j", null).export(datas.getAllData(), projectName, id); - } catch (NumberFormatException | IOException e) { - e.printStackTrace(); - } - } +// EmpiricalTrial t = trials.get(i); +// Trace trace = t.getBuggyTrace(); +// Commented out as it breaks during run with mismatched trace +// if(!t.getDeadEndRecordList().isEmpty()){ +// Repository.clearCache(); +// DeadEndRecord record = t.getDeadEndRecordList().get(0); +// DED datas = record.getTransformedData(trace); +//// DED datas = new TrainingDataTransfer().transfer(record, trace); +// setTestCase(datas, t.getTestcase()); +// try { +//// new DeadEndReporter().export(datas.getAllData(), projectName, Integer.valueOf(id)); +// new DeadEndCSVWriter("_d4j", null).export(datas.getAllData(), projectName, id); +// } catch (NumberFormatException | IOException e) { +// e.printStackTrace(); +// } +// } } diff --git a/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java b/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java index f4d28683..7fabd4c6 100644 --- a/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java +++ b/tregression/src/main/tregression/views/ConcurrentStepDetailUI.java @@ -103,7 +103,7 @@ public void mouseDown(MouseEvent e) { } } else if(controlButton.getSelection()){ - suspiciousNode = currentNode.getInvocationMethodOrDominator(); + suspiciousNode = currentNode.getBound().getInvocationMethodOrDominator(); } if(suspiciousNode != null){ diff --git a/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java b/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java index 2e6545df..162fe97b 100644 --- a/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java +++ b/tregression/src/main/tregression/views/ConcurrentStepPropertyView.java @@ -76,11 +76,15 @@ else if(view instanceof ConcurrentCorrectTraceView){ } public void refreshConc(TraceNode correctNode, TraceNode buggyNode, DiffMatcher diffMatcher, PairList pairList){ - if (buggyNode == null || correctNode == null) { - return; + + Trace buggyTrace = null; + if (buggyNode != null) { + buggyTrace = buggyNode.getTrace(); + } + Trace correctTrace = null; + if (correctNode != null) { + correctTrace = correctNode.getTrace(); } - Trace buggyTrace = buggyNode.getTrace(); - Trace correctTrace = correctNode.getTrace(); StepChangeTypeChecker checker = new StepChangeTypeChecker(buggyTrace, correctTrace); if(buggyDetailUI != null && buggyNode != null) { From 56bb86c38f3862bccc24664020d82abf9d9eab49 Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Sat, 6 Apr 2024 18:57:55 +0800 Subject: [PATCH 16/22] Fix wrong function call --- .../main/tregression/empiricalstudy/ConcurrentSimulator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index b83d9a7d..c804ba3b 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -507,7 +507,7 @@ public List detectMutatedBug(Trace buggyTrace, Trace correctTrac RootCauseFinder finder = new RootCauseFinder(); long start = System.currentTimeMillis(); - finder.checkRootCause(observedFault, buggyTrace, correctTrace, pairList, matcher); + finder.checkRootCauseConc(observedFault, (ConcurrentTrace) buggyTrace, (ConcurrentTrace) correctTrace, pairList, matcher); long end = System.currentTimeMillis(); int checkTime = (int) (end-start); From ce6684ae1d4de4ecd890cc5906918996301056dd Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Sat, 6 Apr 2024 21:32:40 +0800 Subject: [PATCH 17/22] Fix minor bugs --- .../src/main/tregression/StepChangeType.java | 8 +- .../empiricalstudy/ConcurrentSimulator.java | 110 +++++++++++++++++- .../empiricalstudy/RootCauseFinder.java | 24 ++++ 3 files changed, 134 insertions(+), 8 deletions(-) diff --git a/tregression/src/main/tregression/StepChangeType.java b/tregression/src/main/tregression/StepChangeType.java index c7b9c7df..dcb97701 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; diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index c804ba3b..d3111783 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -3,17 +3,27 @@ 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; @@ -55,7 +65,7 @@ public void prepareConc(List buggyTraces, } } - private List startSimulationConc(TraceNode observedFaultNode, Trace buggyTrace, Trace correctTrace, + 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<>(); @@ -67,15 +77,107 @@ private List startSimulationConc(TraceNode observedFaultNode, Tr return trials; } - protected EmpiricalTrial workSingleTrialConc(Trace buggyTrace, Trace correctTrace, PairList pairList, DiffMatcher matcher, + 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())); + StepChangeType changeType = typeChecker.getType(currentNode, true, 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 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)); + } + 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 */ @@ -516,7 +618,7 @@ public List detectMutatedBug(Trace buggyTrace, Trace correctTrac trials = startSimulationWithCachedState(observedFault, buggyTrace, correctTrace, getPairList(), matcher, finder); } else { - trials = startSimulationConc(observedFault, buggyTrace, correctTrace, getPairList(), matcher, finder); + trials = startSimulationConc(observedFault, (ConcurrentTrace) buggyTrace, (ConcurrentTrace) correctTrace, getPairList(), matcher, finder); } if(trials!=null) { diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java index 63668ca9..0e7519c8 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java @@ -9,6 +9,7 @@ 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.Trace; @@ -168,9 +169,24 @@ public void setRootCauseBasedOnDefects4J(PairList pairList, DiffMatcher matcher, private CausalityGraph causalityGraph; + private ArrayList nodes; + + public List getConcNodes() { + return nodes; + } + + 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(); @@ -211,9 +227,12 @@ else if(changeType.getType()==StepChangeType.DAT){ 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); @@ -222,6 +241,7 @@ else if(changeType.getType()==StepChangeType.DAT){ 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); } @@ -250,6 +270,7 @@ else if(controlDom!=null && !controlDom.isConditional() && controlDom.isBranch() } } 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); @@ -259,11 +280,14 @@ else if(controlDom!=null && !controlDom.isConditional() && controlDom.isBranch() 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; From 7c8743dc2d31482b60789b38bdc8fe2fc7db8b65 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Sat, 6 Apr 2024 23:10:40 +0800 Subject: [PATCH 18/22] Fix minor bugs --- tregression/src/main/tregression/StepChangeType.java | 1 + .../tregression/empiricalstudy/ConcurrentSimulator.java | 4 ++-- .../main/tregression/empiricalstudy/RootCauseFinder.java | 7 +++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tregression/src/main/tregression/StepChangeType.java b/tregression/src/main/tregression/StepChangeType.java index dcb97701..4d8ab221 100644 --- a/tregression/src/main/tregression/StepChangeType.java +++ b/tregression/src/main/tregression/StepChangeType.java @@ -93,6 +93,7 @@ public VarValue getWrongVariable(TraceNode node, boolean isOnBefore, RootCauseFi 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/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index d3111783..c4de5855 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -93,8 +93,8 @@ public StepOperationTuple fromConcNode(ConcNode concNode, ConcurrentTrace buggyT case StepChangeType.DAT: // handle the data feedback = new UserFeedback(UserFeedback.WRONG_VARIABLE_VALUE); - TraceNode currentNode = ((ConcurrentTraceNode)trace.getTraceNode(concNode.getNode1())); - StepChangeType changeType = typeChecker.getType(currentNode, true, pairList, matcher); + 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: diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java index 0e7519c8..4b9e727d 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java @@ -12,6 +12,7 @@ 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; @@ -202,7 +203,9 @@ public void checkRootCauseConc(TraceNode observedFaultNode, ConcurrentTrace bugg TraceNodeW stepW = workList.remove(0); TraceNode step = stepW.node; - if (step.getBound() != null) step = step.getBound(); + if (step instanceof ConcurrentTraceNode) { + step = ((ConcurrentTraceNode) step).getInitialTraceNode(); + } CausalityNode resultNode = causalityGraph.findOrCreate(step, stepW.isOnBefore); StepChangeType changeType = typeChecker.getType(step, stepW.isOnBefore, pairList, matcher); @@ -250,7 +253,7 @@ else if(changeType.getType()==StepChangeType.DAT){ } else if(changeType.getType()==StepChangeType.CTL){ - TraceNode controlDom = step.getInvocationMethodOrDominator(); + TraceNode controlDom = step.getBound().getInvocationMethodOrDominator(); if(step.insideException()){ controlDom = step.getStepInPrevious(); } From 07cf7b07fd97dc2d6692f8d68851b8a8f9b4e183 Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Sun, 7 Apr 2024 11:27:47 +0800 Subject: [PATCH 19/22] Update regression node list in simulator bfs --- .../empiricalstudy/ConcurrentSimulator.java | 21 ++++++++++++++++++- .../empiricalstudy/RootCauseFinder.java | 4 ++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java index c4de5855..962d51c4 100644 --- a/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java +++ b/tregression/src/main/tregression/empiricalstudy/ConcurrentSimulator.java @@ -77,6 +77,10 @@ private List startSimulationConc(TraceNode observedFaultNode, Co 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) { @@ -120,6 +124,11 @@ protected EmpiricalTrial workSingleTrialConc(ConcurrentTrace buggyTrace, 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<>(); @@ -165,11 +174,21 @@ protected EmpiricalTrial workSingleTrialConc(ConcurrentTrace buggyTrace, 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(), diff --git a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java index 4b9e727d..8a5d1a1b 100644 --- a/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java +++ b/tregression/src/main/tregression/empiricalstudy/RootCauseFinder.java @@ -176,6 +176,10 @@ 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) { From 39b56a5b697c823bed88978f3d98edcf2554a056 Mon Sep 17 00:00:00 2001 From: "DESKTOP-5JKAH8G\\Gabriel" Date: Sun, 7 Apr 2024 14:40:20 +0800 Subject: [PATCH 20/22] Add force junit3Or4 option --- .../src/main/tregression/model/StepOperationTuple.java | 8 ++++++-- .../separatesnapshots/BuggyTraceCollector.java | 1 + .../tregression/separatesnapshots/TraceCollector0.java | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) 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/separatesnapshots/BuggyTraceCollector.java b/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java index adccccdc..80ad5200 100644 --- a/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java +++ b/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java @@ -20,6 +20,7 @@ public class BuggyTraceCollector extends TraceCollector0 { public BuggyTraceCollector(int limit) { super(true); + isForceJunit3Or4 = true; this.limit = limit; // TODO Auto-generated constructor stub } diff --git a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java index 834c87e4..3b3c18e5 100644 --- a/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java +++ b/tregression/src/main/tregression/separatesnapshots/TraceCollector0.java @@ -16,7 +16,7 @@ public class TraceCollector0 { private boolean isBuggy; - + protected boolean isForceJunit3Or4 = false; public TraceCollector0(boolean buggy) { this.isBuggy = buggy; } @@ -58,6 +58,7 @@ public RunningResult runInner(String workingDir, TestCase tc, List includeLibs, List excludeLibs){ InstrumentationExecutor executor = generateExecutor(workingDir, tc, config, isRunInTestCaseMode, includeLibs, excludeLibs); + executor.setIsForceJunit3Or4(this.isForceJunit3Or4); RunningInfo info = null; try { info = executor.run(); From bcbcc3acda7324054882b4ad9aa1206fddf8a318 Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Tue, 9 Apr 2024 15:19:26 +0800 Subject: [PATCH 21/22] Fix alternate trace collectors --- .../empiricalstudy/TrialGenerator0.java | 18 +++++- .../BuggyRnRTraceCollector.java | 60 +++++++++++++++---- .../BuggyTraceCollector.java | 20 +++---- 3 files changed, 75 insertions(+), 23 deletions(-) diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index 2c6060b9..ec01a31d 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -372,7 +372,7 @@ private Set hasDeadlock(List traces) { 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 buggyCollector = new BuggyRnRTraceCollector(100); TraceCollector0 correctCollector = new TraceCollector0(false); long time1 = 0; long time2 = 0; @@ -424,7 +424,8 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat Settings.compilationUnitMap.clear(); Settings.iCompilationUnitMap.clear(); - buggyRS = buggyCollector.runForceMultithreaded(buggyPath, tc, config, isRunInTestCaseMode, includedClassNames, excludedClassNames); + buggyRS = buggyCollector.run(buggyPath, tc, config, isRunInTestCaseMode, true, includedClassNames, excludedClassNames); +// buggyRS = buggyCollector.runForceMultithreaded(buggyPath, tc, config, isRunInTestCaseMode, includedClassNames, excludedClassNames); if (buggyRS.getRunningType() != NORMAL) { trial = EmpiricalTrial.createDumpTrial(getProblemType(buggyRS.getRunningType())); trial.setTestcase(tc.testClass + "#" + tc.testMethod); @@ -510,7 +511,18 @@ private EmpiricalTrial analyzeConcurrentTestCase(String buggyPath, String fixPat } 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); diff --git a/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java b/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java index bb905429..3b8928f1 100644 --- a/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java +++ b/tregression/src/main/tregression/separatesnapshots/BuggyRnRTraceCollector.java @@ -15,6 +15,7 @@ import microbat.util.Settings; import sav.strategies.dto.AppJavaClassPath; import tregression.empiricalstudy.TestCase; +import tregression.empiricalstudy.TrialGenerator0; import tregression.empiricalstudy.config.ProjectConfig; /** @@ -36,39 +37,78 @@ protected RunningResult generateResult(String workingDir, TestCase tc, ProjectCo 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); - StorableReader reader = new StorableReader(concDumpFile); - reader.read(); - String programMsgString = reader.getProgramMsg(); - // when it is a fail - if (!MicrobatUtils.checkTestResult(programMsgString)) { - firstIter = i + 1; - break; + 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(workingDir, concDumpFileString, Settings.stepLimit); - if (!MicrobatUtils.checkTestResult(resultInfo.getProgramMsg())) { + 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 diff --git a/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java b/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java index 80ad5200..f7e945c8 100644 --- a/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java +++ b/tregression/src/main/tregression/separatesnapshots/BuggyTraceCollector.java @@ -28,22 +28,22 @@ public BuggyTraceCollector(int limit) { protected RunningResult generateResult(String workingDir, TestCase tc, ProjectConfig config, boolean isRunInTestCaseMode, boolean allowMultiThread, List includeLibs, List excludeLibs) { - return super.run(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); - } - - @Override - public RunningResult run(String workingDir, TestCase tc, ProjectConfig config, boolean isRunInTestCaseMode, - boolean allowMultiThread, List includeLibs, List excludeLibs) { - RunningResult tmpResult = null; + RunningResult tmpResult = super.run(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); for (int i = 0; i < limit; ++i) { - tmpResult = generateResult(workingDir, tc, config, isRunInTestCaseMode, allowMultiThread, includeLibs, excludeLibs); if (!tmpResult.hasPassedTest()) { - numOfIter = i + 1; - return tmpResult; + 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); + } } From fed8b1bb26c64cc254580931c486889d85e079c2 Mon Sep 17 00:00:00 2001 From: "Au Chen Xi, Gabriel" Date: Tue, 9 Apr 2024 16:17:01 +0800 Subject: [PATCH 22/22] Switch to trace collector --- .../src/main/tregression/empiricalstudy/TrialGenerator0.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java index ec01a31d..b32a6fcd 100644 --- a/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java +++ b/tregression/src/main/tregression/empiricalstudy/TrialGenerator0.java @@ -372,7 +372,7 @@ private Set hasDeadlock(List traces) { 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 BuggyRnRTraceCollector(100); + TraceCollector0 buggyCollector = new BuggyTraceCollector(100); TraceCollector0 correctCollector = new TraceCollector0(false); long time1 = 0; long time2 = 0;