# HG changeset patch # User Doug Simon # Date 1415301287 -3600 # Node ID 5415422cb32f821210253749c09b0a23da503043 # Parent e7d219e9d01f8b5406dd490f386c5913ccc94680# Parent f1a988d9213ff22e6be27b4cffa5290bdbd46468 Merge. diff -r e7d219e9d01f -r 5415422cb32f CHANGELOG.md --- a/CHANGELOG.md Thu Nov 06 20:13:08 2014 +0100 +++ b/CHANGELOG.md Thu Nov 06 20:14:47 2014 +0100 @@ -15,6 +15,7 @@ * Renamed DirectCallNode#split to DirectCallNode#cloneCallTarget * Renamed DirectCallNode#isSplit to DirectCallNode#isCallTargetCloned * Added PrimitiveValueProfile. +* Added -G:TruffleTimeThreshold=5000 option to defer compilation for call targets * ... ## Version 0.5 diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Thu Nov 06 20:14:47 2014 +0100 @@ -116,12 +116,13 @@ private RootCallTarget createCallTargetImpl(OptimizedCallTarget source, RootNode rootNode) { CompilationPolicy compilationPolicy; if (acceptForCompilation(rootNode)) { - compilationPolicy = new CounterBasedCompilationPolicy(); + compilationPolicy = new CounterAndTimeBasedCompilationPolicy(); } else { compilationPolicy = new InterpreterOnlyCompilationPolicy(); } OptimizedCallTarget target = new OptimizedCallTarget(source, rootNode, this, compilationPolicy, new HotSpotSpeculationLog()); callTargets.put(target, null); + return target; } diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Thu Nov 06 20:14:47 2014 +0100 @@ -28,16 +28,21 @@ public class CompilationProfile { + private static final int TIMESTAMP_THRESHOLD = Math.max(TruffleCompilationThreshold.getValue() / 2, 1); + /** * Number of times an installed code for this tree was invalidated. */ private int invalidationCount; + private int deferedCount; private int interpreterCallCount; private int interpreterCallAndLoopCount; private int compilationCallThreshold; private int compilationCallAndLoopThreshold; + private long timestamp; + public CompilationProfile() { this.compilationCallThreshold = TruffleMinInvokeThreshold.getValue(); this.compilationCallAndLoopThreshold = TruffleCompilationThreshold.getValue(); @@ -54,8 +59,8 @@ String callsThreshold = String.format("%7d/%5d", getInterpreterCallCount(), getCompilationCallThreshold()); String loopsThreshold = String.format("%7d/%5d", getInterpreterCallAndLoopCount(), getCompilationCallAndLoopThreshold()); String invalidations = String.format("%5d", invalidationCount); - properties.put("C/T", callsThreshold); - properties.put("L/T", loopsThreshold); + properties.put("Calls/Thres", callsThreshold); + properties.put("CallsAndLoop/Thres", loopsThreshold); properties.put("Inval#", invalidations); return properties; } @@ -72,6 +77,10 @@ return interpreterCallCount; } + public int getDeferedCount() { + return deferedCount; + } + public int getCompilationCallAndLoopThreshold() { return compilationCallAndLoopThreshold; } @@ -101,6 +110,11 @@ public void reportInterpreterCall() { interpreterCallCount++; interpreterCallAndLoopCount++; + + int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount; + if (callsMissing == TIMESTAMP_THRESHOLD) { + timestamp = System.nanoTime(); + } } public void reportDirectCall() { @@ -115,8 +129,19 @@ } + public void deferCompilation() { + ensureProfiling(0, TIMESTAMP_THRESHOLD + 1); + timestamp = 0; + deferedCount++; + } + void reportLoopCount(int count) { interpreterCallAndLoopCount += count; + + int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount; + if (callsMissing <= TIMESTAMP_THRESHOLD && callsMissing + count > TIMESTAMP_THRESHOLD) { + timestamp = System.nanoTime(); + } } void reportNodeReplaced() { @@ -125,4 +150,7 @@ ensureProfiling(1, replaceBackoff); } + public long getTimestamp() { + return timestamp; + } } diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CounterAndTimeBasedCompilationPolicy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CounterAndTimeBasedCompilationPolicy.java Thu Nov 06 20:14:47 2014 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle; + +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; + +public class CounterAndTimeBasedCompilationPolicy extends CounterBasedCompilationPolicy { + + private static final long threshold = TruffleTimeThreshold.getValue() * 1_000_000L; + + @Override + public boolean shouldCompile(CompilationProfile profile) { + if (super.shouldCompile(profile)) { + long time = profile.getTimestamp(); + if (time == 0) { + throw new AssertionError(); + } + long timeElapsed = System.nanoTime() - time; + if (timeElapsed > threshold) { + profile.deferCompilation(); + return false; + } + return true; + } else { + return false; + } + } + +} diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleCompilationListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleCompilationListener.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleCompilationListener.java Thu Nov 06 20:14:47 2014 +0100 @@ -24,18 +24,48 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.nodes.*; -import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; +/** + * Enables implementations of this interface to listen to compilation related events of the Graal + * Truffle runtime. The states for a particular {@link OptimizedCallTarget} that is compiled using + * the Graal Truffle system can be described using the following deterministic automata: * + *
+ * ( (split | (queue . unqueue))*
+ *    . queue . started
+ *    . (truffleTierFinished . graalTierFinished . success)
+ *      | ([truffleTierFinished] . [graalTierFinished] . failed)
+ *    . invalidate )*
+ * 
+ *
+ *

+ * Note: | is the 'or' and . is the sequential operator. The + * * represents the Kleene Closure. + *

+ * + * @see GraalTruffleRuntime#addCompilationListener(GraalTruffleCompilationListener) + */ public interface GraalTruffleCompilationListener { + void notifyCompilationSplit(OptimizedDirectCallNode callNode); + + /** + * Invoked if a call target was queued to the compilation queue. + */ void notifyCompilationQueued(OptimizedCallTarget target); + /** + * Invoked if a call target was unqueued from the compilation queue. + * + * @param source the source object that caused the compilation to be unqueued. For example the + * source {@link Node} object. May be null. + * @param reason a textual description of the reason why the compilation was unqueued. May be + * null. + */ void notifyCompilationDequeued(OptimizedCallTarget target, Object source, CharSequence reason); void notifyCompilationFailed(OptimizedCallTarget target, StructuredGraph graph, Throwable t); - void notifyCompilationSplit(OptimizedDirectCallNode callNode); - void notifyCompilationStarted(OptimizedCallTarget target); void notifyCompilationTruffleTierFinished(OptimizedCallTarget target, StructuredGraph graph); @@ -44,8 +74,24 @@ void notifyCompilationSuccess(OptimizedCallTarget target, StructuredGraph graph, CompilationResult result); + /** + * Invoked if a compiled call target was invalidated. + * + * @param source the source object that caused the compilation to be invalidated. For example + * the source {@link Node} object. May be null. + * @param reason a textual description of the reason why the compilation was invalidated. May be + * null. + */ void notifyCompilationInvalidated(OptimizedCallTarget target, Object source, CharSequence reason); - void notifyShutdown(TruffleRuntime runtime); + /** + * Invoked as the compiler gets shut down. + */ + void notifyShutdown(GraalTruffleRuntime runtime); + + /** + * Invoked as soon as the compiler is ready to use. + */ + void notifyStartup(GraalTruffleRuntime runtime); } diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Thu Nov 06 20:14:47 2014 +0100 @@ -66,6 +66,7 @@ TraceSplittingListener.install(this); PrintCallTargetProfiling.install(this); CompilationStatisticsListener.install(this); + compilationNotify.notifyStartup(this); } protected void lookupCallMethods(MetaAccessProvider metaAccess) { @@ -283,9 +284,13 @@ compilationListeners.forEach(l -> l.notifyCompilationTruffleTierFinished(target, graph)); } - public void notifyShutdown(TruffleRuntime runtime) { + public void notifyShutdown(GraalTruffleRuntime runtime) { compilationListeners.forEach(l -> l.notifyShutdown(runtime)); } + public void notifyStartup(GraalTruffleRuntime runtime) { + compilationListeners.forEach(l -> l.notifyStartup(runtime)); + } + } } diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Thu Nov 06 20:14:47 2014 +0100 @@ -54,6 +54,7 @@ protected final CompilationPolicy compilationPolicy; private final OptimizedCallTarget sourceCallTarget; private final AtomicInteger callSitesKnown = new AtomicInteger(0); + @CompilationFinal private Class[] profiledArgumentTypes; @CompilationFinal private Assumption profiledArgumentTypesAssumption; @CompilationFinal private Class profiledReturnType; @@ -238,7 +239,7 @@ // We are called and we are still in Truffle interpreter mode. interpreterCall(); } else { - // We come here from compiled code (i.e., we have been inlined). + // We come here from compiled code } return callRoot(args); @@ -418,8 +419,8 @@ @Override public void nodeReplaced(Node oldNode, Node newNode, CharSequence reason) { + CompilerAsserts.neverPartOfCompilation(); if (isValid()) { - CompilerAsserts.neverPartOfCompilation(); invalidate(newNode, reason); } /* Notify compiled method that have inlined this call target that the tree changed. */ diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu Nov 06 20:14:47 2014 +0100 @@ -45,6 +45,8 @@ public static final OptionValue TruffleCompileOnly = new OptionValue<>(null); @Option(help = "Compile call target when call count exceeds this threshold") public static final OptionValue TruffleCompilationThreshold = new OptionValue<>(1000); + @Option(help = "Defines the maximum timespan in milliseconds that is required for a call target to be queued for compilation.") + public static final OptionValue TruffleTimeThreshold = new OptionValue<>(5000); @Option(help = "Minimum number of calls before a call target is compiled") public static final OptionValue TruffleMinInvokeThreshold = new OptionValue<>(3); @Option(help = "Delay compilation after an invalidation to allow for reprofiling") diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java Thu Nov 06 20:14:47 2014 +0100 @@ -29,7 +29,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.truffle.*; -import com.oracle.truffle.api.*; public abstract class AbstractDebugCompilationListener implements GraalTruffleCompilationListener { @@ -62,16 +61,20 @@ public void notifyCompilationInvalidated(OptimizedCallTarget target, Object source, CharSequence reason) { } - public void notifyShutdown(TruffleRuntime runtime) { + public void notifyShutdown(GraalTruffleRuntime runtime) { + } + + public void notifyStartup(GraalTruffleRuntime runtime) { } public static void log(int indent, String msg, String details, Map properties) { + int spaceIndent = indent * 2; StringBuilder sb = new StringBuilder(); sb.append(String.format("[truffle] %-16s ", msg)); - for (int i = 0; i < indent; i++) { + for (int i = 0; i < spaceIndent; i++) { sb.append(' '); } - sb.append(String.format("%-" + (60 - indent) + "s", details)); + sb.append(String.format("%-" + (60 - spaceIndent) + "s", details)); if (properties != null) { for (String property : properties.keySet()) { Object value = properties.get(property); diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/CompilationStatisticsListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/CompilationStatisticsListener.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/CompilationStatisticsListener.java Thu Nov 06 20:14:47 2014 +0100 @@ -34,7 +34,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.truffle.*; import com.oracle.graal.truffle.TruffleInlining.CallTreeNodeVisitor; -import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.Node; @@ -50,6 +49,10 @@ private int dequeues; private int splits; + private final IntSummaryStatistics deferCompilations = new IntSummaryStatistics(); + private final LongSummaryStatistics timeToQueue = new LongSummaryStatistics(); + private final LongSummaryStatistics timeToCompilation = new LongSummaryStatistics(); + private final IntSummaryStatistics nodeCount = new IntSummaryStatistics(); private final IntSummaryStatistics nodeCountTrivial = new IntSummaryStatistics(); private final IntSummaryStatistics nodeCountNonTrivial = new IntSummaryStatistics(); @@ -105,6 +108,7 @@ if (firstCompilation == 0) { firstCompilation = System.nanoTime(); } + timeToQueue.accept(System.nanoTime() - target.getCompilationProfile().getTimestamp()); } @Override @@ -130,6 +134,9 @@ CompilationLocal local = new CompilationLocal(); local.compilationStarted = System.nanoTime(); compilationLocal.set(local); + + deferCompilations.accept(target.getCompilationProfile().getDeferedCount()); + timeToCompilation.accept(local.compilationStarted - target.getCompilationProfile().getTimestamp()); } @Override @@ -197,8 +204,8 @@ } @Override - public void notifyShutdown(TruffleRuntime runtime) { - printStatistics((GraalTruffleRuntime) runtime, OUT); + public void notifyShutdown(GraalTruffleRuntime runtime) { + printStatistics(runtime, OUT); } public void printStatistics(GraalTruffleRuntime runtime, PrintStream out) { @@ -216,6 +223,10 @@ printStatistic("Queue Accuracy", 1.0 - dequeues / (double) queues); printStatistic("Compilation Utilization", compilationTime.getSum() / (double) (endTime - firstCompilation)); printStatistic("Remaining Compilation Queue", runtime.getQueuedCallTargets().size()); + printStatistic("Times defered until compilation", deferCompilations); + + printStatisticTime("Time to queue", timeToQueue); + printStatisticTime("Time to compilation", timeToCompilation); printStatisticTime("Compilation time", compilationTime); printStatisticTime(" Truffle Tier", compilationTimeTruffleTier); diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/PrintCallTargetProfiling.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/PrintCallTargetProfiling.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/PrintCallTargetProfiling.java Thu Nov 06 20:14:47 2014 +0100 @@ -40,7 +40,7 @@ } @Override - public void notifyShutdown(TruffleRuntime runtime) { + public void notifyShutdown(GraalTruffleRuntime runtime) { Map> groupedTargets = Truffle.getRuntime().getCallTargets().stream().map(target -> (OptimizedCallTarget) target).collect( Collectors.groupingBy(target -> { if (target.getSourceCallTarget() != null) { diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationCallTreeListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationCallTreeListener.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationCallTreeListener.java Thu Nov 06 20:14:47 2014 +0100 @@ -65,10 +65,10 @@ addASTSizeProperty(callNode.getCurrentCallTarget(), properties); properties.putAll(callNode.getCurrentCallTarget().getDebugProperties()); properties.put("Stamp", callNode.getCurrentCallTarget().getArgumentStamp()); - log((depth * 2), "opt call tree", callNode.getCurrentCallTarget().toString() + dispatched, properties); + log(depth, "opt call tree", callNode.getCurrentCallTarget().toString() + dispatched, properties); } else if (node instanceof OptimizedIndirectCallNode) { int depth = decisionStack == null ? 0 : decisionStack.size() - 1; - log((depth * 2), "opt call tree", "", new LinkedHashMap()); + log(depth, "opt call tree", "", new LinkedHashMap()); } return true; } diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceInliningListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceInliningListener.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceInliningListener.java Thu Nov 06 20:14:47 2014 +0100 @@ -24,8 +24,6 @@ import static com.oracle.graal.truffle.TruffleCompilerOptions.*; -import java.util.*; - import com.oracle.graal.nodes.*; import com.oracle.graal.truffle.*; @@ -57,19 +55,11 @@ TruffleInliningProfile profile = decision.getProfile(); boolean inlined = decision.isInline(); String msg = inlined ? "inline success" : "inline failed"; - logInlinedImpl(msg, decision.getProfile().getCallNode(), profile, depth); + log(depth, msg, decision.getProfile().getCallNode().getCurrentCallTarget().toString(), profile.getDebugProperties()); if (inlined) { logInliningDecisionRecursive(decision, depth + 1); } } } - private static void logInlinedImpl(String status, OptimizedDirectCallNode callNode, TruffleInliningProfile profile, int depth) { - Map properties = new LinkedHashMap<>(); - if (profile != null) { - properties.putAll(profile.getDebugProperties()); - } - log((depth * 2), status, callNode.getCurrentCallTarget().toString(), properties); - } - } diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TracePerformanceWarningsListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TracePerformanceWarningsListener.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TracePerformanceWarningsListener.java Thu Nov 06 20:14:47 2014 +0100 @@ -26,7 +26,6 @@ import java.util.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.truffle.*; public final class TracePerformanceWarningsListener extends AbstractDebugCompilationListener { @@ -40,10 +39,6 @@ } } - @Override - public void notifyCompilationTruffleTierFinished(OptimizedCallTarget target, StructuredGraph graph) { - } - public static boolean isEnabled() { return TraceTrufflePerformanceWarnings.getValue(); } diff -r e7d219e9d01f -r 5415422cb32f graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Thu Nov 06 20:13:08 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Thu Nov 06 20:14:47 2014 +0100 @@ -119,7 +119,7 @@ VirtualUtil.trace("\nBlock: %s, preds: %s, succ: %s (", block, block.getPredecessors(), block.getSuccessors()); GraphEffectList effects = blockEffects.get(block); - FixedWithNextNode lastFixedNode = null; + FixedWithNextNode lastFixedNode = block.getBeginNode().predecessor() instanceof FixedWithNextNode ? (FixedWithNextNode) block.getBeginNode().predecessor() : null; Iterable nodes = schedule != null ? schedule.getBlockToNodesMap().get(block) : block.getNodes(); for (Node node : nodes) { aliases.set(node, null);