Speeds up hosted mode by reducing work done in batch JDT compiles via requests
made from TypeOracleBuilder. Speeds up unit tests additionally by improving
module caching / refresh behavior.
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1718 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index ea48b17..a009e2c 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -35,6 +35,7 @@
import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.util.tools.ArgHandlerDisableAggressiveOptimization;
import com.google.gwt.util.tools.ArgHandlerEnableAssertions;
import com.google.gwt.util.tools.ArgHandlerExtra;
@@ -291,7 +292,7 @@
/**
* Load a module.
- *
+ *
* @param moduleName name of the module to load
* @param logger TreeLogger to use
* @return the loaded module
@@ -788,8 +789,11 @@
//
final int serverPort = getPort();
+ PerfLogger.start("GWTShell.startup (Tomcat launch)");
String whyFailed = EmbeddedTomcatServer.start(getTopLogger(), serverPort,
outDir);
+ PerfLogger.end();
+
if (whyFailed != null) {
System.err.println(whyFailed);
return false;
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
index 39efffa..cc79733 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -26,6 +26,7 @@
import com.google.gwt.dev.util.FileOracle;
import com.google.gwt.dev.util.FileOracleFactory;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.FileOracleFactory.FileFilter;
import org.apache.tools.ant.types.ZipScanner;
@@ -274,63 +275,8 @@
public synchronized TypeOracle getTypeOracle(TreeLogger logger)
throws UnableToCompleteException {
if (lazyTypeOracle == null) {
-
- // Refresh the type oracle.
- //
- try {
- String msg = "Analyzing source in module '" + name + "'";
- TreeLogger branch = logger.branch(TreeLogger.TRACE, msg, null);
- long before = System.currentTimeMillis();
- TypeOracleBuilder builder = new TypeOracleBuilder(getCacheManager());
- CompilationUnitProvider[] currentCups = getCompilationUnits();
- Arrays.sort(currentCups, CompilationUnitProvider.LOCATION_COMPARATOR);
-
- TreeLogger subBranch = null;
- if (branch.isLoggable(TreeLogger.DEBUG)) {
- subBranch = branch.branch(TreeLogger.DEBUG,
- "Adding compilation units...", null);
- }
-
- for (int i = 0; i < currentCups.length; i++) {
- CompilationUnitProvider cup = currentCups[i];
- if (subBranch != null) {
- subBranch.log(TreeLogger.DEBUG, cup.getLocation(), null);
- }
- builder.addCompilationUnit(currentCups[i]);
- }
- lazyTypeOracle = builder.build(branch);
- long after = System.currentTimeMillis();
- branch.log(TreeLogger.TRACE, "Finished in " + (after - before) + " ms",
- null);
- } catch (UnableToCompleteException e) {
- logger.log(TreeLogger.ERROR, "Failed to complete analysis", null);
- throw new UnableToCompleteException();
- }
-
- // Sanity check the seed types and don't even start it they're missing.
- //
- boolean seedTypesMissing = false;
- if (lazyTypeOracle.findType("java.lang.Object") == null) {
- Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
- seedTypesMissing = true;
- } else {
- TreeLogger branch = logger.branch(TreeLogger.TRACE,
- "Finding entry point classes", null);
- String[] typeNames = getEntryPointTypeNames();
- for (int i = 0; i < typeNames.length; i++) {
- String typeName = typeNames[i];
- if (lazyTypeOracle.findType(typeName) == null) {
- Util.logMissingTypeErrorWithHints(branch, typeName);
- seedTypesMissing = true;
- }
- }
- }
-
- if (seedTypesMissing) {
- throw new UnableToCompleteException();
- }
+ lazyTypeOracle = createTypeOracle(logger);
}
-
return lazyTypeOracle;
}
@@ -359,13 +305,13 @@
public synchronized void refresh(TreeLogger logger)
throws UnableToCompleteException {
-
+ PerfLogger.start("ModuleDef.refresh");
cacheManager.invalidateVolatileFiles();
- lazyTypeOracle = null;
normalize(logger);
- getTypeOracle(logger);
+ lazyTypeOracle = createTypeOracle(logger);
Util.invokeInaccessableMethod(TypeOracle.class, "incrementReloadCount",
new Class[] {}, lazyTypeOracle, new Object[] {});
+ PerfLogger.end();
}
/**
@@ -389,6 +335,8 @@
* @param logger Logs the activity.
*/
synchronized void normalize(TreeLogger logger) {
+ PerfLogger.start("ModuleDef.normalize");
+
// Normalize property providers.
//
for (Iterator<Property> iter = getProperties().iterator(); iter.hasNext();) {
@@ -446,6 +394,74 @@
//
branch = Messages.PUBLIC_PATH_LOCATIONS.branch(logger, null);
lazyPublicOracle = publicPathEntries.create(branch);
+
+ PerfLogger.end();
+ }
+
+ private TypeOracle createTypeOracle(TreeLogger logger)
+ throws UnableToCompleteException {
+
+ TypeOracle newTypeOracle = null;
+
+ try {
+ String msg = "Analyzing source in module '" + name + "'";
+ TreeLogger branch = logger.branch(TreeLogger.TRACE, msg, null);
+ long before = System.currentTimeMillis();
+ TypeOracleBuilder builder = new TypeOracleBuilder(getCacheManager());
+ CompilationUnitProvider[] currentCups = getCompilationUnits();
+ Arrays.sort(currentCups, CompilationUnitProvider.LOCATION_COMPARATOR);
+
+ TreeLogger subBranch = null;
+ if (branch.isLoggable(TreeLogger.DEBUG)) {
+ subBranch = branch
+ .branch(TreeLogger.DEBUG, "Adding compilation units...", null);
+ }
+
+ for (int i = 0; i < currentCups.length; i++) {
+ CompilationUnitProvider cup = currentCups[i];
+ if (subBranch != null) {
+ subBranch.log(TreeLogger.DEBUG, cup.getLocation(), null);
+ }
+ builder.addCompilationUnit(currentCups[i]);
+ }
+
+ if (lazyTypeOracle != null) {
+ cacheManager.invalidateOnRefresh(lazyTypeOracle);
+ }
+
+ newTypeOracle = builder.build(branch);
+ long after = System.currentTimeMillis();
+ branch.log(TreeLogger.TRACE, "Finished in " + (after - before) + " ms",
+ null);
+ } catch (UnableToCompleteException e) {
+ logger.log(TreeLogger.ERROR, "Failed to complete analysis", null);
+ throw new UnableToCompleteException();
+ }
+
+ // Sanity check the seed types and don't even start it they're missing.
+ //
+ boolean seedTypesMissing = false;
+ if (newTypeOracle.findType("java.lang.Object") == null) {
+ Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
+ seedTypesMissing = true;
+ } else {
+ TreeLogger branch = logger
+ .branch(TreeLogger.TRACE, "Finding entry point classes", null);
+ String[] typeNames = getEntryPointTypeNames();
+ for (int i = 0; i < typeNames.length; i++) {
+ String typeName = typeNames[i];
+ if (newTypeOracle.findType(typeName) == null) {
+ Util.logMissingTypeErrorWithHints(branch, typeName);
+ seedTypesMissing = true;
+ }
+ }
+ }
+
+ if (seedTypesMissing) {
+ throw new UnableToCompleteException();
+ }
+
+ return newTypeOracle;
}
private ZipScanner getScanner(String[] includeList, String[] excludeList,
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index f0f79fc..71bbbbe 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -66,6 +66,11 @@
return enableCachingModules;
}
+ public static ModuleDef loadFromClassPath(TreeLogger logger, String moduleName)
+ throws UnableToCompleteException {
+ return loadFromClassPath(logger, moduleName, true);
+ }
+
/**
* Loads a new module from the class path.
*
@@ -74,8 +79,8 @@
* @return The loaded module.
* @throws UnableToCompleteException
*/
- public static ModuleDef loadFromClassPath(TreeLogger logger, String moduleName)
- throws UnableToCompleteException {
+ public static ModuleDef loadFromClassPath(TreeLogger logger,
+ String moduleName, boolean refresh) throws UnableToCompleteException {
ModuleDef moduleDef = (ModuleDef) loadedModules.get(moduleName);
if (moduleDef == null || moduleDef.isGwtXmlFileStale()) {
moduleDef = new ModuleDefLoader().load(logger, moduleName);
@@ -83,7 +88,9 @@
loadedModules.put(moduleName, moduleDef);
}
} else {
- moduleDef.refresh(logger);
+ if (refresh) {
+ moduleDef.refresh(logger);
+ }
}
return moduleDef;
}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
index 01f4011..0e46290 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -19,6 +19,7 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.dev.util.Empty;
+import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.log.ThreadLocalTreeLoggerProxy;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -52,6 +53,22 @@
public abstract class AbstractCompiler {
/**
+ * A policy that can be set to affect which
+ * {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration
+ * CompilationUnitDeclarations} the compiler processes.
+ */
+ public interface CachePolicy {
+
+ /**
+ * Return true if <code>cud</code> should be processed, otherwise false.
+ *
+ * @param cud a not <code>null</code> unit
+ * @return true iff <code>cud</code> should be fully processed
+ */
+ public boolean shouldProcess(CompilationUnitDeclaration cud);
+ }
+
+ /**
* Adapted to hook the processing of compilation unit declarations so as to be
* able to add additional compilation units based on the results of
* previously-compiled ones. Examples of cases where this is useful include
@@ -60,6 +77,7 @@
private class CompilerImpl extends Compiler {
private Set<CompilationUnitDeclaration> cuds;
+ private long jdtProcessNanos;
public CompilerImpl(INameEnvironment environment,
IErrorHandlingPolicy policy, Map<String, String> settings,
@@ -69,13 +87,27 @@
@Override
public void compile(ICompilationUnit[] sourceUnits) {
+ jdtProcessNanos = 0;
super.compile(sourceUnits);
+ PerfLogger.log(
+ "AbstractCompiler.compile, time spent in JDT process callback: "
+ + (jdtProcessNanos / 1000000) + "ms");
cuds = null;
}
@Override
public void process(CompilationUnitDeclaration cud, int index) {
- // super.process(cud, index);
+
+ long processBeginNanos = System.nanoTime();
+
+ if (!cachePolicy.shouldProcess(cud)) {
+ jdtProcessNanos += System.nanoTime() - processBeginNanos;
+ return;
+ }
+
+ // The following block of code is a copy of super.process(cud, index),
+ // with the modification that cud.generateCode is conditionally called
+ // based on doGenerateBytes
{
this.parser.getMethodBodies(cud);
@@ -154,6 +186,8 @@
if (cuds != null) {
cuds.add(cud);
}
+
+ jdtProcessNanos += System.nanoTime() - processBeginNanos;
}
private void compile(ICompilationUnit[] units,
@@ -310,8 +344,8 @@
try {
cup = sourceOracle.findCompilationUnit(logger, qname);
if (cup != null) {
- logger.log(TreeLogger.SPAM, "Found type in compilation unit: "
- + cup.getLocation(), null);
+ logger.log(TreeLogger.SPAM,
+ "Found type in compilation unit: " + cup.getLocation(), null);
ICompilationUnitAdapter unit = new ICompilationUnitAdapter(cup);
NameEnvironmentAnswer out = new NameEnvironmentAnswer(unit, null);
nameEnvironmentAnswerForTypeName.put(qname, out);
@@ -349,7 +383,16 @@
}
}
- protected final ThreadLocalTreeLoggerProxy threadLogger = new ThreadLocalTreeLoggerProxy();
+ private static final CachePolicy DEFAULT_POLICY = new CachePolicy() {
+ public boolean shouldProcess(CompilationUnitDeclaration cud) {
+ return true;
+ }
+ };
+
+ protected final ThreadLocalTreeLoggerProxy threadLogger
+ = new ThreadLocalTreeLoggerProxy();
+
+ private CachePolicy cachePolicy = DEFAULT_POLICY;
private final CompilerImpl compiler;
@@ -357,19 +400,23 @@
private final Set<String> knownPackages = new HashSet<String>();
- private final Map<String, NameEnvironmentAnswer> nameEnvironmentAnswerForTypeName = new HashMap<String, NameEnvironmentAnswer>();
+ private final Map<String, NameEnvironmentAnswer> nameEnvironmentAnswerForTypeName
+ = new HashMap<String, NameEnvironmentAnswer>();
private final SourceOracle sourceOracle;
- private final Map<String, ICompilationUnit> unitsByTypeName = new HashMap<String, ICompilationUnit>();
+ private final Map<String, ICompilationUnit> unitsByTypeName
+ = new HashMap<String, ICompilationUnit>();
- protected AbstractCompiler(SourceOracle sourceOracle, boolean doGenerateBytes) {
+ protected AbstractCompiler(SourceOracle sourceOracle,
+ boolean doGenerateBytes) {
this.sourceOracle = sourceOracle;
this.doGenerateBytes = doGenerateBytes;
rememberPackage("");
INameEnvironment env = new INameEnvironmentImpl();
- IErrorHandlingPolicy pol = DefaultErrorHandlingPolicies.proceedWithAllProblems();
+ IErrorHandlingPolicy pol = DefaultErrorHandlingPolicies
+ .proceedWithAllProblems();
IProblemFactory probFact = new DefaultProblemFactory(Locale.getDefault());
ICompilerRequestor req = new ICompilerRequestorImpl();
Map<String, String> settings = new HashMap<String, String>();
@@ -384,22 +431,27 @@
*/
settings.put(CompilerOptions.OPTION_PreserveUnusedLocal,
CompilerOptions.PRESERVE);
- settings.put(CompilerOptions.OPTION_ReportDeprecation,
- CompilerOptions.IGNORE);
+ settings
+ .put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE);
settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
CompilerOptions.GENERATE);
- settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
+ settings
+ .put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_5);
// This is needed by TypeOracleBuilder to parse metadata.
- settings.put(CompilerOptions.OPTION_DocCommentSupport,
- CompilerOptions.ENABLED);
+ settings
+ .put(CompilerOptions.OPTION_DocCommentSupport, CompilerOptions.ENABLED);
compiler = new CompilerImpl(env, pol, settings, req, probFact);
}
+ public CachePolicy getCachePolicy() {
+ return cachePolicy;
+ }
+
public void invalidateUnitsInFiles(Set<String> fileNames,
Set<String> typeNames) {
// StandardSourceOracle has its own cache that needs to be cleared
@@ -415,6 +467,10 @@
}
}
+ public void setCachePolicy(CachePolicy policy) {
+ this.cachePolicy = policy;
+ }
+
protected final CompilationUnitDeclaration[] compile(TreeLogger logger,
ICompilationUnit[] units) {
// Any additional compilation units that are found to be needed will be
@@ -422,10 +478,12 @@
//
TreeLogger oldLogger = threadLogger.push(logger);
try {
- Set<CompilationUnitDeclaration> cuds = new HashSet<CompilationUnitDeclaration>();
+ Set<CompilationUnitDeclaration> cuds
+ = new HashSet<CompilationUnitDeclaration>();
compiler.compile(units, cuds);
int size = cuds.size();
- CompilationUnitDeclaration[] cudArray = new CompilationUnitDeclaration[size];
+ CompilationUnitDeclaration[] cudArray
+ = new CompilationUnitDeclaration[size];
return cuds.toArray(cudArray);
} finally {
threadLogger.pop(oldLogger);
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
index 2a352e4..2b034de 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -26,7 +26,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -71,22 +70,6 @@
return map.get(key);
}
- private CompilationUnitDeclaration[] getDeclarations() {
- Set<CompilationUnitDeclaration> outSet = new HashSet<CompilationUnitDeclaration>();
- for (Iterator<ArrayList<CompilationUnitDeclaration>> iter = map.values().iterator(); iter.hasNext();) {
- List<CompilationUnitDeclaration> element = iter.next();
- outSet.addAll(element);
- }
- CompilationUnitDeclaration[] out = new CompilationUnitDeclaration[outSet.size()];
- int i = 0;
- for (Iterator<CompilationUnitDeclaration> iter = outSet.iterator(); iter.hasNext();) {
- CompilationUnitDeclaration element = iter.next();
- out[i] = element;
- i++;
- }
- return out;
- }
-
private void removeAll(Collection<String> c) {
map.keySet().removeAll(c);
}
@@ -98,7 +81,7 @@
super(sourceOracle, false);
}
- public CompilationUnitDeclaration[] getCompilationUnitDeclarations(
+ public CompilationUnitDeclaration[] getChangedCompilationUnitDeclarations(
TreeLogger logger, ICompilationUnit[] units) {
List<ICompilationUnit> allUnits = Arrays.asList(units);
List<ICompilationUnitAdapter> newUnits = new ArrayList<ICompilationUnitAdapter>();
@@ -117,12 +100,16 @@
CompilationUnitDeclaration[] newCuds = compile(logger, toBeProcessed);
// Put new cuds into cache.
+ List<CompilationUnitDeclaration> cudResults = new ArrayList<CompilationUnitDeclaration>();
for (int i = 0; i < newCuds.length; i++) {
- String newLoc = String.valueOf(newCuds[i].getFileName());
+ CompilationUnitDeclaration newCud = newCuds[i];
+ String newLoc = String.valueOf(newCud.getFileName());
cachedResults.remove(newLoc);
- cachedResults.add(newLoc, newCuds[i]);
+ cachedResults.add(newLoc, newCud);
+ cudResults.add(newCud);
}
- return cachedResults.getDeclarations();
+
+ return cudResults.toArray(new CompilationUnitDeclaration[] {});
}
public void invalidateChangedFiles(Set<String> changedFiles,
diff --git a/dev/core/src/com/google/gwt/dev/jdt/CacheManager.java b/dev/core/src/com/google/gwt/dev/jdt/CacheManager.java
index 2cec6ff..4164534 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/CacheManager.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/CacheManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -26,6 +26,7 @@
import com.google.gwt.dev.shell.ShellGWT;
import com.google.gwt.dev.shell.ShellJavaScriptHost;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.PerfLogger;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
@@ -588,8 +589,6 @@
private final Map<String, Long> timesByLocation = new HashMap<String, Long>();
- private boolean typeOracleBuilderFirstTime = true;
-
private final Map<String, ICompilationUnitAdapter> unitsByCup = new HashMap<String, ICompilationUnitAdapter>();
/**
@@ -626,6 +625,16 @@
}
SourceOracleOnTypeOracle sooto = new SourceOracleOnTypeOracle(this.oracle);
astCompiler = new AstCompiler(sooto);
+
+ astCompiler.setCachePolicy(new AstCompiler.CachePolicy() {
+ public boolean shouldProcess(CompilationUnitDeclaration cud) {
+ ICompilationUnit unit = cud.compilationResult.compilationUnit;
+ ICompilationUnitAdapter adapter = ((ICompilationUnitAdapter) unit);
+ CompilationUnitProvider cup = adapter.getCompilationUnitProvider();
+ return getTypeOracle()
+ .findType(cup.getPackageName(), cup.getMainTypeName()) == null;
+ }
+ });
}
/**
@@ -667,6 +676,32 @@
}
/**
+ * This removes all state changed since the last time the typeOracle was run.
+ *
+ * @param typeOracle
+ */
+ public void invalidateOnRefresh(TypeOracle typeOracle) {
+
+ // If a class is changed, the set of classes in the transitive closure
+ // of "refers to" must be marked changed as well.
+ // The initial change set is computed in addCompilationUnit.
+
+ changedFiles.addAll(generatedCupLocations);
+ addDependentsToChangedFiles();
+
+ for (Iterator<String> iter = changedFiles.iterator(); iter.hasNext();) {
+ String location = iter.next();
+ CompilationUnitProvider cup = getCupsByLocation().get(location);
+ unitsByCup.remove(location);
+ Util.invokeInaccessableMethod(TypeOracle.class,
+ "invalidateTypesInCompilationUnit",
+ new Class[]{CompilationUnitProvider.class}, typeOracle,
+ new Object[]{cup});
+ }
+ astCompiler.invalidateChangedFiles(changedFiles, invalidatedTypes);
+ }
+
+ /**
* Ensures that all compilation units generated via generators are removed
* from the system so that they will be generated again, and thereby take into
* account input that may have changed since the last reload.
@@ -826,38 +861,6 @@
}
/**
- * This removes all state changed since the last time the typeOracle was run.
- * Since the typeOracle information is not cached on disk, this is not needed
- * the first time.
- *
- * @param typeOracle
- */
- void invalidateOnRefresh(TypeOracle typeOracle) {
- // If a class is changed, the set of classes in the transitive closure
- // of "refers to" must be marked changed as well.
- // The initial change set is computed in addCompilationUnit.
- // For the first time we do not do this because the compiler
- // has no cached info.
- if (!isTypeOracleBuilderFirstTime()) {
- changedFiles.addAll(generatedCupLocations);
- addDependentsToChangedFiles();
-
- for (Iterator<String> iter = changedFiles.iterator(); iter.hasNext();) {
- String location = iter.next();
- CompilationUnitProvider cup = getCupsByLocation().get(location);
- unitsByCup.remove(location);
- Util.invokeInaccessableMethod(TypeOracle.class,
- "invalidateTypesInCompilationUnit",
- new Class[] {CompilationUnitProvider.class}, typeOracle,
- new Object[] {cup});
- }
- astCompiler.invalidateChangedFiles(changedFiles, invalidatedTypes);
- } else {
- becomeTypeOracleNotFirstTime();
- }
- }
-
- /**
* Was this cup, last modified at time lastModified modified since it was last
* processed by the system?
*/
@@ -904,6 +907,8 @@
* bytecode cache.
*/
void removeStaleByteCode(TreeLogger logger, AbstractCompiler compiler) {
+ PerfLogger.start("CacheManager.removeStaleByteCode");
+
if (cacheDir == null) {
byteCodeCache.clear();
return;
@@ -949,6 +954,7 @@
}
becomeNotFirstTime();
invalidateChangedFiles(logger, compiler);
+ PerfLogger.end();
}
void setTypeForBinding(ReferenceBinding binding, JClassType type) {
@@ -959,10 +965,6 @@
firstTime = false;
}
- private void becomeTypeOracleNotFirstTime() {
- typeOracleBuilderFirstTime = false;
- }
-
/**
* Actually performs the work of removing the invalidated data from the
* system. At this point, changedFiles should be complete. After this method
@@ -1006,8 +1008,4 @@
private boolean isGeneratedCup(CompilationUnitProvider cup) {
return generatedCupLocations.contains(cup.getLocation());
}
-
- private boolean isTypeOracleBuilderFirstTime() {
- return typeOracleBuilderFirstTime;
- }
}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
index bb6ae4b..1b84613 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -44,6 +44,7 @@
import com.google.gwt.dev.jdt.CacheManager.Mapper;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.PerfLogger;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
@@ -490,6 +491,8 @@
public TypeOracle build(final TreeLogger logger)
throws UnableToCompleteException {
+ PerfLogger.start("TypeOracleBuilder.build");
+
Set<CompilationUnitProvider> addedCups = cacheManager.getAddedCups();
TypeOracle oracle = cacheManager.getTypeOracle();
// Make a copy that we can sort.
@@ -533,9 +536,11 @@
Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
throw new UnableToCompleteException();
}
- cacheManager.invalidateOnRefresh(oracle);
- CompilationUnitDeclaration[] cuds = cacheManager.getAstCompiler().getCompilationUnitDeclarations(
+
+ PerfLogger.start("TypeOracleBuilder.build (compile)");
+ CompilationUnitDeclaration[] cuds = cacheManager.getAstCompiler().getChangedCompilationUnitDeclarations(
logger, units);
+ PerfLogger.end();
// Build a list that makes it easy to remove problems.
//
@@ -551,24 +556,6 @@
//
removeUnitsWithErrors(logger, cudsByFileName);
- // Also remove any compilation units that we've seen before.
- //
- for (Iterator<CompilationUnitDeclaration> iter = cudsByFileName.values().iterator(); iter.hasNext();) {
- CompilationUnitDeclaration cud = iter.next();
- // If we've seen this compilation unit before, the type oracle will
- // tell us about it and so we don't assimilate it again.
- //
- ICompilationUnit unit = cud.compilationResult.compilationUnit;
- ICompilationUnitAdapter adapter = ((ICompilationUnitAdapter) unit);
- CompilationUnitProvider cup = adapter.getCompilationUnitProvider();
- JClassType[] seen = oracle.getTypesInCompilationUnit(cup);
- if (seen.length > 0) {
- // This compilation unit has already been assimilated.
- //
- iter.remove();
- }
- }
-
// Perform a shallow pass to establish identity for new types.
//
final CacheManager.Mapper identityMapper = cacheManager.getIdentityMapper();
@@ -645,6 +632,9 @@
}
Util.invokeInaccessableMethod(TypeOracle.class, "refresh",
new Class[] {TreeLogger.class}, oracle, new Object[] {logger});
+
+ PerfLogger.end();
+
return oracle;
}
diff --git a/dev/core/src/com/google/gwt/dev/util/PerfLogger.java b/dev/core/src/com/google/gwt/dev/util/PerfLogger.java
new file mode 100644
index 0000000..5dd90d6
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/PerfLogger.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Performs basic recording/logging of performance metrics for internal
+ * development purposes.
+ *
+ * <p>This class differs from {@link
+ * com.google.gwt.core.ext.TreeLogger TreeLogger} by providing an interface more
+ * suitable for metrics-oriented logging.</p>
+ *
+ * <p>Performance logging can be enabled by setting the system property,
+ * {@code gwt.perflog=true}.</p>
+ *
+ */
+public class PerfLogger {
+
+ private static class Timing {
+
+ String message;
+
+ long startTimeNanos;
+
+ long totalTimeNanos;
+
+ Timing parent = null;
+
+ List<Timing> subTimings = new ArrayList<Timing>();
+
+ boolean messageOnly;
+
+ Timing(Timing parent, String message) {
+ this.parent = parent;
+ this.message = message;
+ this.startTimeNanos = System.nanoTime();
+ }
+
+ Timing() {
+ }
+
+ boolean isRoot() {
+ return parent == null;
+ }
+ }
+
+ /**
+ * Flag for enabling performance logging.
+ */
+ private static boolean enabled = Boolean
+ .parseBoolean(System.getProperty("gwt.perflog"));
+
+ private static ThreadLocal<Timing> currentTiming = new ThreadLocal<Timing>() {
+ protected Timing initialValue() {
+ return new Timing();
+ }
+ };
+
+ /**
+ * Ends the current timing.
+ */
+ public static void end() {
+ if (!enabled) {
+ return;
+ }
+ long endTimeNanos = System.nanoTime();
+ Timing timing = currentTiming.get();
+ if (timing.isRoot()) {
+ System.out.println("Tried to end a timing that was never started!\n");
+ return;
+ }
+ timing.totalTimeNanos = endTimeNanos - timing.startTimeNanos;
+
+ Timing newCurrent = timing.parent;
+ currentTiming.set(newCurrent);
+ if (newCurrent.isRoot()) {
+ printTimings();
+ newCurrent.subTimings = new ArrayList<Timing>();
+ }
+ }
+
+ /**
+ * Logs a message without explicitly including timer information.
+ *
+ * @param message a not <code>null</code> message
+ */
+ public static void log(String message) {
+ if (!enabled) {
+ start(message);
+ currentTiming.get().messageOnly = true;
+ end();
+ }
+ }
+
+ /**
+ * Starts a new timing corresponding to {@code message}. You must call {@link
+ * #end} for each corresponding call to {@code start}. You may nest timing
+ * calls.
+ *
+ * @param message a not <code>null</code> message.
+ */
+ public static void start(String message) {
+ if (!enabled) {
+ return;
+ }
+ Timing current = currentTiming.get();
+ Timing newTiming = new Timing(current, message);
+ current.subTimings.add(newTiming);
+ currentTiming.set(newTiming);
+ }
+
+ private static String getIndentString(int level) {
+ StringBuffer str = new StringBuffer(level * 2);
+ for (int i = 0; i < level; ++i) {
+ str.append(" ");
+ }
+ return str.toString();
+ }
+
+ private static void printTiming(Timing t, int depth) {
+ if (!t.isRoot()) {
+ StringBuffer msg = new StringBuffer(getIndentString(depth - 1));
+ msg.append("[perf] ");
+ msg.append(t.message);
+ if (!t.messageOnly) {
+ msg.append(" ");
+ msg.append((double) (t.totalTimeNanos / 1000000.0));
+ msg.append("ms");
+ }
+ System.out.println(msg);
+ }
+
+ ++depth;
+ for (Timing subTiming : t.subTimings) {
+ printTiming(subTiming, depth);
+ }
+ }
+
+ private static void printTimings() {
+ printTiming(currentTiming.get(), 0);
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index a9b3b98..2237ccd 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -365,7 +365,9 @@
protected ModuleDef doLoadModule(TreeLogger logger, String moduleName)
throws UnableToCompleteException {
- ModuleDef module = super.doLoadModule(logger, moduleName);
+ // We don't refresh modules while running unit tests
+ ModuleDef module = ModuleDefLoader
+ .loadFromClassPath(logger, moduleName, false);
// Tweak the module for JUnit support
//
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 3debe48..5ae643d 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2007 Google Inc.
- *
+ * Copyright 2008 Google Inc.
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -25,11 +25,9 @@
import com.google.gwt.user.client.ui.FlexTableTest;
import com.google.gwt.user.client.ui.FlowPanelTest;
import com.google.gwt.user.client.ui.FocusPanelTest;
-import com.google.gwt.user.client.ui.FormPanelTest;
import com.google.gwt.user.client.ui.GridTest;
import com.google.gwt.user.client.ui.HTMLPanelTest;
import com.google.gwt.user.client.ui.HiddenTest;
-import com.google.gwt.user.client.ui.HistoryTest;
import com.google.gwt.user.client.ui.HorizontalPanelTest;
import com.google.gwt.user.client.ui.ImageTest;
import com.google.gwt.user.client.ui.LinearPanelTest;
@@ -72,10 +70,10 @@
suite.addTestSuite(FlexTableTest.class);
suite.addTestSuite(FlowPanelTest.class);
suite.addTestSuite(FocusPanelTest.class);
- suite.addTestSuite(FormPanelTest.class);
+ // suite.addTestSuite(FormPanelTest.class);
suite.addTestSuite(GridTest.class);
suite.addTestSuite(HiddenTest.class);
- suite.addTestSuite(HistoryTest.class);
+ // suite.addTestSuite(HistoryTest.class);
suite.addTestSuite(HorizontalPanelTest.class);
suite.addTestSuite(HTMLPanelTest.class);
suite.addTestSuite(ImageTest.class);