blob: 1e69b5a8c77c2cc8aa26137cf8199c15375c8cca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.performance;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import junit.framework.Test;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.SourceElementParser;
import org.eclipse.jdt.internal.compiler.SourceElementRequestorAdapter;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.Scanner;
import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.util.Util;
import org.eclipse.test.performance.Performance;
/**
* Class to test compiler performance.
* This includes tests on build, batch compiler, Scanner and Parser.
*/
public class FullSourceWorkspaceBuildTests extends FullSourceWorkspaceTests {
// Tests counters
private static int TESTS_COUNT = 0;
private final static int ITERATIONS_COUNT = 10;
private final static int SCAN_REPEAT = 800; // 800 is default
// Tests thresholds
private final static int TIME_THRESHOLD = 150;
// Log files
private static PrintStream[] LOG_STREAMS = new PrintStream[LOG_TYPES.length];
/**
* @param name
*/
public FullSourceWorkspaceBuildTests(String name) {
super(name);
}
static {
// TESTS_PREFIX = "testPerfBatch";
// TESTS_NAMES = new String[] { "testBatchCompilerAllWarnings" };
}
public static Test suite() {
Test suite = buildSuite(testClass());
TESTS_COUNT = suite.countTestCases();
createPrintStream(testClass(), LOG_STREAMS, TESTS_COUNT, null);
return suite;
}
private static Class testClass() {
return FullSourceWorkspaceBuildTests.class;
}
/*
* Parse several times a file giving its name.
*/
private long[] parseFile(String fileName, int kind, int iterations) throws InvalidInputException, IOException {
// Test for parser
File file = new File(fileName);
char[] content = Util.getFileCharContent(file, null);
CompilerOptions options = new CompilerOptions();
options.sourceLevel = ClassFileConstants.JDK1_4;
options.targetJDK = ClassFileConstants.JDK1_4;
ProblemReporter problemReporter =
new ProblemReporter(
DefaultErrorHandlingPolicies.exitAfterAllProblems(),
options,
new DefaultProblemFactory());
// Create parser
Parser parser = null;
switch (kind) {
case 1: // SourceElementParser
parser = new SourceElementParser(new SourceElementRequestorAdapter(), problemReporter.problemFactory, options, true, true);
break;
default:
parser = new Parser(problemReporter, true);
break;
}
// Warm up
for (int i = 0; i < 2; i++) {
ICompilationUnit unit = new CompilationUnit(content, file.getName(), null);
CompilationResult unitResult = new CompilationResult(unit, 0, 1, options.maxProblemsPerUnit);
CompilationUnitDeclaration unitDeclaration = parser.dietParse(unit, unitResult);
parser.getMethodBodies(unitDeclaration);
}
// Clean memory
runGc();
// Measures
long parsedLines = 0;
long parsedCharacters = 0;
long start = 0;
if (DEBUG) {
start = System.currentTimeMillis();
}
startMeasuring();
for (int i = 0; i < iterations; i++) {
ICompilationUnit unit = new CompilationUnit(content, file.getName(), null);
CompilationResult unitResult = new CompilationResult(unit, 0, 1, options.maxProblemsPerUnit);
CompilationUnitDeclaration unitDeclaration = parser.dietParse(unit, unitResult);
parser.getMethodBodies(unitDeclaration);
parsedCharacters += content.length;
parsedLines += unitResult.getLineSeparatorPositions().length;
}
stopMeasuring();
// Warn if measure time is not enough while debugging
if (DEBUG) {
long time = System.currentTimeMillis() - start;
if (time < TIME_THRESHOLD) {
System.err.println(parsedLines + " lines/"+ parsedCharacters + " characters parsed");
} else {
System.out.println(parsedLines + " lines/"+ parsedCharacters + " characters parsed");
}
}
// Return stats
return new long[] { parsedCharacters, parsedLines };
}
/*
* Test performance for a parser on one file.
* Parse is executed many times ({@link #ITERATIONS_COUNT}) to have significant time for execution.
* This test is repeated several times ({@link #MEASURES_COUNT}) to average time measuring.
*
* @throws InvalidInputException
* @throws IOException
*/
void parseParserFile(int kind) throws InvalidInputException, IOException {
// Get workspace path
IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IWorkspaceRoot workspaceRoot = workspace.getRoot();
final String targetWorkspacePath = workspaceRoot.getProject(JavaCore.PLUGIN_ID)
.getLocation()
.toFile()
.getCanonicalPath();
// Run test
for (int i=0; i<MEASURES_COUNT; i++) {
parseFile(targetWorkspacePath+"/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java", kind, ITERATIONS_COUNT*6);
}
// dump measure
commitMeasurements();
assertPerformance();
}
/*
* Scan a file giving its name.
* Two kind of scan is currently possible:
* - 0: only scan all tokens
* - 1: scan all tokens and get each identifier
*/
private void scanFile(String fileName, int kind) throws InvalidInputException, IOException {
// Test for scanner
long tokenCount = 0;
char[] content = Util.getFileCharContent(new File(fileName),
null);
Scanner scanner = new Scanner();
scanner.setSource(content);
// Warm up
for (int i = 0; i < 2; i++) {
scanner.resetTo(0, content.length);
tokenize: while (true) {
int token = scanner.getNextToken();
switch (kind) {
case 0: // first case: only read tokens
switch (token) {
case TerminalTokens.TokenNameEOF:
break tokenize;
}
break;
case 1: // second case: read tokens + get ids
switch (token) {
case TerminalTokens.TokenNameEOF:
break tokenize;
case TerminalTokens.TokenNameIdentifier:
scanner.getCurrentIdentifierSource();
break;
}
break;
}
}
}
// Clean memory
runGc();
// Measures
long size = 0;
for (int i = 0; i < MEASURES_COUNT; i++) {
startMeasuring();
for (int j = 0; j < SCAN_REPEAT; j++) {
scanner.resetTo(0, content.length);
tokenize: while (true) {
int token = scanner.getNextToken();
switch (kind) {
case 0: // first case: only read tokens
switch (token) {
case TerminalTokens.TokenNameEOF:
break tokenize;
}
break;
case 1: // second case: read tokens + get ids
switch (token) {
case TerminalTokens.TokenNameEOF:
break tokenize;
case TerminalTokens.TokenNameIdentifier:
char[] c = scanner.getCurrentIdentifierSource();
size += c.length;
break;
}
break;
}
tokenCount++;
}
}
stopMeasuring();
}
// Commit
commitMeasurements();
assertPerformance();
// Debug
if (DEBUG) {
switch (kind) {
case 0:
System.out.println(tokenCount + " tokens read.");
break;
case 1:
System.out.print(tokenCount + " tokens were read ("+size+" characters)");
break;
}
}
}
/* (non-Javadoc)
* @see junit.framework.TestCase#tearDown()
*/
protected void tearDown() throws Exception {
// End of execution => one test less
TESTS_COUNT--;
// Log perf result
if (LOG_DIR != null) {
logPerfResult(LOG_STREAMS, TESTS_COUNT);
}
// Call super at the end as it close print streams
super.tearDown();
}
/**
* Full build with no warning.
*
* Not calling tagAsSummary means that this test is currently evaluated
* before put it in builds performance results.
*
* @throws CoreException
* @throws IOException
*/
public void testFullBuildNoWarning() throws CoreException, IOException {
tagAsSummary("Compile>Build>Clean>Full>No warning", false); // do NOT put in fingerprint
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support");
startBuild(warningOptions(-1/*no warning*/), false);
}
/**
* Full build with JavaCore default options.
*
* @throws CoreException
* @throws IOException
*/
public void testFullBuildDefault() throws CoreException, IOException {
tagAsGlobalSummary("Compile>Build>Clean>Full>Default warnings", true); // put in fingerprint
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support + additional warnings (e.g. validate unused local and private members)");
startBuild(warningOptions(0/*default warnings*/), false);
}
/**
* Full build with all warnings.
*
* Not calling tagAsSummary means that this test is currently evaluated
* before put it in builds performance results.
*
* @throws CoreException
* @throws IOException
*
*/
public void testFullBuildAllWarnings() throws CoreException, IOException {
tagAsSummary("Compile>Build>Clean>Full>All warnings", false); // do NOT put in fingerprint
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support");
startBuild(warningOptions(1/*all warnings*/), false);
}
/**
* Batch compiler build with no warning
*
* Not calling tagAsSummary means that this test is currently evaluated
* before put it in builds performance results.
*
* @throws IOException
*/
public void testBatchCompilerNoWarning() throws IOException {
tagAsSummary("Compile>Batch>Compiler>No warning", true); // put in fingerprint
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support");
buildUsingBatchCompiler("-nowarn");
}
/**
* Batch compiler build with default warnings
*
* Not calling tagAsSummary means that this test is currently evaluated
* before put it in builds performance results.
*
* @throws IOException
*/
public void testBatchCompilerDefault() throws IOException {
tagAsSummary("Compile>Batch>Compiler>Default warnings", false); // do NOT put in fingerprint
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support");
buildUsingBatchCompiler("");
}
/**
* Batch compiler build with default javadoc warnings
*
* Not calling tagAsSummary means that this test is currently evaluated
* before put it in builds performance results.
*
* @throws IOException
*/
public void testBatchCompilerJavadoc() throws IOException {
tagAsSummary("Compile>Batch>Compiler>Javadoc warnings", false); // do NOT put in fingerprint
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support");
buildUsingBatchCompiler("-warn:javadoc");
}
/**
* Batch compiler build with invalid javadoc warnings
*
* Not calling tagAsSummary means that this test is currently evaluated
* before put it in builds performance results.
*
* @throws IOException
*/
// TODO (frederic) put back after having understood why this test result can have variation over 20%
public void _testBatchCompilerAllJavadoc() throws IOException {
tagAsSummary("Compile>Batch>Compiler>All Javadoc warnings", false); // do NOT put in fingerprint
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support");
buildUsingBatchCompiler("-warn:allJavadoc");
}
/**
* Batch compiler build with all warnings
*
* Not calling tagAsSummary means that this test is currently evaluated
* before put it in builds performance results.
*
* @throws IOException
*/
public void testBatchCompilerAllWarnings() throws IOException {
tagAsSummary("Compile>Batch>Compiler>All warnings", false); // do NOT put in fingerprint
String allOptions = "-warn:" +
"allDeprecation," +
"allJavadoc," +
"assertIdentifier," +
"charConcat," +
"conditionAssign," +
"constructorName," +
"deprecation," +
"emptyBlock," +
"fieldHiding," +
"finally," +
"indirectStatic," +
"intfNonInherited," +
"localHiding," +
"maskedCatchBlock," +
"nls," +
"noEffectAssign," +
"pkgDefaultMethod," +
"semicolon," +
"unqualifiedField," +
"unusedArgument," +
"unusedImport," +
"unusedLocal," +
"unusedPrivate," +
"unusedThrown," +
"unnecessaryElse," +
"uselessTypeCheck," +
"specialParamHiding," +
"staticReceiver," +
"syntheticAccess," +
"tasks(TODO|FIX|XXX)";
setComment(Performance.EXPLAINS_DEGRADATION_COMMENT, "J2SE 5.0 support");
buildUsingBatchCompiler(allOptions);
}
/**
* Test performance for Scanner on one file.
* Scan is executed many times ({@link #SCAN_REPEAT}) to have significant time for execution.
* This test is repeated several times ({@link #ITERATIONS_COUNT}) to average time measuring.
*
* @throws InvalidInputException
* @throws IOException
*/
public void testScanner() throws InvalidInputException, IOException {
// Do no longer print result in performance fingerprint
tagAsSummary("Compile>Scan>Parser>Default", true); // put in fingerprint
// Get workspace path
IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IWorkspaceRoot workspaceRoot = workspace.getRoot();
final String targetWorkspacePath = workspaceRoot.getProject(JavaCore.PLUGIN_ID)
.getLocation()
.toFile()
.getCanonicalPath();
// Run test
// scanFile(targetWorkspacePath+"/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java", 0/*only scan tokens*/);
scanFile(targetWorkspacePath+"/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java", 1/*scan tokens+get identifiers*/);
}
/**
* Test performance for Parser on one file.
* Parse is executed many times ({@link #ITERATIONS_COUNT}) to have significant time for execution.
* This test is repeated several times ({@link #MEASURES_COUNT}) to average time measuring.
*
* @throws InvalidInputException
* @throws IOException
*/
public void testParser() throws InvalidInputException, IOException {
tagAsSummary("Compile>Parse>Parser>Default", true); // put in fingerprint
parseParserFile(0); // Parser kind
}
/**
* Test performance for SourceElementParser on one file.
* Parse is executed many times ({@link #ITERATIONS_COUNT}) to have significant time for execution.
* This test is repeated several times ({@link #MEASURES_COUNT}) to average time measuring.
*
* Note: This test has been temporarily removed as there's unexplicable difference between
* HEAD and 3.0 versions for CPU Time results (10% faster) and Elapsed process (25% slower)...
* TODO (frederic) Put back when platform-releng will have stabilized performance results process.
*
* @throws InvalidInputException
* @throws IOException
*/
public void _testSourceParser() throws InvalidInputException, IOException {
tagAsSummary("Compile>SrcParse>Parser>Default", true); // put in fingerprint
parseParserFile(1); // SourceElementParser kind
}
}