Remove UnifiedAST memory calculation and clean up instance-creation aspects of UnifiedAST.
This patch is in preparation for pluggable CompilePerms workers.
Patch by: scottb
Review by: bobv
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4129 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/PermutationCompiler.java b/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
index f89b102..3b6f85d 100644
--- a/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/PermutationCompiler.java
@@ -19,9 +19,8 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.StaticPropertyOracle;
-import com.google.gwt.dev.jjs.UnifiedAst;
import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
-import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.UnifiedAst;
import com.google.gwt.dev.util.PerfLogger;
import java.util.concurrent.BlockingQueue;
@@ -191,14 +190,6 @@
});
}
- if (!hasEnoughMemory()) {
- /*
- * Not enough memory to run, but if there are multiple threads, we can
- * try again with fewer threads.
- */
- tryToExitNonFinalThread(outOfMemoryRetryAction);
- }
-
boolean definitelyFinalThread = (threadCount.get() == 1);
try {
String result = currentTask.call();
@@ -247,26 +238,6 @@
}
/**
- * Returns <code>true</code> if there is enough estimated memory to run
- * another permutation, or if this is the last live worker thread and we
- * have no choice.
- */
- private boolean hasEnoughMemory() {
- if (threadCount.get() == 1) {
- // I'm the last thread, so I have to at least try.
- return true;
- }
-
- if (astMemoryUsage >= getPotentialFreeMemory()) {
- return true;
- }
-
- // Best effort memory reclaim.
- System.gc();
- return astMemoryUsage < getPotentialFreeMemory();
- }
-
- /**
* Exits this thread if and only if it's not the last running thread,
* performing the specified action before terminating.
*
@@ -294,21 +265,6 @@
private static final Result FINISHED_RESULT = new Result(null, -1) {
};
- private static long getPotentialFreeMemory() {
- long used = Runtime.getRuntime().totalMemory()
- - Runtime.getRuntime().freeMemory();
- assert (used > 0);
- long potentialFree = Runtime.getRuntime().maxMemory() - used;
- assert (potentialFree >= 0);
- return potentialFree;
- }
-
- /**
- * Holds an estimate of how many bytes of memory a new concurrent compilation
- * will consume.
- */
- protected final long astMemoryUsage;
-
/**
* A queue of results being sent from worker threads to the main thread.
*/
@@ -329,7 +285,6 @@
public PermutationCompiler(TreeLogger logger, UnifiedAst unifiedAst,
Permutation[] perms, int[] permsToRun) {
this.logger = logger;
- this.astMemoryUsage = unifiedAst.getAstMemoryUsage();
for (int permToRun : permsToRun) {
tasks.add(new PermutationTask(logger, unifiedAst, perms[permToRun],
permToRun));
@@ -387,52 +342,10 @@
result = Math.min(Runtime.getRuntime().availableProcessors(), result);
/*
- * Allow user-defined override as an escape valve.
+ * User-defined value caps.
*/
- result = Math.min(result, Integer.getInteger("gwt.jjs.maxThreads", result));
+ result = Math.min(result, Integer.getInteger("gwt.jjs.maxThreads", 1));
- if (result == 1) {
- return 1;
- }
-
- // More than one thread would definitely be faster at this point.
-
- if (JProgram.isTracingEnabled()) {
- logger.log(TreeLogger.INFO,
- "Parallel compilation disabled due to gwt.jjs.traceMethods being enabled");
- return 1;
- }
-
- int desiredThreads = result;
-
- /*
- * Need to do some memory estimation to figure out how many concurrent
- * threads we can safely run.
- */
- long potentialFreeMemory = getPotentialFreeMemory();
- int extraMemUsageThreads = (int) (potentialFreeMemory / astMemoryUsage);
- logger.log(TreeLogger.TRACE,
- "Extra threads constrained by estimated memory usage: "
- + extraMemUsageThreads + " = " + potentialFreeMemory + " / "
- + astMemoryUsage);
- int memUsageThreads = extraMemUsageThreads + 1;
-
- if (memUsageThreads < desiredThreads) {
- long currentMaxMemory = Runtime.getRuntime().maxMemory();
- // Convert to megabytes.
- currentMaxMemory /= 1024 * 1024;
-
- long suggestedMaxMemory = currentMaxMemory * 2;
-
- logger.log(TreeLogger.WARN, desiredThreads
- + " threads could be run concurrently, but only " + memUsageThreads
- + " threads will be run due to limited memory; "
- + "increasing the amount of memory by using the -Xmx flag "
- + "at startup (java -Xmx" + suggestedMaxMemory
- + "M ...) may result in faster compiles");
- }
-
- result = Math.min(memUsageThreads, desiredThreads);
return result;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index a78a2d1..96f2f59 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -255,8 +255,6 @@
JsProgram jsProgram = new JsProgram();
try {
- long usedMemoryBefore = singlePermutation ? 0 : getUsedMemory();
-
/*
* (1) Build a flattened map of TypeDeclarations => JType. The resulting
* map contains entries for all reference types. BuildTypeMap also parses
@@ -276,10 +274,6 @@
GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, jsProgram,
options.isEnableAssertions());
- long usedMemoryAfter = singlePermutation ? 0 : getUsedMemory();
- long memoryDelta = usedMemoryAfter - usedMemoryBefore;
- long astMemoryUsage = (long) (memoryDelta * 1.5);
-
// GenerateJavaAST can uncover semantic JSNI errors; report & abort
checkForErrors(logger, goldenCuds, true);
@@ -329,7 +323,7 @@
RecordRebinds.exec(jprogram, rebindRequests);
return new UnifiedAst(options, new AST(jprogram, jsProgram),
- singlePermutation, astMemoryUsage, rebindRequests);
+ singlePermutation, rebindRequests);
} catch (Throwable e) {
throw logAndTranslateException(logger, e);
} finally {
@@ -565,14 +559,6 @@
return null;
}
- private static long getUsedMemory() {
- System.gc();
- long used = Runtime.getRuntime().totalMemory()
- - Runtime.getRuntime().freeMemory();
- assert (used > 0);
- return used;
- }
-
private static UnableToCompleteException logAndTranslateException(
TreeLogger logger, Throwable e) {
if (e instanceof UnableToCompleteException) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/UnifiedAst.java b/dev/core/src/com/google/gwt/dev/jjs/UnifiedAst.java
index a5e85b0..6dfc5fe 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/UnifiedAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/UnifiedAst.java
@@ -57,10 +57,42 @@
}
}
- /**
- * Estimated AST memory usage.
- */
- private long astMemoryUsage;
+ private static AST deserializeAst(byte[] serializedAst) {
+ try {
+ PerfLogger.start("deserialize");
+ ByteArrayInputStream bais = new ByteArrayInputStream(serializedAst);
+ ObjectInputStream is;
+ is = new ObjectInputStream(bais);
+ JProgram jprogram = (JProgram) is.readObject();
+ JsProgram jsProgram = (JsProgram) is.readObject();
+ return new AST(jprogram, jsProgram);
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Should be impossible for memory based streams", e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(
+ "Should be impossible when deserializing in process", e);
+ } finally {
+ PerfLogger.end();
+ }
+ }
+
+ private static byte[] serializeAst(AST ast) {
+ try {
+ PerfLogger.start("serialize");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream os = new ObjectOutputStream(baos);
+ os.writeObject(ast.getJProgram());
+ os.writeObject(ast.getJsProgram());
+ os.close();
+ return baos.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Should be impossible for memory based streams", e);
+ } finally {
+ PerfLogger.end();
+ }
+ }
/**
* The original AST; nulled out once consumed (by the first call to
@@ -84,31 +116,17 @@
private final SortedSet<String> rebindRequests;
/**
- * The serialized form of savedAst.
+ * The serialized AST.
*/
private byte[] serializedAst;
- /**
- * If <code>true</code>, only one permutation will be run, so we don't need
- * to serialize our AST (unless this whole object is about to be serialized).
- */
- private transient boolean singlePermutation;
-
public UnifiedAst(JJSOptions options, AST initialAst,
- boolean singlePermutation, long astMemoryUsage, Set<String> rebindRequests) {
+ boolean singlePermutation, Set<String> rebindRequests) {
this.options = new JJSOptionsImpl(options);
this.initialAst = initialAst;
- this.singlePermutation = singlePermutation;
- this.astMemoryUsage = astMemoryUsage;
this.rebindRequests = Collections.unmodifiableSortedSet(new TreeSet<String>(
rebindRequests));
- }
-
- /**
- * Returns a rough estimate of how much memory an AST will take up.
- */
- public long getAstMemoryUsage() {
- return astMemoryUsage;
+ this.serializedAst = singlePermutation ? null : serializeAst(initialAst);
}
/**
@@ -128,42 +146,19 @@
AST getFreshAst() {
synchronized (myLockObject) {
if (initialAst != null) {
- if (!singlePermutation && serializedAst == null) {
- // Must preserve a serialized copy for future calls.
- serializeAst();
- }
AST result = initialAst;
initialAst = null;
return result;
} else {
if (serializedAst == null) {
- throw new IllegalStateException("No serialized AST was cached.");
+ throw new IllegalStateException(
+ "No serialized AST was cached and AST was already consumed.");
}
- return deserializeAst();
+ return deserializeAst(serializedAst);
}
}
}
- private AST deserializeAst() {
- try {
- PerfLogger.start("deserialize");
- ByteArrayInputStream bais = new ByteArrayInputStream(serializedAst);
- ObjectInputStream is;
- is = new ObjectInputStream(bais);
- JProgram jprogram = (JProgram) is.readObject();
- JsProgram jsProgram = (JsProgram) is.readObject();
- return new AST(jprogram, jsProgram);
- } catch (IOException e) {
- throw new RuntimeException(
- "Should be impossible for memory based streams", e);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(
- "Should be impossible when deserializing in process", e);
- } finally {
- PerfLogger.end();
- }
- }
-
/**
* Re-initialize lock object.
*/
@@ -172,35 +167,17 @@
return this;
}
- private void serializeAst() {
- try {
- assert (initialAst != null);
- assert (serializedAst == null);
- PerfLogger.start("serialize");
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream os = new ObjectOutputStream(baos);
- os.writeObject(initialAst.getJProgram());
- os.writeObject(initialAst.getJsProgram());
- os.close();
- serializedAst = baos.toByteArray();
-
- // Very rough heuristic.
- astMemoryUsage = Math.max(astMemoryUsage, serializedAst.length * 4);
- } catch (IOException e) {
- throw new RuntimeException(
- "Should be impossible for memory based streams", e);
- } finally {
- PerfLogger.end();
- }
- }
-
/**
* Force byte serialization of AST before writing.
*/
private Object writeReplace() {
- synchronized (myLockObject) {
- if (serializedAst == null) {
- serializeAst();
+ if (serializedAst == null) {
+ synchronized (myLockObject) {
+ if (initialAst == null) {
+ throw new IllegalStateException(
+ "No serialized AST was cached and AST was already consumed.");
+ }
+ serializedAst = serializeAst(initialAst);
}
}
return this;