Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Strohschein2016-05-05 05:26:10 +0000
committerManoj Palat2016-05-05 05:26:10 +0000
commit62f0009f204d08fcdbe82b163b7a48ac082dedc9 (patch)
tree41a9cf3ccfcd64e8d3622886d8d295e771198f97
parente011cc03c880280f3916961950a745666f15125c (diff)
downloadeclipse.jdt.core-62f0009f204d08fcdbe82b163b7a48ac082dedc9.tar.gz
eclipse.jdt.core-62f0009f204d08fcdbe82b163b7a48ac082dedc9.tar.xz
eclipse.jdt.core-62f0009f204d08fcdbe82b163b7a48ac082dedc9.zip
Bug 484361 Huge performance slowdown between 4.6 M3 and M4
- 5 unit tests added to check if the performance optimizations have (still) an effect (checks if searching for secondary types is the last option to check). - 1 integrative performance test added which triggered many searches for secondary types before the performance optimizations were realized Signed-off-by: Sven Strohschein <novanic@gmx.de>
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java43
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java161
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java3
-rw-r--r--org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/AllPerformanceTests.java5
-rw-r--r--org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/SecondaryTypesPerformanceTest.java169
5 files changed, 378 insertions, 3 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
index dfb1b92890..c2376593a0 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
@@ -54,9 +54,14 @@ import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.CompilationProgress;
import org.eclipse.jdt.core.compiler.batch.BatchCompiler;
import org.eclipse.jdt.core.tests.util.Util;
+import org.eclipse.jdt.internal.compiler.batch.ClasspathDirectory;
import org.eclipse.jdt.internal.compiler.batch.ClasspathJar;
import org.eclipse.jdt.internal.compiler.batch.ClasspathLocation;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem;
import org.eclipse.jdt.internal.compiler.batch.Main;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.util.ManifestAnalyzer;
@SuppressWarnings({ "unchecked", "rawtypes" })
@@ -14556,4 +14561,42 @@ public void test439750() {
"1 problem (1 warning)\n",
true);
}
+
+/**
+ * A fast exit/result is expected when secondary types are searched with the reserved class name "package-info",
+ * because there can not exist a secondary type with the name "package-info", because it is a reserved class name.
+ * This fast exit improves the performance, because the search for secondary types is very expensive regarding performance
+ * (all classes of a package have to get loaded, parsed and analyzed).
+ */
+public void testFileSystem_findSecondaryInClass() {
+ final String testScratchArea = "fileSystemTestScratchArea";
+
+ File testScratchAreaFile = new File(Util.getOutputDirectory(), testScratchArea);
+ try {
+ if(!testScratchAreaFile.exists()) {
+ testScratchAreaFile.mkdirs();
+ }
+
+ assertTrue(testScratchAreaFile.exists());
+
+ Classpath classpath = FileSystem.getClasspath(testScratchAreaFile.getPath(), null, null);
+ assertNotNull(classpath);
+ assertTrue(classpath instanceof ClasspathDirectory);
+
+ ClasspathDirectory classpathDirectory = (ClasspathDirectory)classpath;
+ NameEnvironmentAnswer answer = classpathDirectory.findSecondaryInClass(TypeConstants.PACKAGE_INFO_NAME, null, null);
+ assertNull(answer); //No answer is expected, because "package-info" isn't a secondary type.
+
+ try {
+ //When there is a call with another name like "package-info", an exception is expected, because the search can not get executed successfully
+ // when no value for qualifiedPackageName is provided.
+ classpathDirectory.findSecondaryInClass("X".toCharArray(), null, null);
+ fail("An exception is expected, because the parameter qualifiedPackageName can not be NULL!");
+ } catch(Exception e) {}
+ } finally {
+ if(testScratchAreaFile.exists()) {
+ Util.delete(testScratchAreaFile);
+ }
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java
new file mode 100644
index 0000000000..827e53d393
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PackageBindingTest.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Sven Strohschein and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sven Strohschein - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.compiler.regression;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.tests.util.AbstractCompilerTest;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.core.INameEnvironmentWithProgress;
+
+public class PackageBindingTest extends AbstractCompilerTest
+{
+ public PackageBindingTest(String name) {
+ super(name);
+ }
+
+ /**
+ * This test checks if it is searched for packages before searching for types.
+ * The search for packages is much faster than searching for types, therefore it should get executed before searching for types.
+ */
+ public void test01() {
+ NameEnvironmentDummy nameEnv = new NameEnvironmentDummy(true);
+
+ PackageBinding packageBinding = new PackageBinding(new LookupEnvironment(null, new CompilerOptions(), null, nameEnv));
+ Binding resultBinding = packageBinding.getTypeOrPackage("java.lang".toCharArray());
+ assertNotNull(resultBinding);
+
+ assertTrue(nameEnv.isPackageSearchExecuted);
+ assertFalse(nameEnv.isTypeSearchExecuted);
+ }
+
+ /**
+ * This test checks if it is searched for types when no package was found.
+ * The test {@link #test01()} checks if the package search is executed before the type search.
+ * The search for packages is much faster than searching for types, therefore it should get executed before searching for types.
+ */
+ public void test02() {
+ NameEnvironmentDummy nameEnv = new NameEnvironmentDummy(false);
+
+ PackageBinding packageBinding = new PackageBinding(new LookupEnvironment(null, new CompilerOptions(), null, nameEnv));
+ Binding resultBinding = packageBinding.getTypeOrPackage("java.lang.String".toCharArray());
+ assertNull(resultBinding); // (not implemented)
+
+ assertTrue(nameEnv.isPackageSearchExecuted);
+ assertTrue(nameEnv.isTypeSearchExecuted);
+ }
+
+ /**
+ * This test checks if {@link INameEnvironment#findType(char[], char[][])} is executed.
+ * INameEnvironment has no option to avoid the search for secondary types, therefore the search for secondary types is executed (when available).
+ */
+ public void test03() {
+ NameEnvironmentDummy nameEnv = new NameEnvironmentDummy(false);
+
+ LookupEnvironment lookupEnv = new LookupEnvironment(null, new CompilerOptions(), null, nameEnv);
+ PackageBinding packageBinding = lookupEnv.createPackage(new char[][]{"org/eclipse/jdt".toCharArray(), "org/eclipse/jdt/internal".toCharArray()});
+ assertNotNull(packageBinding);
+
+ assertTrue(nameEnv.isTypeSearchExecuted); //the method findType(char[], char[][]) should got executed (without an option to avoid the search for secondary types)
+ }
+
+ /**
+ * This test checks if types are searched on creating a package, but without the search for secondary types.
+ * It isn't necessary to search for secondary types when creating a package, because a package name can not collide with a secondary type.
+ * The search for secondary types should not get executed, because the search for secondary types is very expensive regarding performance
+ * (all classes of a package have to get loaded, parsed and analyzed).
+ */
+ public void test04() {
+ NameEnvironmentWithProgressDummy nameEnvWithProgress = new NameEnvironmentWithProgressDummy();
+
+ LookupEnvironment lookupEnv = new LookupEnvironment(null, new CompilerOptions(), null, nameEnvWithProgress);
+ PackageBinding packageBinding = lookupEnv.createPackage(new char[][]{"org/eclipse/jdt".toCharArray(), "org/eclipse/jdt/internal".toCharArray()});
+ assertNotNull(packageBinding);
+
+ assertTrue(nameEnvWithProgress.isTypeSearchExecutedWithSearchWithSecondaryTypes); //the method findType(char[], char[][], boolean) should got executed ...
+ assertFalse(nameEnvWithProgress.isTypeSearchWithSearchWithSecondaryTypes); //... but without the search for secondary types
+ }
+
+ private class NameEnvironmentDummy implements INameEnvironment
+ {
+ private final boolean isPackage;
+ boolean isPackageSearchExecuted;
+ boolean isTypeSearchExecuted;
+
+ NameEnvironmentDummy(boolean isPackage) {
+ this.isPackage = isPackage;
+ }
+
+ @Override
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ this.isTypeSearchExecuted = true;
+ return null;
+ }
+
+ @Override
+ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
+ this.isTypeSearchExecuted = true;
+ return null;
+ }
+
+ @Override
+ public boolean isPackage(char[][] parentPackageName, char[] packageName) {
+ this.isPackageSearchExecuted = true;
+ return this.isPackage;
+ }
+
+ @Override
+ public void cleanup() {
+ }
+ }
+
+ private class NameEnvironmentWithProgressDummy implements INameEnvironmentWithProgress
+ {
+ boolean isTypeSearchWithSearchWithSecondaryTypes;
+ boolean isTypeSearchExecutedWithSearchWithSecondaryTypes;
+
+ NameEnvironmentWithProgressDummy() {}
+
+ @Override
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ return null;
+ }
+
+ @Override
+ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
+ return null;
+ }
+
+ @Override
+ public boolean isPackage(char[][] parentPackageName, char[] packageName) {
+ return false;
+ }
+
+ @Override
+ public void cleanup() {
+ }
+
+ @Override
+ public void setMonitor(IProgressMonitor monitor) {
+ }
+
+ @Override
+ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, boolean searchWithSecondaryTypes) {
+ this.isTypeSearchExecutedWithSearchWithSecondaryTypes = true;
+ this.isTypeSearchWithSearchWithSecondaryTypes = searchWithSecondaryTypes;
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java
index 4e78c1fe14..69a99e5419 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -86,6 +86,7 @@ public static Test suite() {
standardTests.add(ManifestAnalyzerTest.class);
standardTests.add(InitializationTests.class);
standardTests.add(ResourceLeakTests.class);
+ standardTests.add(PackageBindingTest.class);
// add all javadoc tests
for (int i=0, l=JavadocTest.ALL_CLASSES.size(); i<l; i++) {
diff --git a/org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/AllPerformanceTests.java b/org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/AllPerformanceTests.java
index 18a41e942a..0178650dc7 100644
--- a/org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/AllPerformanceTests.java
+++ b/org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/AllPerformanceTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -47,13 +47,14 @@ public class AllPerformanceTests extends junit.framework.TestCase {
/**
* Additional test class(es).
*
- * Classes put in this list will be run only if "add" VM parameter is added
+ * Classes put in this list will be run only if "add" VM parameter (-Dadd=true) is added
* while running JUnit test suite.
*
* @see #ADD
*/
public static Class[] getAdditionalTestClasses() {
return new Class[] {
+ SecondaryTypesPerformanceTest.class
};
}
diff --git a/org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/SecondaryTypesPerformanceTest.java b/org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/SecondaryTypesPerformanceTest.java
new file mode 100644
index 0000000000..c42b8c8af6
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.performance/src/org/eclipse/jdt/core/tests/performance/SecondaryTypesPerformanceTest.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Sven Strohschein and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sven Strohschein - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.performance;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.tests.util.Util;
+import org.eclipse.test.performance.PerformanceTestCase;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class SecondaryTypesPerformanceTest extends PerformanceTestCase {
+
+ private static final String testScratchArea = Util.getOutputDirectory() + File.separator + "enumPerformanceTestScratchArea";
+ private static final int numberOfClasspathsToCreate = 10; //can get set higher, but not lower than 3 (the first 3 packages are used within the test case)
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(SecondaryTypesPerformanceTest.class.getName());
+ suite.addTestSuite(SecondaryTypesPerformanceTest.class);
+ return suite;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ File testScratchAreaFile = new File(testScratchArea);
+ if(!testScratchAreaFile.exists()) {
+ testScratchAreaFile.mkdir();
+
+ File packageFile = new File(testScratchAreaFile, "test" + File.separator + "performance");
+ packageFile.mkdirs();
+ writeDummySourceClasses(packageFile, "test.performance");
+
+ Set<String> paths = createClasspathStrings();
+ for(String path: paths) {
+ File pathFile = new File(path);
+ pathFile.mkdir();
+
+ writeDummySourceClasses(pathFile, "test.performance." + pathFile.getName());
+ }
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ File testScratchAreaFile = new File(testScratchArea);
+ if(testScratchAreaFile.exists()) {
+ Util.delete(testScratchAreaFile);
+ }
+ }
+
+ public void test01() {
+ List<String> classpathList = new ArrayList<>();
+ classpathList.addAll(createClasspathStrings());
+ classpathList.add(testScratchArea);
+
+ for (int i = 0; i<10; ++i) {
+ ASTParser parser = ASTParser.newParser(AST.JLS8);
+ parser.setResolveBindings(true);
+ parser.setStatementsRecovery(true);
+ parser.setBindingsRecovery(true);
+ parser.setCompilerOptions(createCompilerOptions());
+ parser.setUnitName("X");
+ parser.setKind(ASTParser.K_COMPILATION_UNIT);
+ parser.setEnvironment(classpathList.toArray(new String[classpathList.size()]), null, null, true);
+ parser.setSource((""
+ + "import test.performance.test1.*;\n"
+ + "public enum X\n" +
+ "{\n" +
+ " TEST;\n" +
+ "\n" +
+ " public void method() {\n" +
+ " new Z().toString();\n" +
+ " new test.performance.test2.Z().toString();\n" +
+ " new test.performance.test3.Z().toString();\n" +
+ "\n" +
+ " }\n" +
+ "}").toCharArray());
+
+ startMeasuring();
+ ASTNode theAST = parser.createAST(null);
+ theAST.accept(new ASTVisitor() {});
+ stopMeasuring();
+ }
+
+ //Commit measure
+ commitMeasurements();
+ assertPerformance();
+ }
+
+ private Map<String, String> createCompilerOptions() {
+ Map<String, String> compilerOptions = new HashMap<>(10);
+ compilerOptions.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8);
+ compilerOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8);
+ compilerOptions.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
+ compilerOptions.put(JavaCore.COMPILER_TASK_PRIORITIES, JavaCore.COMPILER_TASK_PRIORITY_HIGH);
+ compilerOptions.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
+ return compilerOptions;
+ }
+
+ private Set<String> createClasspathStrings() {
+ Set<String> paths = new LinkedHashSet<>(numberOfClasspathsToCreate);
+ for(int i = 1; i <= numberOfClasspathsToCreate; i++) {
+ paths.add(testScratchArea + File.separator + "test" + File.separator + "performance" + File.separator + "test" + i);
+ }
+ return paths;
+ }
+
+ private void writeDummySourceClasses(File aPath, String packageName) throws IOException {
+ writeFile(new File(aPath, "Z.java"), "public class Z {}");
+
+ "ABC".toLowerCase(Locale.ENGLISH);
+
+ for(int i = 1; i <= 100; i++) {
+ String sourceContent = "package " + packageName + ";\n" +
+ "\n" +
+ "import java.util.Locale;\n" +
+ "\n" +
+ "public class X" + i + " {\n" +
+ "\tpublic X" + i + "() {\n" +
+ "\t\t\"ABC\".toLowerCase(Locale.ENGLISH);\n" +
+ "new Object() {\n" +
+ " @Override\n" +
+ " public String toString() {\n" +
+ " return \"Test\";\n" +
+ " }\n" +
+ " }.toString();" +
+ "\t}\n" +
+ "}";
+
+ writeFile(new File(aPath, "X" + i + ".java"), sourceContent);
+ }
+ }
+
+ private void writeFile(File aFile, String aSource) throws IOException {
+ FileWriter fileWriter = new FileWriter(aFile);
+ try {
+ fileWriter.write(aSource);
+ } finally {
+ fileWriter.close();
+ }
+ }
+} \ No newline at end of file

Back to the top