Skip to content
This repository was archived by the owner on Sep 26, 2020. It is now read-only.

Commit 72320e4

Browse files
author
stalcup@google.com
committed
reduces Java AST optimization time by bailing out when the rate of change slows to a crawl (only applies on optimization levels less than 9)
Change-Id: Iabf844d6a02f694e8d14103377f74f46e4e01915 Review-Link: https://gwt-review.googlesource.com/#/c/2580/ Review by: rluble@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11600 8db76d5a-ed1c-0410-87a9-c151d255dfc7
1 parent d2bfe5f commit 72320e4

File tree

1 file changed

+53
-16
lines changed

1 file changed

+53
-16
lines changed

dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,34 @@ public boolean visit(JNode x, Context ctx) {
251251

252252
private static final String ENUM_NAME_OBFUSCATION_PROPERTY = "compiler.enum.obfuscate.names";
253253

254+
/**
255+
* Continuing to apply optimizations till the rate of change reaches this value causes the AST to
256+
* reach a fixed point.
257+
*/
258+
private static final int FIXED_POINT_CHANGE_RATE = 0;
259+
260+
/**
261+
* Ending optimization passes when the rate of change has reached this value results in
262+
* gaining nearly all of the impact while avoiding the long tail of costly but low-impact passes.
263+
*/
264+
private static final float EFFICIENT_CHANGE_RATE = 0.01f;
265+
266+
/**
267+
* Limits the number of optimization passes against the possible danger of an AST that does not
268+
* converge.
269+
*/
270+
private static final int MAX_PASSES = 100;
271+
254272
/**
255273
* Compiles a particular permutation, based on a precompiled unified AST.
256274
*
257275
* @param logger the logger to use
258-
* @param unifiedAst the result of a
259-
* {@link #precompile(TreeLogger, ModuleDef, RebindPermutationOracle, String[], String[], JJSOptions, boolean, PrecompilationMetricsArtifact)}
276+
* @param unifiedAst the result of a {@link #precompile(TreeLogger, ModuleDef,
277+
* RebindPermutationOracle, String[], String[], JJSOptions, boolean,
278+
* PrecompilationMetricsArtifact)}
260279
* @param permutation the permutation to compile
261280
* @return the output JavaScript
262-
* @throws UnableToCompleteException if an error other than
263-
* {@link OutOfMemoryError} occurs
281+
* @throws UnableToCompleteException if an error other than {@link OutOfMemoryError} occurs
264282
*/
265283
public static PermutationResult compilePermutation(TreeLogger logger, UnifiedAst unifiedAst,
266284
Permutation permutation) throws UnableToCompleteException {
@@ -768,11 +786,16 @@ protected static void optimize(JJSOptions options, JProgram jprogram)
768786
Event optimizeEvent = SpeedTracerLogger.start(CompilerEventType.OPTIMIZE);
769787

770788
List<OptimizerStats> allOptimizerStats = new ArrayList<OptimizerStats>();
771-
int counter = 0;
772-
int optimizationLevel = options.getOptimizationLevel();
789+
int passCount = 0;
790+
int nodeCount = getNodeCount(jprogram);
791+
int lastNodeCount;
792+
793+
boolean atMaxLevel = options.getOptimizationLevel() == OptionOptimize.OPTIMIZE_LEVEL_MAX;
794+
int passLimit = atMaxLevel ? MAX_PASSES : options.getOptimizationLevel();
795+
float minChangeRate = atMaxLevel ? FIXED_POINT_CHANGE_RATE : EFFICIENT_CHANGE_RATE;
773796
while (true) {
774-
counter++;
775-
if (optimizationLevel < OptionOptimize.OPTIMIZE_LEVEL_MAX && counter > optimizationLevel) {
797+
passCount++;
798+
if (passCount > passLimit) {
776799
break;
777800
}
778801
if (Thread.interrupted()) {
@@ -781,9 +804,14 @@ protected static void optimize(JJSOptions options, JProgram jprogram)
781804
}
782805
AstDumper.maybeDumpAST(jprogram);
783806
OptimizerStats stats =
784-
optimizeLoop("Pass " + counter, jprogram, options.isAggressivelyOptimize());
807+
optimizeLoop("Pass " + passCount, jprogram, options.isAggressivelyOptimize(), nodeCount);
785808
allOptimizerStats.add(stats);
786-
if (!stats.didChange()) {
809+
lastNodeCount = nodeCount;
810+
nodeCount = getNodeCount(jprogram);
811+
812+
float nodeChangeRate = stats.getNumMods() / (float) lastNodeCount;
813+
float sizeChangeRate = (lastNodeCount - nodeCount) / (float) lastNodeCount;
814+
if (nodeChangeRate <= minChangeRate && sizeChangeRate <= minChangeRate) {
787815
break;
788816
}
789817
}
@@ -849,15 +877,15 @@ protected static void optimizeJs(JJSOptions options, JsProgram jsProgram,
849877

850878
protected static OptimizerStats optimizeLoop(String passName, JProgram jprogram,
851879
boolean isAggressivelyOptimize) {
852-
Event optimizeEvent = SpeedTracerLogger.start(CompilerEventType.OPTIMIZE, "phase", "loop");
853-
854-
// Count the number of nodes in the AST so we can measure the efficiency of
855-
// the optimizers.
856-
Event countEvent = SpeedTracerLogger.start(CompilerEventType.OPTIMIZE, "phase", "countNodes");
857880
TreeStatistics treeStats = new TreeStatistics();
858881
treeStats.accept(jprogram);
859882
int numNodes = treeStats.getNodeCount();
860-
countEvent.end();
883+
return optimizeLoop("Early Optimization", jprogram, false, numNodes);
884+
}
885+
886+
protected static OptimizerStats optimizeLoop(String passName, JProgram jprogram,
887+
boolean isAggressivelyOptimize, int numNodes) {
888+
Event optimizeEvent = SpeedTracerLogger.start(CompilerEventType.OPTIMIZE, "phase", "loop");
861889

862890
// Recompute clinits each time, they can become empty.
863891
jprogram.typeOracle.recomputeAfterOptimizations();
@@ -911,6 +939,15 @@ protected static OptimizerStats optimizeLoop(String passName, JProgram jprogram,
911939
return stats;
912940
}
913941

942+
private static int getNodeCount(JProgram jProgram) {
943+
Event countEvent = SpeedTracerLogger.start(CompilerEventType.OPTIMIZE, "phase", "countNodes");
944+
TreeStatistics treeStats = new TreeStatistics();
945+
treeStats.accept(jProgram);
946+
int numNodes = treeStats.getNodeCount();
947+
countEvent.end();
948+
return numNodes;
949+
}
950+
914951
private static MultipleDependencyGraphRecorder chooseDependencyRecorder(boolean soycEnabled,
915952
OutputStream out) {
916953
MultipleDependencyGraphRecorder dependencyRecorder = CodeSplitter.NULL_RECORDER;

0 commit comments

Comments
 (0)