From 3e303a5d1ded591fce59b7deadfe1660a458fbca Mon Sep 17 00:00:00 2001 From: Moustafa Ismail Date: Sun, 12 Nov 2023 06:14:02 +0000 Subject: [PATCH 1/7] Graph building for method first run is optimized --- .../starts/constants/StartsConstants.java | 1 + .../MethodLevelStaticDepsBuilder.java | 185 ++++++++++++++++++ .../illinois/starts/jdeps/MethodsMojo.java | 53 ++--- 3 files changed, 215 insertions(+), 24 deletions(-) diff --git a/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java b/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java index b68c9f24..bdf3d883 100644 --- a/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java +++ b/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java @@ -67,6 +67,7 @@ public interface StartsConstants { String TARGET = "target"; String METHODS_TEST_DEPS_ZLC_FILE = "methods-deps.zlc"; String METHODS_CHECKSUMS_SERIALIZED_FILE = "methods-checksums.ser"; + String METHODS_DEPENDENCIES_SERIALIZED_FILE = "methods-dependencies.ser"; String CLASSES_ZLC_FILE = "classes-checksums.zlc"; String CLASSES_CHECKSUM_SERIALIZED_FILE = "classes-checksums.ser"; diff --git a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java index e471c9e8..cbc45413 100644 --- a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java +++ b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java @@ -77,6 +77,191 @@ public class MethodLevelStaticDepsBuilder { private static final Logger LOGGER = Logger.getGlobal(); + private static HashSet class_paths = null; + + private static Map classNameToPathMap = null; + + /* + * This function returns all the classes' paths in the project. + */ + public static HashSet getAllClassesPaths() { + if (class_paths != null) { + return class_paths; + } + try { + class_paths = new HashSet<>(Files.walk(Paths.get(".")) + .filter(Files::isRegularFile) + .filter(f -> (f.toString().endsWith(".class") && f.toString().contains("target"))) + .map(f -> f.normalize().toAbsolutePath().toString()) + .collect(Collectors.toList())); + } catch (Exception e) { + e.printStackTrace(); + } + return class_paths; + } + + /* + * This function returns a map from class name to class path. + * e.g., com/example/A -> + * /home/mopuser/earv-research/starts-example/target/classes/com/example/A.class + */ + public static Map getClassNameToPathMap() { + if (classNameToPathMap != null) { + return classNameToPathMap; + } + classNameToPathMap = new HashMap<>(); + for (String classPath : getAllClassesPaths()) { + String className = getClassNameFromClassPath(classPath); + classNameToPathMap.put(className, classPath); + } + return classNameToPathMap; + } + + /* + * This function returns all the classes' Names in the project. + */ + public static HashSet getAllClassesNames() { + HashSet classPaths = getAllClassesPaths(); + HashSet classes = new HashSet<>(); + for (String classPath : classPaths) { + String className = getClassNameFromClassPath(classPath); + classes.add(className); + } + return classes; + } + + /* + * This function returns the class name from the class path. + * e.g., + * /home/mopuser/earv-research/starts-example/target/classes/com/example/B.class + * -> com/example/B + */ + public static String getClassNameFromClassPath(String classPath) { + String className = classPath.substring(classPath.indexOf("classes/") + "classes/".length(), + classPath.length() - ".class".length()); + return className; + } + + /* + * This function returns the classes' paths for set of classes' names. + */ + public static Set getClassPathsForSetOfClassNames(Set classesNames) { + Set classesPaths = new HashSet<>(); + Map classNameToPathMap = getClassNameToPathMap(); + for (String className : classesNames) { + String classPath = classNameToPathMap.get(className); + classesPaths.add(classPath); + } + return classesPaths; + } + + /* + * This function returns the class path for the given class name. + */ + public static String getClassPathForClassName(String className) { + String classPath = null; + Map classNameToPathMap = getClassNameToPathMap(); + classPath = classNameToPathMap.get(className); + return classPath; + } + + /* + * This function computes methods checksums for all the methods in the project. + * It returns a map containing them. + */ + public static Map computeAllMethodsChecksums() { + HashSet classPaths = getAllClassesPaths(); + Map computedMethodsChecksums = new HashMap<>(); + for (String classPath : classPaths) { + + ClassNode node = new ClassNode(Opcodes.ASM5); + ClassReader reader = null; + try { + reader = new ClassReader(new FileInputStream(classPath)); + } catch (IOException exception) { + LOGGER.log(Level.INFO, "[ERROR] reading class: " + classPaths); + continue; + } + + String methodChecksum = null; + reader.accept(node, ClassReader.SKIP_DEBUG); + List methods = node.methods; + String className = node.name; + + // Looping over all the methods in the class, and computing the checksum for + // each method + for (MethodNode method : methods) { + String methodContent = ZLCHelperMethods.printMethodContent(method); + try { + methodChecksum = ChecksumUtil.computeStringChecksum(methodContent); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + computedMethodsChecksums.put( + className + "#" + method.name + method.desc.substring(0, method.desc.indexOf(")") + 1), + methodChecksum); + } + } + return computedMethodsChecksums; + } + + /* + * This function builds the method dependency graph for all the methods in the + * project. + */ + public static Map> buildMethodsDependencyGraph(HashSet classPathsSet, + boolean includeVariables, + boolean includeTestMethods) { + findMethodsinvoked(classPathsSet); + if (includeTestMethods) { + // Suppose that test classes have Test in their class name + // and are in src/test + Set testClasses = new HashSet<>(); + for (String method : methodNameToMethodNames.keySet()) { + String className = method.split("#|\\$")[0]; + if (className.contains("Test")) { + testClasses.add(className); + } + } + + // Finding Test Classes to methods + testClassesToMethods = getDepsSingleThread(testClasses); + } + + addReflexiveClosure(methodNameToMethodNames); + /* + * Adding reflexive closure to methodNameToMethodNames + * A -> B + * It will be: + * A -> A, B + */ + addReflexiveClosure(methodNameToMethodNames); + + // Inverting methodNameToMethodNames to have the dependency graph for each + // method + // methodNameToMethodNames = invertMap(methodNameToMethodNames); + methodDependencyGraph = invertMap(methodNameToMethodNames); + + if (includeVariables) { + /* + * The original dependency graph is like this: + * (A, B, C) are classes + * (a) is a variable + * A -> A, B, C + * a -> A + * After this function call the dependency graph will be like this: + * A -> A, B, C, a + * a -> A + */ + addVariableDepsToDependencyGraph(); + } else { + // Remove any variables from keys or values i.e. pure method-level deps + filterVariables(); + } + + return null; + } + /** * This function builds the method dependency graph for all the methods in the * project. diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java index 1f800f20..e8a659de 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java @@ -44,6 +44,7 @@ public class MethodsMojo extends DiffMojo { private Map methodsCheckSum; private Map> methodToTestClasses; private ClassLoader loader; + private Map> methodsDependencyGraph; /** * Set this to "true" to compute impacted methods as well. False indicates only @@ -147,17 +148,7 @@ public void execute() throws MojoExecutionException { logger = Logger.getGlobal(); Classpath sfClassPath = getSureFireClassPath(); loader = createClassLoader(sfClassPath); - - // Build method level static dependencies - try { - MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); - methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(); - methodsCheckSum = MethodLevelStaticDepsBuilder.computeMethodsChecksum(loader); - } catch (Exception exception) { - throw new RuntimeException(exception); - } - - runMethods(computeImpactedMethods); + runMethods(); } /** @@ -172,27 +163,33 @@ public void execute() throws MojoExecutionException { * It also updates the methods checksums in the dependency file if * updateMethodsChecksums is true. * - * @param impacted a boolean value indicating whether to compute impacted - * methods and impacted test classes * @throws MojoExecutionException if an exception occurs while setting changed * methods */ - protected void runMethods(boolean impacted) throws MojoExecutionException { - + protected void runMethods() throws MojoExecutionException { // Checking if the file of depedencies exists (first run or not) if (!Files.exists(Paths.get(getArtifactsDir() + METHODS_CHECKSUMS_SERIALIZED_FILE))) { + // Compute Methods Checksums and Build the method level dependencies graph + try { + methodsCheckSum = MethodLevelStaticDepsBuilder.computeAllMethodsChecksums(); + HashSet classesPathsSet = MethodLevelStaticDepsBuilder.getAllClassesPaths(); + methodsDependencyGraph = MethodLevelStaticDepsBuilder.buildMethodsDependencyGraph(classesPathsSet, includeVariables, computeAffectedTests); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + changedMethods = new HashSet<>(); - newMethods = MethodLevelStaticDepsBuilder.computeMethods(); + newMethods = methodsCheckSum.keySet(); oldClasses = new HashSet<>(); changedClasses = new HashSet<>(); - newClasses = MethodLevelStaticDepsBuilder.getClasses(); + newClasses = MethodLevelStaticDepsBuilder.getAllClassesNames(); nonAffectedMethods = new HashSet<>(); if (computeAffectedTests) { affectedTestClasses = MethodLevelStaticDepsBuilder.computeTestClasses(); } - if (impacted) { + if (computeImpactedMethods) { impactedMethods = newMethods; } @@ -200,15 +197,25 @@ protected void runMethods(boolean impacted) throws MojoExecutionException { try { ZLCHelperMethods.serializeMapping(methodsCheckSum, getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); + ZLCHelperMethods.serializeMapping(methodsDependencyGraph, getArtifactsDir(), METHODS_DEPENDENCIES_SERIALIZED_FILE); } catch (IOException exception) { exception.printStackTrace(); } } else { + // Build method level static dependencies + try { + MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); + methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(); + methodsCheckSum = MethodLevelStaticDepsBuilder.computeMethodsChecksum(loader); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + // First run has saved the old revision's checksums. Time to find changes. computeChangedMethods(); - if (impacted) { + if (computeImpactedMethods) { computeImpactedMethods(); } @@ -226,7 +233,7 @@ protected void runMethods(boolean impacted) throws MojoExecutionException { } } - logInfoStatements(impacted); + logInfoStatements(); } /** @@ -234,14 +241,12 @@ protected void runMethods(boolean impacted) throws MojoExecutionException { * impacted test classes, new classes, old classes and changed classes. * If impacted is true, it also logs information about impacted methods. * - * @param impacted a boolean value indicating whether to log information about - * impacted methods */ - private void logInfoStatements(boolean impacted) { + private void logInfoStatements() { logger.log(Level.INFO, "ChangedMethods: " + changedMethods.size()); logger.log(Level.INFO, "NewMethods: " + newMethods.size()); - if (impacted) { + if (computeImpactedMethods) { logger.log(Level.INFO, "ImpactedMethods: " + impactedMethods.size()); } From f48b147cc7dda24f24ee8d70ee92fe1f44af94d8 Mon Sep 17 00:00:00 2001 From: Moustafa Ismail Date: Sun, 12 Nov 2023 08:06:11 +0000 Subject: [PATCH 2/7] Optimizing method dependency graph building for methods in completed and testes --- .../starts/helpers/ZLCHelperMethods.java | 18 ++-- .../MethodLevelStaticDepsBuilder.java | 100 +++++++++++++++--- .../edu/illinois/starts/jdeps/HybridMojo.java | 6 +- .../illinois/starts/jdeps/MethodsMojo.java | 42 ++++---- 4 files changed, 114 insertions(+), 52 deletions(-) diff --git a/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java b/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java index 07392ba2..783f2e80 100644 --- a/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java +++ b/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java @@ -47,18 +47,15 @@ public class ZLCHelperMethods implements StartsConstants { * @param artifactsDir The directory where the serialized file is saved. * @param newMethodsChecksums A map containing the method names and their * checksums. - * @param methodToTestClasses A map from method names to their test classes/ * @return A list of sets containing all the information described above. */ - public static List> getChangedDataMethods(Map newMethodsChecksums, - Map> methodToTestClasses, String artifactsDir, String filepath) { + public static List> getChangedDataMethods(Map newMethodsChecksums, String artifactsDir, + String filepath) { long start = System.currentTimeMillis(); Map oldMethodChecksums = deserializeMapping(artifactsDir, filepath); - Set changedMethods = new HashSet<>(); - Set affectedTests = new HashSet<>(); Set oldClasses = new HashSet<>(); Set changedClasses = new HashSet<>(); Set newMethods = new HashSet<>(newMethodsChecksums.keySet()); @@ -66,7 +63,6 @@ public static List> getChangedDataMethods(Map newMet for (String method : oldMethodChecksums.keySet()) { String oldChecksum = oldMethodChecksums.get(method); String newChecksum = newMethodsChecksums.get(method); - Set deps = methodToTestClasses.getOrDefault(method, new HashSet<>()); String className = method.split("#")[0]; oldClasses.add(className); @@ -77,7 +73,6 @@ public static List> getChangedDataMethods(Map newMet continue; } else { changedMethods.add(method); - affectedTests.addAll(deps); changedClasses.add(className); } } @@ -87,7 +82,7 @@ public static List> getChangedDataMethods(Map newMet for (String method : newMethods) { changedClasses.add(method.split("#")[0]); } - Collections.addAll(result, changedMethods, newMethods, affectedTests, oldClasses, changedClasses); + Collections.addAll(result, changedMethods, newMethods, oldClasses, changedClasses); LOGGER.log(Level.FINEST, TIME_COMPUTING_NON_AFFECTED + (end - start) + MILLISECOND); return result; } @@ -129,7 +124,8 @@ public static List> getChangedDataHybridClassLevel(Map> getChangedDataHybridMethodLevel(Set addedClasses, Set deletedClasses, + public static List> getChangedDataHybridMethodLevel(Set addedClasses, + Set deletedClasses, Set changedClassesWithChangedHeaders, Set changedClassesWithoutChangedHeaders, Map methodChecksums, ClassLoader loader, @@ -147,11 +143,9 @@ public static List> getChangedDataHybridMethodLevel(Set adde Map changedClassesWithoutChangedHeadersMethodsChecksums = MethodLevelStaticDepsBuilder .getMethodsChecksumsForClasses(changedClassesWithoutChangedHeaders, loader); - List> changedAndNewMethodsForMethodAnalysis = findChangedAndNewMethods(oldMethodsChecksums, changedClassesWithoutChangedHeadersMethodsChecksums); - // Constructing a methods checksums map for next run Set modifiedOldClasses = new HashSet<>(); modifiedOldClasses.addAll(deletedClasses); @@ -313,7 +307,7 @@ public static void serializeMapping(Map map, String artifactsDir, * found. */ @SuppressWarnings("unchecked") - private static Map deserializeMapping(String artifactsDir, String filename) { + public static Map deserializeMapping(String artifactsDir, String filename) { Map map = new HashMap<>(); try { FileInputStream fis = new FileInputStream(artifactsDir + filename); diff --git a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java index cbc45413..bda627cc 100644 --- a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java +++ b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java @@ -54,7 +54,7 @@ public class MethodLevelStaticDepsBuilder { // for every class, find its children. public static Map> hierarchyChildren = new HashMap<>(); - public static Map> testClassesToMethods = new HashMap<>(); + public static Map> testClassesToMethods = null; public static Map> testClassesToClasses = new HashMap<>(); @@ -81,6 +81,8 @@ public class MethodLevelStaticDepsBuilder { private static Map classNameToPathMap = null; + private static Map> OldMethodNameToMethodName = null; + /* * This function returns all the classes' paths in the project. */ @@ -209,9 +211,11 @@ public static Map computeAllMethodsChecksums() { * This function builds the method dependency graph for all the methods in the * project. */ - public static Map> buildMethodsDependencyGraph(HashSet classPathsSet, + public static Map> buildMethodsDependencyGraph( boolean includeVariables, boolean includeTestMethods) { + + Set classPathsSet = getAllClassesPaths(); findMethodsinvoked(classPathsSet); if (includeTestMethods) { // Suppose that test classes have Test in their class name @@ -228,7 +232,6 @@ public static Map> buildMethodsDependencyGraph(HashSet B @@ -239,7 +242,6 @@ public static Map> buildMethodsDependencyGraph(HashSet> buildMethodsDependencyGraph(HashSet> buildMethodsDependencyGraphUsingOldGraphAndChangedClasses( + Map> oldMethodsDependencyGraph, Set changedClasses, Set newClasses, + boolean includeVariables, boolean includeTestMethods) { + Set newAndChangedClasses = new HashSet<>(changedClasses); + newAndChangedClasses.addAll(newClasses); + Set classesPathSet = getClassPathsForSetOfClassNames(newAndChangedClasses); + findMethodsinvoked(classesPathSet); + OldMethodNameToMethodName = invertMap(oldMethodsDependencyGraph); + + methodNameToMethodNames + .forEach((key, value) -> OldMethodNameToMethodName.merge(key, value, (oldValue, newValue) -> newValue)); + methodNameToMethodNames = OldMethodNameToMethodName; + + addReflexiveClosure(methodNameToMethodNames); + methodDependencyGraph = invertMap(methodNameToMethodNames); + + if (includeVariables) { + /* + * The original dependency graph is like this: + * (A, B, C) are classes + * (a) is a variable + * A -> A, B, C + * a -> A + * After this function call the dependency graph will be like this: + * A -> A, B, C, a + * a -> A + */ + addVariableDepsToDependencyGraph(); + } else { + // Remove any variables from keys or values i.e. pure method-level deps + filterVariables(methodDependencyGraph); } - return null; + return methodDependencyGraph; } /** @@ -320,7 +362,7 @@ public static void buildMethodsGraph(boolean includeVariables) throws Exception addVariableDepsToDependencyGraph(); } else { // Remove any variables from keys or values i.e. pure method-level deps - filterVariables(); + filterVariables(methodDependencyGraph); } } @@ -381,12 +423,37 @@ public static Map getMethodsCheckSum() { return methodsCheckSum; } + public static Map> computeTestClassesToMethod(boolean includeVariables) { + if (testClassesToMethods == null) { + // Suppose that test classes have Test in their class name + // and are in src/test + Set testClasses = new HashSet<>(); + for (String method : methodNameToMethodNames.keySet()) { + String className = method.split("#|\\$")[0]; + if (className.contains("Test")) { + testClasses.add(className); + } + } + // Finding Test Classes to methods + testClassesToMethods = getDepsSingleThread(testClasses); + } + + if (!includeVariables) { + filterVariables(testClassesToMethods); + } + + return testClassesToMethods; + } + /** * This function Computes and returns the methodToTestClasses map. - * + * * @return methodToTestClasses method to test classes mapping */ - public static Map> computeMethodToTestClasses() { + public static Map> computeMethodToTestClasses(boolean includeVariables) { + if (testClassesToMethods == null) { + testClassesToMethods = computeTestClassesToMethod(includeVariables); + } methodToTestClasses = invertMap(testClassesToMethods); return methodToTestClasses; } @@ -847,8 +914,11 @@ public static void addReflexiveClosure(Map> mapToAddReflexiv * * @return testClasses */ - public static Set computeTestClasses() { + public static Set computeTestClasses(boolean includeVariables) { Set testClasses = new HashSet<>(); + if (testClassesToMethods == null) { + computeTestClassesToMethod(includeVariables); + } for (String testClass : testClassesToMethods.keySet()) { testClasses.add(testClass); } @@ -873,16 +943,12 @@ public static Set computeMethods() { * * @return testMethods */ - public static void filterVariables() { + public static void filterVariables(Map> mapToFilter) { // Filter out keys that are variables. - methodDependencyGraph.keySet().removeIf(method -> !method.matches(".*\\(.*\\)")); + mapToFilter.keySet().removeIf(method -> !method.matches(".*\\(.*\\)")); // Filter values of methodName2MethodNames - methodDependencyGraph.values() - .forEach(methodList -> methodList.removeIf(method -> !method.matches(".*\\(.*\\)"))); - - // Filter from test2methods - testClassesToMethods.values() + mapToFilter.values() .forEach(methodList -> methodList.removeIf(method -> !method.matches(".*\\(.*\\)"))); } diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java index c21e9fb6..13169ddc 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java @@ -173,7 +173,7 @@ public void execute() throws MojoExecutionException { classesChecksum = MethodLevelStaticDepsBuilder.computeClassesChecksums(loader, cleanBytes); if (computeAffectedTests) { - methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(); + methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(includeVariables); } } catch (Exception exception) { throw new RuntimeException(exception); @@ -217,7 +217,7 @@ protected void runHybrid(boolean impacted) throws MojoExecutionException { nonAffectedMethods = new HashSet<>(); if (computeAffectedTests) { - affectedTestClasses = MethodLevelStaticDepsBuilder.computeTestClasses(); + affectedTestClasses = MethodLevelStaticDepsBuilder.computeTestClasses(includeVariables); } if (impacted) { @@ -244,7 +244,7 @@ protected void runHybrid(boolean impacted) throws MojoExecutionException { MethodLevelStaticDepsBuilder.constuctTestClassesToClassesGraph(); if (computeAffectedTests) { classToTestClassGraph = MethodLevelStaticDepsBuilder.constructClassesToTestClassesGraph(); - methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(); + methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(includeVariables); affectedTestClasses = new HashSet<>(); } diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java index e8a659de..c9345232 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java @@ -172,8 +172,8 @@ protected void runMethods() throws MojoExecutionException { // Compute Methods Checksums and Build the method level dependencies graph try { methodsCheckSum = MethodLevelStaticDepsBuilder.computeAllMethodsChecksums(); - HashSet classesPathsSet = MethodLevelStaticDepsBuilder.getAllClassesPaths(); - methodsDependencyGraph = MethodLevelStaticDepsBuilder.buildMethodsDependencyGraph(classesPathsSet, includeVariables, computeAffectedTests); + methodsDependencyGraph = MethodLevelStaticDepsBuilder.buildMethodsDependencyGraph( + includeVariables, computeAffectedTests); } catch (Exception exception) { throw new RuntimeException(exception); } @@ -186,7 +186,7 @@ protected void runMethods() throws MojoExecutionException { nonAffectedMethods = new HashSet<>(); if (computeAffectedTests) { - affectedTestClasses = MethodLevelStaticDepsBuilder.computeTestClasses(); + affectedTestClasses = MethodLevelStaticDepsBuilder.computeTestClasses(includeVariables); } if (computeImpactedMethods) { @@ -197,24 +197,33 @@ protected void runMethods() throws MojoExecutionException { try { ZLCHelperMethods.serializeMapping(methodsCheckSum, getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); - ZLCHelperMethods.serializeMapping(methodsDependencyGraph, getArtifactsDir(), METHODS_DEPENDENCIES_SERIALIZED_FILE); + ZLCHelperMethods.serializeMapping(methodsDependencyGraph, getArtifactsDir(), + METHODS_DEPENDENCIES_SERIALIZED_FILE); } catch (IOException exception) { exception.printStackTrace(); } } else { - // Build method level static dependencies + // Compute Methods Checksums try { - MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); - methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(); - methodsCheckSum = MethodLevelStaticDepsBuilder.computeMethodsChecksum(loader); + methodsCheckSum = MethodLevelStaticDepsBuilder.computeAllMethodsChecksums(); } catch (Exception exception) { throw new RuntimeException(exception); } // First run has saved the old revision's checksums. Time to find changes. + // It finds Changed Methods, new Methods, old classes, changed classes, new + // classes. computeChangedMethods(); + // Readind old method graph + Map> oldMethodsDependencyGraph = ZLCHelperMethods.deserializeMapping(getArtifactsDir(), + METHODS_DEPENDENCIES_SERIALIZED_FILE); + + methodsDependencyGraph = MethodLevelStaticDepsBuilder + .buildMethodsDependencyGraphUsingOldGraphAndChangedClasses(oldMethodsDependencyGraph, + changedClasses, newClasses, includeVariables, computeAffectedTests); + if (computeImpactedMethods) { computeImpactedMethods(); @@ -227,6 +236,8 @@ protected void runMethods() throws MojoExecutionException { try { ZLCHelperMethods.serializeMapping(methodsCheckSum, getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); + ZLCHelperMethods.serializeMapping(methodsDependencyGraph, getArtifactsDir(), + METHODS_DEPENDENCIES_SERIALIZED_FILE); } catch (IOException exception) { exception.printStackTrace(); } @@ -276,23 +287,14 @@ private void logInfoStatements() { protected void computeChangedMethods() throws MojoExecutionException { List> dataList = ZLCHelperMethods.getChangedDataMethods(methodsCheckSum, - methodToTestClasses, getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); + getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); changedMethods = dataList == null ? new HashSet() : dataList.get(0); newMethods = dataList == null ? new HashSet() : dataList.get(1); - - affectedTestClasses = dataList == null ? new HashSet() : dataList.get(2); - for (String newMethod : newMethods) { - affectedTestClasses.addAll(methodToTestClasses.getOrDefault(newMethod, new HashSet<>())); - } - - oldClasses = dataList == null ? new HashSet() : dataList.get(3); - changedClasses = dataList == null ? new HashSet() : dataList.get(4); + oldClasses = dataList == null ? new HashSet() : dataList.get(2); + changedClasses = dataList == null ? new HashSet() : dataList.get(3); newClasses = MethodLevelStaticDepsBuilder.getClasses(); newClasses.removeAll(oldClasses); - // nonAffectedMethods = MethodLevelStaticDepsBuilder.computeMethods(); - // nonAffectedMethods.removeAll(changedMethods); - // nonAffectedMethods.removeAll(newMethods); } /** From 7a6c31832e24f4b03adccf96e644d9ca773a5258 Mon Sep 17 00:00:00 2001 From: Moustafa Ismail Date: Sun, 12 Nov 2023 08:26:32 +0000 Subject: [PATCH 3/7] Optimizing hybrid --- .../edu/illinois/starts/jdeps/HybridMojo.java | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java index 13169ddc..512f0612 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java @@ -167,19 +167,7 @@ public void execute() throws MojoExecutionException { Classpath sfClassPath = getSureFireClassPath(); loader = createClassLoader(sfClassPath); - // Build method level static dependencies - try { - MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); - - classesChecksum = MethodLevelStaticDepsBuilder.computeClassesChecksums(loader, cleanBytes); - if (computeAffectedTests) { - methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(includeVariables); - } - } catch (Exception exception) { - throw new RuntimeException(exception); - } - - runHybrid(computeImpactedMethods); + runHybrid(); } /** @@ -194,12 +182,23 @@ public void execute() throws MojoExecutionException { * It also updates the methods checksums in the dependency file if * updateMethodsChecksums is true. * - * @param impacted a boolean value indicating whether to compute impacted - * methods and impacted test classes * @throws MojoExecutionException if an exception occurs while setting changed * methods */ - protected void runHybrid(boolean impacted) throws MojoExecutionException { + protected void runHybrid() throws MojoExecutionException { + + // Build method level static dependencies + try { + MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); + + classesChecksum = MethodLevelStaticDepsBuilder.computeClassesChecksums(loader, cleanBytes); + if (computeAffectedTests) { + methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(includeVariables); + } + } catch (Exception exception) { + throw new RuntimeException(exception); + } + // Checking if the file of dependencies exists (first run) if (!Files.exists(Paths.get(getArtifactsDir() + METHODS_CHECKSUMS_SERIALIZED_FILE)) && !Files.exists(Paths.get(getArtifactsDir() + CLASSES_CHECKSUM_SERIALIZED_FILE))) { @@ -220,7 +219,7 @@ protected void runHybrid(boolean impacted) throws MojoExecutionException { affectedTestClasses = MethodLevelStaticDepsBuilder.computeTestClasses(includeVariables); } - if (impacted) { + if (computeImpactedMethods) { impactedMethods = newMethods; impactedClasses = newClasses; } @@ -250,7 +249,7 @@ protected void runHybrid(boolean impacted) throws MojoExecutionException { setChangedAndNonaffectedMethods(); - if (impacted) { + if (computeImpactedMethods) { computeImpactedMethods(); computeImpactedClasses(); } @@ -270,7 +269,7 @@ protected void runHybrid(boolean impacted) throws MojoExecutionException { } - logInfo(impacted); + logInfo(computeImpactedMethods); } /** From 0ca3fc1cec1bc58d95c29b756f3b2e782649d8f1 Mon Sep 17 00:00:00 2001 From: Moustafa Ismail Date: Sun, 12 Nov 2023 10:19:16 +0000 Subject: [PATCH 4/7] Optimizing hybrid is complete --- .../starts/constants/StartsConstants.java | 3 + .../MethodLevelStaticDepsBuilder.java | 30 +++- .../edu/illinois/starts/jdeps/HybridMojo.java | 146 ++++++++++++------ 3 files changed, 128 insertions(+), 51 deletions(-) diff --git a/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java b/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java index bdf3d883..f35e1ef4 100644 --- a/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java +++ b/starts-core/src/main/java/edu/illinois/starts/constants/StartsConstants.java @@ -70,6 +70,9 @@ public interface StartsConstants { String METHODS_DEPENDENCIES_SERIALIZED_FILE = "methods-dependencies.ser"; String CLASSES_ZLC_FILE = "classes-checksums.zlc"; String CLASSES_CHECKSUM_SERIALIZED_FILE = "classes-checksums.ser"; + String CLASSES_DEPENDENCIES_SERIALIZED_FILE = "classes-dependencies.ser"; + String HIERARCHY_CHILDREN_SERIALIZED_FILE = "hierarchy-children.ser"; + String HIERARCHY_PARENTS_SERIALIZED_FILE = "hierarchy-parents.ser"; // Used in smethods String SMETHODS_ROOT_DIR_NAME = ".smethods"; diff --git a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java index bda627cc..601113df 100644 --- a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java +++ b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java @@ -525,7 +525,8 @@ public static Set getClasses() { */ public static Map> computeClassesChecksums(ClassLoader loader, boolean cleanBytes) { // Loopig over all the classes, and computing the checksum for each class - for (String className : classToContainedMethodNames.keySet()) { + Set classesNames = getAllClassesNames(); + for (String className : classesNames) { // Computing the checksum for the class file List classPartsChecksums = new ArrayList<>(); String klas = ChecksumUtil.toClassOrJavaName(className, false); @@ -610,14 +611,37 @@ public static Map> constructClassesDependencyGraph() { } addReflexiveClosure(classToContainedMethodNames); classesDependencyGraph = invertMap(classesDependencyGraph); - return classesDependencyGraph; } + public static Map> getHierarchyParents() { + return hierarchyParents; + } + + public static Map> getHierarchyChildren() { + return hierarchyChildren; + } + + public static void updateHierarchyParents(Map> oldHierarchyParents) { + hierarchyParents + .forEach((key, value) -> oldHierarchyParents.merge(key, value, (oldValue, newValue) -> newValue)); + hierarchyParents = oldHierarchyParents; + } + + public static void updateHierarchyChildren(Map> oldHierarchyChildren) { + hierarchyChildren + .forEach((key, value) -> oldHierarchyChildren.merge(key, value, (oldValue, newValue) -> newValue)); + hierarchyChildren = oldHierarchyChildren; + } + /* * This function computes the testClassesToClasses graph. */ - public static Map> constuctTestClassesToClassesGraph() { + public static Map> constuctTestClassesToClassesGraph(boolean includeVariables) { + if (testClassesToMethods == null) { + computeTestClassesToMethod(includeVariables); + } + for (String testClass : testClassesToMethods.keySet()) { Set classes = new HashSet<>(); for (String method : testClassesToMethods.get(testClass)) { diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java index 512f0612..2a48ee81 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java @@ -15,11 +15,6 @@ import java.util.Set; import java.util.logging.Level; -import edu.illinois.starts.helpers.ZLCHelperMethods; -import edu.illinois.starts.smethods.MethodLevelStaticDepsBuilder; -import edu.illinois.starts.util.ChecksumUtil; -import edu.illinois.starts.util.Logger; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -28,6 +23,11 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.surefire.booter.Classpath; +import edu.illinois.starts.helpers.ZLCHelperMethods; +import edu.illinois.starts.smethods.MethodLevelStaticDepsBuilder; +import edu.illinois.starts.util.ChecksumUtil; +import edu.illinois.starts.util.Logger; + @Mojo(name = "hybrid", requiresDirectInvocation = true, requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) public class HybridMojo extends DiffMojo { @@ -44,12 +44,13 @@ public class HybridMojo extends DiffMojo { private Map> classesChecksum; private Map> methodToTestClasses; private ClassLoader loader; - private Map> classDependencyGraph; + private Map> classesDependencyGraph; private Map> classToTestClassGraph; private Set deletedClasses; private Set changedClassesWithChangedHeaders; private Set changedClassesWithoutChangedHeaders; private Set impactedClasses; + private Map> methodsDependencyGraph; @Parameter(property = "computeImpactedMethods", defaultValue = TRUE) private boolean computeImpactedMethods; @@ -60,7 +61,7 @@ public class HybridMojo extends DiffMojo { @Parameter(property = "includeVariables", defaultValue = FALSE) private boolean includeVariables; - @Parameter(property = "debug", defaultValue = TRUE) + @Parameter(property = "debug", defaultValue = FALSE) private boolean debug; /** @@ -187,25 +188,26 @@ public void execute() throws MojoExecutionException { */ protected void runHybrid() throws MojoExecutionException { - // Build method level static dependencies - try { - MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); - - classesChecksum = MethodLevelStaticDepsBuilder.computeClassesChecksums(loader, cleanBytes); - if (computeAffectedTests) { - methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(includeVariables); - } - } catch (Exception exception) { - throw new RuntimeException(exception); - } - // Checking if the file of dependencies exists (first run) if (!Files.exists(Paths.get(getArtifactsDir() + METHODS_CHECKSUMS_SERIALIZED_FILE)) && !Files.exists(Paths.get(getArtifactsDir() + CLASSES_CHECKSUM_SERIALIZED_FILE))) { // In the first run we compute all method checksums and save them. // In later runs we just compute new method checksums for changed classes + + // Build method level static dependencies + try { + MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); + classesChecksum = MethodLevelStaticDepsBuilder.computeClassesChecksums(loader, cleanBytes); + methodsCheckSum = MethodLevelStaticDepsBuilder.computeAllMethodsChecksums(); + methodsDependencyGraph = MethodLevelStaticDepsBuilder.buildMethodsDependencyGraph(includeVariables, + computeAffectedTests); + classesDependencyGraph = MethodLevelStaticDepsBuilder.constructClassesDependencyGraph(); + + } catch (Exception exception) { + throw new RuntimeException(exception); + } + MethodLevelStaticDepsBuilder.computeMethodsChecksum(loader); - methodsCheckSum = MethodLevelStaticDepsBuilder.getMethodsCheckSum(); changedMethods = new HashSet<>(); newMethods = MethodLevelStaticDepsBuilder.computeMethods(); newClasses = MethodLevelStaticDepsBuilder.getClasses(); @@ -233,22 +235,57 @@ protected void runHybrid() throws MojoExecutionException { // ZLCHelperMethods.getChangedDataHybrid() ZLCHelperMethods.serializeMapping(methodsCheckSum, getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); + + ZLCHelperMethods.serializeMapping(methodsDependencyGraph, getArtifactsDir(), + METHODS_DEPENDENCIES_SERIALIZED_FILE); + + ZLCHelperMethods.serializeMapping(MethodLevelStaticDepsBuilder.getHierarchyParents(), + getArtifactsDir(), + HIERARCHY_PARENTS_SERIALIZED_FILE); + } catch (IOException exception) { exception.printStackTrace(); } } } else { - classDependencyGraph = MethodLevelStaticDepsBuilder.constructClassesDependencyGraph(); - MethodLevelStaticDepsBuilder.constuctTestClassesToClassesGraph(); + // Compute classes checksums + try { + classesChecksum = MethodLevelStaticDepsBuilder.computeClassesChecksums(loader, cleanBytes); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + setChangedMethodsAndChangedClasses(); + + + + // Building Method Dependency Graph + Map> oldMethodsDependencyGraph = ZLCHelperMethods.deserializeMapping(getArtifactsDir(), + METHODS_DEPENDENCIES_SERIALIZED_FILE); + Set changedClasses = new HashSet<>(changedClassesWithChangedHeaders); + changedClasses.addAll(changedClassesWithoutChangedHeaders); + + methodsDependencyGraph = MethodLevelStaticDepsBuilder + .buildMethodsDependencyGraphUsingOldGraphAndChangedClasses(oldMethodsDependencyGraph, + changedClasses, newClasses, includeVariables, computeAffectedTests); + + // Updating Hierarchy Parents and Children Maps because they are used in + // building class dependency graph + Map> hierarchyParents = ZLCHelperMethods.deserializeMapping(getArtifactsDir(), + HIERARCHY_PARENTS_SERIALIZED_FILE); + MethodLevelStaticDepsBuilder.updateHierarchyParents(hierarchyParents); + + // Building Class Dependency Graph + classesDependencyGraph = MethodLevelStaticDepsBuilder.constructClassesDependencyGraph(); + if (computeAffectedTests) { + MethodLevelStaticDepsBuilder.constuctTestClassesToClassesGraph(includeVariables); classToTestClassGraph = MethodLevelStaticDepsBuilder.constructClassesToTestClassesGraph(); methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(includeVariables); affectedTestClasses = new HashSet<>(); + computeAffectedTestClasses(); } - setChangedAndNonaffectedMethods(); - if (computeImpactedMethods) { computeImpactedMethods(); computeImpactedClasses(); @@ -262,6 +299,14 @@ protected void runHybrid() throws MojoExecutionException { // Save method-to-checksum mapping ZLCHelperMethods.serializeMapping(methodsCheckSum, getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); + + ZLCHelperMethods.serializeMapping(methodsDependencyGraph, getArtifactsDir(), + METHODS_DEPENDENCIES_SERIALIZED_FILE); + + ZLCHelperMethods.serializeMapping(MethodLevelStaticDepsBuilder.getHierarchyParents(), + getArtifactsDir(), + HIERARCHY_PARENTS_SERIALIZED_FILE); + } catch (IOException exception) { exception.printStackTrace(); } @@ -269,7 +314,7 @@ protected void runHybrid() throws MojoExecutionException { } - logInfo(computeImpactedMethods); + logInfo(); } /** @@ -277,14 +322,12 @@ protected void runHybrid() throws MojoExecutionException { * impacted test classes, new classes, old classes and changed classes. * If impacted is true, it also logs information about impacted methods. * - * @param impacted a boolean value indicating whether to log information about - * impacted methods */ - private void logInfo(boolean impacted) { + private void logInfo() { logger.log(Level.INFO, "ChangedMethods: " + changedMethods.size()); logger.log(Level.INFO, "NewMethods: " + newMethods.size()); - if (impacted) { + if (computeImpactedMethods) { logger.log(Level.INFO, "ImpactedMethods: " + impactedMethods.size()); } @@ -297,7 +340,7 @@ private void logInfo(boolean impacted) { logger.log(Level.INFO, "AffectedTestClasses: " + affectedTestClasses.size()); } - if (impacted) { + if (computeImpactedMethods) { logger.log(Level.INFO, "ImpactedClasses: " + impactedClasses.size()); } @@ -305,7 +348,7 @@ private void logInfo(boolean impacted) { if (debug) { logger.log(Level.INFO, "ImpactedMethods: " + impactedMethods); logger.log(Level.INFO, "ImpactedClasses: " + impactedClasses); - logger.log(Level.INFO, "ClassDependencyGraph: " + classDependencyGraph); + logger.log(Level.INFO, "ClassDependencyGraph: " + classesDependencyGraph); logger.log(Level.INFO, "ChangedClassesWithChangedHeaders: " + changedClassesWithChangedHeaders); logger.log(Level.INFO, "ChangedClassesWithoutChangedHeaders: " + changedClassesWithoutChangedHeaders); if (computeAffectedTests) { @@ -321,7 +364,8 @@ private void logInfo(boolean impacted) { * This method also updates the impacted test classes by adding test classes * associated with new methods. */ - protected void setChangedAndNonaffectedMethods() throws MojoExecutionException { + protected void setChangedMethodsAndChangedClasses() throws MojoExecutionException { + // Finding changes to classes List> classesData = ZLCHelperMethods.getChangedDataHybridClassLevel(classesChecksum, getArtifactsDir(), CLASSES_CHECKSUM_SERIALIZED_FILE); @@ -331,33 +375,39 @@ protected void setChangedAndNonaffectedMethods() throws MojoExecutionException { changedClassesWithoutChangedHeaders = classesData == null ? new HashSet() : classesData.get(3); oldClasses = classesData == null ? new HashSet() : classesData.get(4); + methodsCheckSum = MethodLevelStaticDepsBuilder.getMethodsCheckSum(); // Currently empty set will be retrived + + // Finding changes to methods + // Note methodsCheckSum is updated in this method to include only method + // checksums for changed classes and new classes. (not deleted classes or old) List> methodsData = ZLCHelperMethods.getChangedDataHybridMethodLevel(newClasses, deletedClasses, changedClassesWithChangedHeaders, changedClassesWithoutChangedHeaders, MethodLevelStaticDepsBuilder.getMethodsCheckSum(), loader, getArtifactsDir(), METHODS_CHECKSUMS_SERIALIZED_FILE); - methodsCheckSum = MethodLevelStaticDepsBuilder.getMethodsCheckSum(); - changedMethods = methodsData == null ? new HashSet() : methodsData.get(0); newMethods = methodsData == null ? new HashSet() : methodsData.get(1); - if (computeAffectedTests) { - for (String newMethod : newMethods) { - affectedTestClasses.addAll(methodToTestClasses.getOrDefault(newMethod, new HashSet<>())); - } + } - for (String changedMethod : changedMethods) { - affectedTestClasses.addAll(methodToTestClasses.getOrDefault(changedMethod, new HashSet<>())); - } + protected void computeAffectedTestClasses() { + for (String newMethod : newMethods) { + affectedTestClasses.addAll(methodToTestClasses.getOrDefault(newMethod, new HashSet<>())); + } - for (String addedClass : newClasses) { - affectedTestClasses.addAll(classToTestClassGraph.getOrDefault(addedClass, new HashSet<>())); - } + for (String changedMethod : changedMethods) { + affectedTestClasses.addAll(methodToTestClasses.getOrDefault(changedMethod, + new HashSet<>())); + } - for (String changedClassesWithChangedHeader : changedClassesWithChangedHeaders) { - affectedTestClasses - .addAll(classToTestClassGraph.getOrDefault(changedClassesWithChangedHeader, new HashSet<>())); - } + for (String addedClass : newClasses) { + affectedTestClasses.addAll(classToTestClassGraph.getOrDefault(addedClass, new HashSet<>())); + } + + for (String changedClassesWithChangedHeader : changedClassesWithChangedHeaders) { + affectedTestClasses + .addAll(classToTestClassGraph.getOrDefault(changedClassesWithChangedHeader, + new HashSet<>())); } } From a4d3c7a9bdba539650c17c42ee57ee3e76c29802 Mon Sep 17 00:00:00 2001 From: Moustafa Ismail Date: Sun, 12 Nov 2023 10:23:57 +0000 Subject: [PATCH 5/7] Fixing checkstyle issues --- .../smethods/MethodLevelStaticDepsBuilder.java | 5 ++--- .../java/edu/illinois/starts/jdeps/HybridMojo.java | 12 +++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java index 601113df..cdc237d3 100644 --- a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java +++ b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java @@ -96,8 +96,8 @@ public static HashSet getAllClassesPaths() { .filter(f -> (f.toString().endsWith(".class") && f.toString().contains("target"))) .map(f -> f.normalize().toAbsolutePath().toString()) .collect(Collectors.toList())); - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception exception) { + exception.printStackTrace(); } return class_paths; } @@ -447,7 +447,6 @@ public static Map> computeTestClassesToMethod(boolean includ /** * This function Computes and returns the methodToTestClasses map. - * * @return methodToTestClasses method to test classes mapping */ public static Map> computeMethodToTestClasses(boolean includeVariables) { diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java index 2a48ee81..a62df21d 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java @@ -15,6 +15,11 @@ import java.util.Set; import java.util.logging.Level; +import edu.illinois.starts.helpers.ZLCHelperMethods; +import edu.illinois.starts.smethods.MethodLevelStaticDepsBuilder; +import edu.illinois.starts.util.ChecksumUtil; +import edu.illinois.starts.util.Logger; + import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -23,11 +28,6 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.surefire.booter.Classpath; -import edu.illinois.starts.helpers.ZLCHelperMethods; -import edu.illinois.starts.smethods.MethodLevelStaticDepsBuilder; -import edu.illinois.starts.util.ChecksumUtil; -import edu.illinois.starts.util.Logger; - @Mojo(name = "hybrid", requiresDirectInvocation = true, requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) public class HybridMojo extends DiffMojo { @@ -257,8 +257,6 @@ protected void runHybrid() throws MojoExecutionException { } setChangedMethodsAndChangedClasses(); - - // Building Method Dependency Graph Map> oldMethodsDependencyGraph = ZLCHelperMethods.deserializeMapping(getArtifactsDir(), METHODS_DEPENDENCIES_SERIALIZED_FILE); From 9775361f65aa44f72f9d3878b980aa073db23463 Mon Sep 17 00:00:00 2001 From: Moustafa Ismail Date: Sun, 12 Nov 2023 10:52:49 +0000 Subject: [PATCH 6/7] Adding some documentation --- .../starts/helpers/ZLCHelperMethods.java | 4 +- .../MethodLevelStaticDepsBuilder.java | 62 +++++++++---------- .../edu/illinois/starts/jdeps/HybridMojo.java | 7 +-- .../illinois/starts/jdeps/MethodsMojo.java | 5 +- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java b/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java index 783f2e80..25371d09 100644 --- a/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java +++ b/starts-core/src/main/java/edu/illinois/starts/helpers/ZLCHelperMethods.java @@ -39,8 +39,8 @@ public class ZLCHelperMethods implements StartsConstants { /** * This helper method is used in method-level analysis returns a list of sets - * containing information about changed methods, new methods, affected tests, - * old classes, and changed classes. + * containing information about changed methods, new methods, old classes, and + * changed classes. * This method is called from MethodMojo.java from the setChangedMethods() * method. * diff --git a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java index cdc237d3..4dc3b041 100644 --- a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java +++ b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java @@ -102,6 +102,19 @@ public static HashSet getAllClassesPaths() { return class_paths; } + /* + * This function returns all the classes' Names in the project. + */ + public static HashSet getAllClassesNames() { + HashSet classPaths = getAllClassesPaths(); + HashSet classes = new HashSet<>(); + for (String classPath : classPaths) { + String className = getClassNameFromClassPath(classPath); + classes.add(className); + } + return classes; + } + /* * This function returns a map from class name to class path. * e.g., com/example/A -> @@ -119,19 +132,6 @@ public static Map getClassNameToPathMap() { return classNameToPathMap; } - /* - * This function returns all the classes' Names in the project. - */ - public static HashSet getAllClassesNames() { - HashSet classPaths = getAllClassesPaths(); - HashSet classes = new HashSet<>(); - for (String classPath : classPaths) { - String className = getClassNameFromClassPath(classPath); - classes.add(className); - } - return classes; - } - /* * This function returns the class name from the class path. * e.g., @@ -212,25 +212,10 @@ public static Map computeAllMethodsChecksums() { * project. */ public static Map> buildMethodsDependencyGraph( - boolean includeVariables, - boolean includeTestMethods) { + boolean includeVariables) { Set classPathsSet = getAllClassesPaths(); findMethodsinvoked(classPathsSet); - if (includeTestMethods) { - // Suppose that test classes have Test in their class name - // and are in src/test - Set testClasses = new HashSet<>(); - for (String method : methodNameToMethodNames.keySet()) { - String className = method.split("#|\\$")[0]; - if (className.contains("Test")) { - testClasses.add(className); - } - } - - // Finding Test Classes to methods - testClassesToMethods = getDepsSingleThread(testClasses); - } /* * Adding reflexive closure to methodNameToMethodNames @@ -270,7 +255,7 @@ public static Map> buildMethodsDependencyGraph( */ public static Map> buildMethodsDependencyGraphUsingOldGraphAndChangedClasses( Map> oldMethodsDependencyGraph, Set changedClasses, Set newClasses, - boolean includeVariables, boolean includeTestMethods) { + boolean includeVariables) { Set newAndChangedClasses = new HashSet<>(changedClasses); newAndChangedClasses.addAll(newClasses); Set classesPathSet = getClassPathsForSetOfClassNames(newAndChangedClasses); @@ -423,6 +408,10 @@ public static Map getMethodsCheckSum() { return methodsCheckSum; } + /* + * This function computes a map from test classes to methods. + * It must be called after the method dependecy graph is build + */ public static Map> computeTestClassesToMethod(boolean includeVariables) { if (testClassesToMethods == null) { // Suppose that test classes have Test in their class name @@ -447,6 +436,7 @@ public static Map> computeTestClassesToMethod(boolean includ /** * This function Computes and returns the methodToTestClasses map. + * * @return methodToTestClasses method to test classes mapping */ public static Map> computeMethodToTestClasses(boolean includeVariables) { @@ -621,13 +611,21 @@ public static Map> getHierarchyChildren() { return hierarchyChildren; } - public static void updateHierarchyParents(Map> oldHierarchyParents) { + /* + * This function take the oldHierarchyParents as input and uses it with the + * partial hierarchyParents graph to create the updated hierarchyParents + */ + public static void constructHierarchyParentsFromOld(Map> oldHierarchyParents) { hierarchyParents .forEach((key, value) -> oldHierarchyParents.merge(key, value, (oldValue, newValue) -> newValue)); hierarchyParents = oldHierarchyParents; } - public static void updateHierarchyChildren(Map> oldHierarchyChildren) { + /* + * This function take the oldHierarchyChildren as input and uses it with the + * partial hierarchyChildren graph to create the updated hierarchyChildren + */ + public static void constructHierarchyChildrenFromOld(Map> oldHierarchyChildren) { hierarchyChildren .forEach((key, value) -> oldHierarchyChildren.merge(key, value, (oldValue, newValue) -> newValue)); hierarchyChildren = oldHierarchyChildren; diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java index a62df21d..6d05896d 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/HybridMojo.java @@ -199,8 +199,7 @@ protected void runHybrid() throws MojoExecutionException { MethodLevelStaticDepsBuilder.buildMethodsGraph(includeVariables); classesChecksum = MethodLevelStaticDepsBuilder.computeClassesChecksums(loader, cleanBytes); methodsCheckSum = MethodLevelStaticDepsBuilder.computeAllMethodsChecksums(); - methodsDependencyGraph = MethodLevelStaticDepsBuilder.buildMethodsDependencyGraph(includeVariables, - computeAffectedTests); + methodsDependencyGraph = MethodLevelStaticDepsBuilder.buildMethodsDependencyGraph(includeVariables); classesDependencyGraph = MethodLevelStaticDepsBuilder.constructClassesDependencyGraph(); } catch (Exception exception) { @@ -265,13 +264,13 @@ protected void runHybrid() throws MojoExecutionException { methodsDependencyGraph = MethodLevelStaticDepsBuilder .buildMethodsDependencyGraphUsingOldGraphAndChangedClasses(oldMethodsDependencyGraph, - changedClasses, newClasses, includeVariables, computeAffectedTests); + changedClasses, newClasses, includeVariables); // Updating Hierarchy Parents and Children Maps because they are used in // building class dependency graph Map> hierarchyParents = ZLCHelperMethods.deserializeMapping(getArtifactsDir(), HIERARCHY_PARENTS_SERIALIZED_FILE); - MethodLevelStaticDepsBuilder.updateHierarchyParents(hierarchyParents); + MethodLevelStaticDepsBuilder.constructHierarchyParentsFromOld(hierarchyParents); // Building Class Dependency Graph classesDependencyGraph = MethodLevelStaticDepsBuilder.constructClassesDependencyGraph(); diff --git a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java index c9345232..ecb30ec0 100644 --- a/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java +++ b/starts-plugin/src/main/java/edu/illinois/starts/jdeps/MethodsMojo.java @@ -173,7 +173,7 @@ protected void runMethods() throws MojoExecutionException { try { methodsCheckSum = MethodLevelStaticDepsBuilder.computeAllMethodsChecksums(); methodsDependencyGraph = MethodLevelStaticDepsBuilder.buildMethodsDependencyGraph( - includeVariables, computeAffectedTests); + includeVariables); } catch (Exception exception) { throw new RuntimeException(exception); } @@ -222,13 +222,14 @@ protected void runMethods() throws MojoExecutionException { methodsDependencyGraph = MethodLevelStaticDepsBuilder .buildMethodsDependencyGraphUsingOldGraphAndChangedClasses(oldMethodsDependencyGraph, - changedClasses, newClasses, includeVariables, computeAffectedTests); + changedClasses, newClasses, includeVariables); if (computeImpactedMethods) { computeImpactedMethods(); } if (computeAffectedTests) { + methodToTestClasses = MethodLevelStaticDepsBuilder.computeMethodToTestClasses(includeVariables); computeAffectedTestClasses(); } From 8541b1800737220501eb9a324228c47222b32bb5 Mon Sep 17 00:00:00 2001 From: Moustafa Ismail Date: Sun, 12 Nov 2023 10:54:52 +0000 Subject: [PATCH 7/7] Fixing checkstyle errors --- .../illinois/starts/smethods/MethodLevelStaticDepsBuilder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java index 4dc3b041..76661d33 100644 --- a/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java +++ b/starts-core/src/main/java/edu/illinois/starts/smethods/MethodLevelStaticDepsBuilder.java @@ -436,7 +436,6 @@ public static Map> computeTestClassesToMethod(boolean includ /** * This function Computes and returns the methodToTestClasses map. - * * @return methodToTestClasses method to test classes mapping */ public static Map> computeMethodToTestClasses(boolean includeVariables) {