# HG changeset patch # User Christian Humer # Date 1392946203 -3600 # Node ID 5f2c0ad0501a44d9458523b34cd4ca88e23fa8d2 # Parent c7ac129e17e9b5535befc479df34a5325c38e96f# Parent 643cb1fc94972999a95aaa5b978450d74208b609 Merge. diff -r 643cb1fc9497 -r 5f2c0ad0501a 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 Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Fri Feb 21 02:30:03 2014 +0100 @@ -24,6 +24,8 @@ import static com.oracle.graal.truffle.TruffleCompilerOptions.*; +import java.util.*; + public class CompilationProfile { /** @@ -57,6 +59,17 @@ this.name = name; } + public Map getDebugProperties() { + Map properties = new LinkedHashMap<>(); + String callsThreshold = String.format("%7d/%5d", getCallCount(), getCompilationCallThreshold()); + String loopsThreshold = String.format("%7d/%5d", getCallAndLoopCount(), getCompilationCallAndLoopThreshold()); + String invalidationReplace = String.format("%5d/%5d", invalidationCount, nodeReplaceCount); + properties.put("C/T", callsThreshold); + properties.put("L/T", loopsThreshold); + properties.put("Inval#/Replace#", invalidationReplace); + return properties; + } + public void reset() { callCount = 0; callAndLoopCount = 0; diff -r 643cb1fc9497 -r 5f2c0ad0501a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Fri Feb 21 02:30:03 2014 +0100 @@ -22,10 +22,13 @@ */ package com.oracle.graal.truffle; +import java.util.concurrent.atomic.*; + import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. @@ -57,8 +60,8 @@ return callCount; } - public TruffleInliningProfile createInliningProfile() { - return new OptimizedCallNodeProfile(this); + public TruffleInliningProfile createInliningProfile(OptimizedCallTarget target) { + return new OptimizedCallNodeProfile(target, this); } @Override @@ -66,10 +69,11 @@ return null; } - final OptimizedCallNode inlineImpl() { + protected OptimizedCallNode inlineImpl() { if (getParent() == null) { throw new IllegalStateException("CallNode must be adopted before it is split."); } + return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), getExecutedCallTarget().getRootNode(), callCount)); } @@ -103,15 +107,57 @@ private Object trySplit(PackedFrame caller, Arguments arguments) { int effectiveCallCount = callCount; // we try splitting for the first two invocations - if (effectiveCallCount == 1 || effectiveCallCount == 2) { + if (effectiveCallCount <= 3) { if (isSplittable() && shouldSplit()) { - return splitImpl().call(caller, arguments); + return splitImpl(true).call(caller, arguments); + } + if (effectiveCallCount == 3) { + splitTried = true; + } + } + return callTarget.call(caller, arguments); + } + + private boolean shouldSplit() { + if (!TruffleCompilerOptions.TruffleSplittingEnabled.getValue()) { + return false; + } + + int nodeCount = NodeUtil.countNodes(getCallTarget().getRootNode(), null, false); + + // max one child call and callCount > 2 and kind of small number of nodes + if (callCount > 2 && isCallMethod()) { + if (nodeCount <= 100) { + return true; } } - if (effectiveCallCount >= 2) { - splitTried = true; + + if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { + return false; } - return callTarget.call(caller, arguments); + return countPolymorphic() > 1 || countGeneric() > 0; + } + + private boolean isCallMethod() { + final AtomicInteger count = new AtomicInteger(0); + getExecutedCallTarget().getRootNode().accept(new NodeVisitor() { + + public boolean visit(Node node) { + if (node instanceof CallNode) { + return count.incrementAndGet() > 1; + } + return true; + } + }); + return count.get() <= 1; + } + + private int countPolymorphic() { + return NodeUtil.countNodes(getCallTarget().getRootNode(), null, Kind.POLYMORPHIC, true); + } + + private int countGeneric() { + return NodeUtil.countNodes(getCallTarget().getRootNode(), null, Kind.GENERIC, true); } @Override @@ -128,30 +174,18 @@ if (getParent() == null) { throw new IllegalStateException("CallNode must be adopted before it is split."); } - splitImpl(); + splitImpl(false); return true; } - private OptimizedCallNode splitImpl() { + private OptimizedCallNode splitImpl(boolean heuristic) { RootNode splittedRoot = getCallTarget().getRootNode().split(); OptimizedCallTarget splitCallTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(splittedRoot); - OptimizedCallTarget.logSplit(getCallTarget(), splitCallTarget); - return replace(new SplitOptimizedCallNode(getCallTarget(), splitCallTarget, callCount)); - } - - private boolean shouldSplit() { - if (!TruffleCompilerOptions.TruffleSplittingEnabled.getValue()) { - return false; + splitCallTarget.setSplitSource(getCallTarget()); + if (heuristic) { + OptimizedCallTarget.logSplit(this, getCallTarget(), splitCallTarget); } - RootNode targetRoot = getCallTarget().getRootNode(); - int nodeCount = NodeUtil.countNodes(targetRoot, null, true); - if (nodeCount >= TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { - return false; - } - SplitScoreVisitor visitor = new SplitScoreVisitor(); - targetRoot.accept(visitor); - int genericNess = visitor.getSplitScore(); - return genericNess > 0; + return replace(new SplitOptimizedCallNode(getCallTarget(), splitCallTarget, callCount)); } @Override @@ -252,40 +286,4 @@ } - private static final class SplitScoreVisitor implements NodeVisitor { - - private int splitScore = 0; - - public boolean visit(Node node) { - if (node instanceof OptimizedCallNode) { - OptimizedCallNode call = (OptimizedCallNode) node; - if (call.getInlinedRoot() != null) { - call.getInlinedRoot().accept(this); - } - } - splitScore += splitScore(node); - return true; - } - - public int getSplitScore() { - return splitScore; - } - - private static int splitScore(Node node) { - NodeInfo info = node.getClass().getAnnotation(NodeInfo.class); - if (info == null) { - return 0; - } - switch (info.kind()) { - case GENERIC: - return 3; - case POLYMORPHIC: - return 1; - default: - return 0; - } - } - - } - } diff -r 643cb1fc9497 -r 5f2c0ad0501a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java Fri Feb 21 02:30:03 2014 +0100 @@ -22,38 +22,44 @@ */ package com.oracle.graal.truffle; +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; + import java.util.*; import com.oracle.truffle.api.nodes.*; -import static com.oracle.graal.truffle.TruffleCompilerOptions.*; - public class OptimizedCallNodeProfile implements TruffleInliningProfile { private static final String REASON_RECURSION = "recursion"; private static final String REASON_FREQUENCY_CUTOFF = "frequency < " + TruffleInliningMinFrequency.getValue(); private static final String REASON_MAXIMUM_NODE_COUNT = "shallowTargetCount > " + TruffleInliningMaxCalleeSize.getValue(); - private static final String REASON_MAXIMUM_TOTAL_NODE_COUNT = "deepTargetCount + currentNodeCount > " + TruffleInliningMaxCallerSize.getValue(); + private static final String REASON_MAXIMUM_TOTAL_NODE_COUNT = "inlinedTotalCount > " + TruffleInliningMaxCallerSize.getValue(); + private final OptimizedCallTarget callTarget; private final OptimizedCallNode callNode; - private final int targetDeepNodeCount; + private int targetDeepNodeCount; + private List compilationRoots; private final int targetShallowNodeCount; - private final List compilationRoots; private final double averageFrequency; private final double score; private String reason; - public OptimizedCallNodeProfile(OptimizedCallNode callNode) { + public OptimizedCallNodeProfile(OptimizedCallTarget target, OptimizedCallNode callNode) { this.callNode = callNode; RootNode inlineRoot = callNode.getExecutedCallTarget().getRootNode(); + this.callTarget = target; this.targetShallowNodeCount = NodeUtil.countNodes(inlineRoot, null, false); this.targetDeepNodeCount = NodeUtil.countNodes(inlineRoot, null, true); this.compilationRoots = findCompilationRoots(callNode); - this.averageFrequency = calculateAverageFrequency(compilationRoots); + this.averageFrequency = calculateFrequency(compilationRoots); this.score = calculateScore(); } + private double calculateFrequency(@SuppressWarnings("unused") List compilationRoots2) { + return calculateSimpleFrequency(); + } + public OptimizedCallNode getCallNode() { return callNode; } @@ -67,6 +73,8 @@ } public boolean isInliningAllowed() { + this.compilationRoots = findCompilationRoots(getCallNode()); + OptimizedCallTarget inlineTarget = callNode.getExecutedCallTarget(); for (OptimizedCallTarget compilationRoot : compilationRoots) { if (compilationRoot == inlineTarget) { @@ -87,9 +95,10 @@ return false; } + this.targetDeepNodeCount = NodeUtil.countNodes(inlineTarget.getRootNode(), null, true); // The maximum total node count cannot be cached since it may change during inlining. - int currentNodeCount = calculateCurrentNodeCount(compilationRoots); - if (targetDeepNodeCount + currentNodeCount > TruffleInliningMaxCallerSize.getValue()) { + int nextNodeCount = calculateInlinedTotalNodeCount(getCallNode()); + if (nextNodeCount > TruffleInliningMaxCallerSize.getValue()) { reason = REASON_MAXIMUM_TOTAL_NODE_COUNT; return false; } @@ -97,33 +106,50 @@ return true; } - private static int calculateCurrentNodeCount(List compilationRoots) { + private int calculateInlinedTotalNodeCount(OptimizedCallNode node) { int currentNodeCount = 0; for (OptimizedCallTarget compilationRoot : compilationRoots) { if (compilationRoot.getRootNode().getParentInlinedCalls().isEmpty()) { - currentNodeCount = Math.max(currentNodeCount, NodeUtil.countNodes(compilationRoot.getRootNode(), null, true)); + TotalNodeCountVisitor visitor = new TotalNodeCountVisitor(node, targetDeepNodeCount); + compilationRoot.getRootNode().accept(visitor); + currentNodeCount = Math.max(currentNodeCount, visitor.count); } } return currentNodeCount; } - @SuppressWarnings("unused") - private double calculateSimpleFrequency() { - RootNode root = callNode.getRootNode(); - OptimizedCallTarget target = ((OptimizedCallTarget) root.getCallTarget()); + private static class TotalNodeCountVisitor implements NodeVisitor { + + private final OptimizedCallNode inlinedNode; + private final int inlinedNodeCount; + + private int count; + + public TotalNodeCountVisitor(OptimizedCallNode inlinedNode, int inlinedNodeCount) { + this.inlinedNode = inlinedNode; + this.inlinedNodeCount = inlinedNodeCount; + } - int totalCallCount = target.getCompilationProfile().getCallCount(); - List parentInlined = root.getParentInlinedCalls(); - for (CallNode node : parentInlined) { - int callCount = ((OptimizedCallNode) node).getCallCount(); - if (callCount >= 0) { - totalCallCount += callCount; + public boolean visit(Node node) { + count++; + if (node instanceof CallNode) { + RootNode inlinedRoot = ((CallNode) node).getInlinedRoot(); + if (inlinedRoot != null) { + inlinedRoot.accept(this); + } else if (node == inlinedNode) { + count += inlinedNodeCount; + } } + return true; } - return callNode.getCallCount() / (double) totalCallCount; + } - private double calculateAverageFrequency(List roots) { + double calculateSimpleFrequency() { + return callNode.getCallCount() / (double) callTarget.getCompilationProfile().getCallCount(); + } + + double calculateAverageFrequency(List roots) { int compilationRootCallCountSum = 0; int compilationRootCount = 0; for (OptimizedCallTarget compilationRoot : roots) { @@ -157,9 +183,10 @@ public Map getDebugProperties() { Map properties = new LinkedHashMap<>(); + OptimizedCallTarget.addASTSizeProperty(getCallNode().getExecutedCallTarget().getRootNode(), properties); properties.put("shallowCount", targetShallowNodeCount); - properties.put("deepCount", targetDeepNodeCount); - properties.put("currentCount", calculateCurrentNodeCount(compilationRoots)); + properties.put("currentCount", calculateInlinedTotalNodeCount(null)); + properties.put("inlinedTotalCount", calculateInlinedTotalNodeCount(getCallNode())); properties.put("score", score); properties.put("frequency", averageFrequency); properties.put("callCount", callNode.getCallCount()); diff -r 643cb1fc9497 -r 5f2c0ad0501a 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 Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Feb 21 02:30:03 2014 +0100 @@ -34,6 +34,7 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. @@ -45,12 +46,14 @@ private InstalledCode installedCode; private Future installedCodeTask; private boolean compilationEnabled; + private boolean inlined; private int callCount; private final TruffleCompiler compiler; private final CompilationProfile compilationProfile; private final CompilationPolicy compilationPolicy; private final SpeculationLog speculationLog = new SpeculationLog(); + private OptimizedCallTarget splitSource; OptimizedCallTarget(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) { super(rootNode); @@ -69,12 +72,19 @@ } } + public void setSplitSource(OptimizedCallTarget splitSource) { + this.splitSource = splitSource; + } + @Override public String toString() { String superString = super.toString(); if (installedCode != null) { superString += " "; } + if (splitSource != null) { + superString += " "; + } return superString; } @@ -118,29 +128,27 @@ } private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { - invalidate("Compiled code invalidated"); + invalidate(null, null, "Compiled code invalidated"); return call(caller, args); } - private void invalidate(String reason) { + private void invalidate(Node oldNode, Node newNode, String reason) { InstalledCode m = this.installedCode; if (m != null) { CompilerAsserts.neverPartOfCompilation(); installedCode = null; compilationProfile.reportInvalidated(); - if (TraceTruffleCompilation.getValue()) { - logOptimizedInvalidated(this, reason); - } + logOptimizedInvalidated(this, oldNode, newNode, reason); } - cancelInstalledTask(reason); + cancelInstalledTask(oldNode, newNode, reason); } - private void cancelInstalledTask(String reason) { + private void cancelInstalledTask(Node oldNode, Node newNode, String reason) { Future task = this.installedCodeTask; if (task != null) { task.cancel(true); this.installedCodeTask = null; - logOptimizingCancelled(this, reason); + logOptimizingUnqueued(this, oldNode, newNode, reason); compilationProfile.reportInvalidated(); } } @@ -167,35 +175,42 @@ if (!TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { return; } + if (inlined) { + return; + } + inlined = true; + + logInliningStart(this); PriorityQueue queue = new PriorityQueue<>(); // Used to avoid running in cycles or inline nodes in Truffle trees // which do not suffice the tree property twice. Set visitedCallNodes = new HashSet<>(); - queueCallSitesForInlining(getRootNode(), visitedCallNodes, queue); + queueCallSitesForInlining(this, getRootNode(), visitedCallNodes, queue); TruffleInliningProfile callSite = queue.poll(); while (callSite != null) { if (callSite.isInliningAllowed()) { OptimizedCallNode callNode = callSite.getCallNode(); - logInlined(callSite); + logInlined(this, callSite); RootNode inlinedRoot = callNode.inlineImpl().getInlinedRoot(); assert inlinedRoot != null; - queueCallSitesForInlining(inlinedRoot, visitedCallNodes, queue); + queueCallSitesForInlining(this, inlinedRoot, visitedCallNodes, queue); } else { logInliningFailed(callSite); } callSite = queue.poll(); } + logInliningDone(this); } - private static void queueCallSitesForInlining(RootNode rootNode, final Set visitedCallSites, final PriorityQueue queue) { + private static void queueCallSitesForInlining(final OptimizedCallTarget target, RootNode rootNode, final Set visitedCallSites, final PriorityQueue queue) { rootNode.accept(new NodeVisitor() { public boolean visit(Node node) { if (node instanceof OptimizedCallNode) { OptimizedCallNode call = ((OptimizedCallNode) node); if (call.isInlinable() && !call.isInlined() && !visitedCallSites.contains(call)) { - queue.add(call.createInliningProfile()); + queue.add(call.createInliningProfile(target)); visitedCallSites.add(call); } else if (call.getInlinedRoot() != null) { call.getInlinedRoot().accept(this); @@ -225,8 +240,8 @@ } return null; } else { - logOptimizing(this); performInlining(); + logOptimizingQueued(this); this.installedCodeTask = compiler.compile(this); if (!TruffleBackgroundCompilation.getValue()) { return receiveInstalledCode(); @@ -240,7 +255,7 @@ return installedCodeTask.get(); } catch (InterruptedException | ExecutionException e) { compilationEnabled = false; - OUT.printf("[truffle] opt failed %-48s %s\n", getRootNode(), e.getMessage()); + logOptimizingFailed(this, e.getMessage()); if (e.getCause() instanceof BailoutException) { // Bailout => move on. } else { @@ -272,64 +287,133 @@ @Override public void nodeReplaced(Node oldNode, Node newNode, String reason) { compilationProfile.reportNodeReplaced(); - invalidate(reason); + invalidate(oldNode, newNode, reason); } public SpeculationLog getSpeculationLog() { return speculationLog; } + public Map getDebugProperties() { + Map properties = new LinkedHashMap<>(); + addASTSizeProperty(getRootNode(), properties); + properties.putAll(getCompilationProfile().getDebugProperties()); + return properties; + + } + private static void logInliningFailed(TruffleInliningProfile callSite) { - if (TraceTruffleInliningDetails.getValue() || TraceTruffleCompilationDetails.getValue()) { - log(0, "inline failed", callSite.getCallNode().getExecutedCallTarget().toString(), callSite.getDebugProperties()); + if (TraceTruffleInliningDetails.getValue()) { + log(2, "inline failed", callSite.getCallNode().getExecutedCallTarget().toString(), callSite.getDebugProperties()); } } - private static void logOptimizing(OptimizedCallTarget target) { - if (TraceTruffleInliningDetails.getValue() || TraceTruffleCompilationDetails.getValue()) { - log(0, "optimizing", target.toString(), null); + private static void logInlined(final OptimizedCallTarget target, TruffleInliningProfile callSite) { + if (TraceTruffleInliningDetails.getValue() || TraceTruffleInlining.getValue()) { + log(2, "inline success", callSite.getCallNode().getExecutedCallTarget().toString(), callSite.getDebugProperties()); + + if (TraceTruffleInliningDetails.getValue()) { + RootNode root = callSite.getCallNode().getExecutedCallTarget().getRootNode(); + root.accept(new NodeVisitor() { + int depth = 1; + + public boolean visit(Node node) { + if (node instanceof OptimizedCallNode) { + OptimizedCallNode callNode = ((OptimizedCallNode) node); + log(2 + (depth * 2), "inline success", callNode.getExecutedCallTarget().toString(), callNode.createInliningProfile(target).getDebugProperties()); + RootNode inlinedRoot = callNode.getInlinedRoot(); + if (inlinedRoot != null) { + depth++; + inlinedRoot.accept(this); + depth--; + } + } + return true; + } + }); + } } } - private static void logOptimizedInvalidated(OptimizedCallTarget target, String reason) { - if (TraceTruffleInliningDetails.getValue() || TraceTruffleCompilationDetails.getValue()) { - Map properties = new LinkedHashMap<>(); - properties.put("Invalidation#", target.compilationProfile.getInvalidationCount()); - properties.put("Replace#", target.compilationProfile.getNodeReplaceCount()); - properties.put("Reason", reason); - log(0, "invalidated", target.toString(), properties); + private static void logInliningStart(OptimizedCallTarget target) { + if (TraceTruffleInliningDetails.getValue()) { + log(0, "inline start", target.toString(), target.getDebugProperties()); + } + } + + private static void logInliningDone(OptimizedCallTarget target) { + if (TraceTruffleInliningDetails.getValue()) { + log(0, "inline done", target.toString(), target.getDebugProperties()); + } + } + + private static void logOptimizingQueued(OptimizedCallTarget target) { + if (TraceTruffleCompilationDetails.getValue()) { + log(0, "opt queued", target.toString(), target.getDebugProperties()); } } - private static void logOptimizingCancelled(OptimizedCallTarget target, String reason) { - if (TraceTruffleInliningDetails.getValue() || TraceTruffleCompilationDetails.getValue()) { + private static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, String reason) { + if (TraceTruffleCompilationDetails.getValue()) { Map properties = new LinkedHashMap<>(); - properties.put("Invalidation#", target.compilationProfile.getInvalidationCount()); - properties.put("Replace#", target.compilationProfile.getNodeReplaceCount()); + addReplaceProperties(properties, oldNode, newNode); properties.put("Reason", reason); - log(0, "optimizing stop", target.toString(), properties); + log(0, "opt unqueued", target.toString(), properties); + } + } + + private static void addReplaceProperties(Map properties, Node oldNode, Node newNode) { + if (oldNode != null && newNode != null) { + properties.put("OldClass", oldNode.getClass().getSimpleName()); + properties.put("NewClass", newNode.getClass().getSimpleName()); + properties.put("Node", newNode); + } + } + + static void logOptimizingStart(OptimizedCallTarget target) { + if (TraceTruffleCompilationDetails.getValue()) { + log(0, "opt start", target.toString(), target.getDebugProperties()); } } - static void logOptimized(OptimizedCallTarget target, Map properties) { - if (TraceTruffleCompilationDetails.getValue() || TraceTruffleCompilation.getValue()) { - log(0, "optimizing done", target.toString(), properties); + private static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, String reason) { + if (TraceTruffleCompilation.getValue()) { + Map properties = new LinkedHashMap<>(); + addReplaceProperties(properties, oldNode, newNode); + properties.put("Reason", reason); + log(0, "opt invalidated", target.toString(), properties); } } - private static void logInlined(TruffleInliningProfile callSite) { - if (TraceTruffleInliningDetails.getValue() || TraceTruffleInlining.getValue()) { - log(0, "inline success", callSite.getCallNode().getExecutedCallTarget().toString(), callSite.getDebugProperties()); + private static void logOptimizingFailed(OptimizedCallTarget callSite, String reason) { + Map properties = new LinkedHashMap<>(); + properties.put("Reason", reason); + log(0, "opt fail", callSite.toString(), properties); + } + + static void logOptimizingDone(OptimizedCallTarget target, Map properties) { + if (TraceTruffleCompilationDetails.getValue() || TraceTruffleCompilation.getValue()) { + log(0, "opt done", target.toString(), properties); } } - static void logSplit(@SuppressWarnings("unused") OptimizedCallTarget target, OptimizedCallTarget newTarget) { + static void logSplit(OptimizedCallNode callNode, OptimizedCallTarget target, OptimizedCallTarget newTarget) { if (TraceTruffleInliningDetails.getValue() || TraceTruffleInlining.getValue()) { - log(0, "split", newTarget.toString(), null); + Map properties = new LinkedHashMap<>(); + addASTSizeProperty(target.getRootNode(), properties); + properties.put("Source", callNode.getEncapsulatingSourceSection()); + log(0, "split", newTarget.toString(), properties); } } - static void log(int indent, String msg, String details, Map properties) { + static void addASTSizeProperty(RootNode target, Map properties) { + String value = String.format("%4d (%d/%d)", NodeUtil.countNodes(target.getRootNode(), null, true), // + NodeUtil.countNodes(target.getRootNode(), null, Kind.POLYMORPHIC, true), NodeUtil.countNodes(target.getRootNode(), null, Kind.GENERIC, true)); // + + properties.put("ASTSize", value); + } + + static synchronized void log(int indent, String msg, String details, Map properties) { OUT.printf("[truffle] %-16s ", msg); for (int i = 0; i < indent; i++) { OUT.print(" "); diff -r 643cb1fc9497 -r 5f2c0ad0501a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Feb 21 02:30:03 2014 +0100 @@ -94,7 +94,7 @@ throw Debug.handle(e); } - if (TraceTruffleCompilationDetails.getValue()) { + if (TraceTruffleCompilationHistogram.getValue()) { constantReceivers = new HashSet<>(); } @@ -130,7 +130,7 @@ new VerifyFrameDoesNotEscapePhase().apply(graph, false); - if (TraceTruffleCompilationDetails.getValue() && constantReceivers != null) { + if (TraceTruffleCompilationHistogram.getValue() && constantReceivers != null) { DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes"); for (Constant c : constantReceivers) { histogram.add(c.asObject().getClass().getSimpleName()); @@ -184,7 +184,7 @@ for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class)) { InvokeKind kind = methodCallTargetNode.invokeKind(); if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || methodCallTargetNode.receiver() instanceof NewFrameNode))) { - if (TraceTruffleCompilationDetails.getValue() && kind == InvokeKind.Special) { + if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) { ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); constantReceivers.add(constantNode.asConstant()); } diff -r 643cb1fc9497 -r 5f2c0ad0501a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Feb 21 02:30:03 2014 +0100 @@ -141,8 +141,12 @@ graphCache.removeStaleGraphs(); } + if (TraceTruffleCompilation.getValue()) { + OptimizedCallTarget.logOptimizingStart(compilable); + } + if (TraceTruffleInliningTree.getValue()) { - printInlineTree(compilable.getRootNode()); + NodeUtil.printInliningTree(OUT, compilable.getRootNode()); } long timeCompilationStarted = System.nanoTime(); @@ -170,8 +174,7 @@ int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode(), null, true); byte[] code = compiledMethod.getCode(); Map properties = new LinkedHashMap<>(); - properties.put("", String.format("%8x", compilable.hashCode())); - properties.put("Nodes", nodeCountTruffle); + properties.put("ASTSize", nodeCountTruffle); properties.put("Time", String.format("%5.0f(%4.0f+%-4.0f)ms", // (timeCompilationFinished - timeCompilationStarted) / 1e6, // (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, // @@ -180,7 +183,7 @@ properties.put("CodeSize", code != null ? code.length : 0); properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection())); - OptimizedCallTarget.logOptimized(compilable, properties); + OptimizedCallTarget.logOptimizingDone(compilable, properties); } return compiledMethod; } @@ -189,43 +192,6 @@ return sourceSection != null ? sourceSection.toString() : "n/a"; } - private void printInlineTree(RootNode rootNode) { - OUT.println(); - OUT.println("Inlining tree for: " + rootNode); - rootNode.accept(new InlineTreeVisitor()); - } - - private class InlineTreeVisitor implements NodeVisitor { - - public boolean visit(Node node) { - if (node instanceof CallNode) { - CallNode callNode = (CallNode) node; - if (callNode.isInlined()) { - int indent = this.indent(node); - for (int i = 0; i < indent; ++i) { - OUT.print(" "); - } - OUT.println(callNode.getCallTarget()); - callNode.getInlinedRoot().accept(this); - } - } - return true; - } - - private int indent(Node n) { - if (n instanceof RootNode) { - List inlinedParents = ((RootNode) n).getParentInlinedCalls(); - CallNode inlinedParent = inlinedParents.isEmpty() ? null : inlinedParents.get(0); - if (inlinedParent != null) { - return indent(inlinedParent) + 1; - } - return 0; - } else { - return indent(n.getParent()); - } - } - } - public InstalledCode compileMethodHelper(StructuredGraph graph, Assumptions assumptions, String name, SpeculationLog speculationLog) { try (Scope s = Debug.scope("TruffleFinal")) { Debug.dump(graph, "After TruffleTier"); diff -r 643cb1fc9497 -r 5f2c0ad0501a 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 Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Fri Feb 21 02:30:03 2014 +0100 @@ -88,6 +88,8 @@ @Option(help = "") public static final OptionValue TraceTruffleCompilationDetails = new OptionValue<>(false); @Option(help = "") + public static final OptionValue TraceTruffleCompilationHistogram = new OptionValue<>(false); + @Option(help = "") public static final OptionValue TraceTruffleExpansion = new OptionValue<>(false); @Option(help = "") public static final OptionValue TraceTruffleExpansionSource = new OptionValue<>(false); diff -r 643cb1fc9497 -r 5f2c0ad0501a graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Fri Feb 21 02:30:03 2014 +0100 @@ -82,6 +82,14 @@ this.sourceSection = section; } + public Kind getKind() { + NodeInfo info = getClass().getAnnotation(NodeInfo.class); + if (info != null) { + return info.kind(); + } + return Kind.SPECIALIZED; + } + /** * Clears any previously assigned guest language source code from this node. */ diff -r 643cb1fc9497 -r 5f2c0ad0501a graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Fri Feb 21 00:19:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Fri Feb 21 02:30:03 2014 +0100 @@ -34,6 +34,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.Node.Children; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * Utility class that manages the special access methods for node instances. @@ -611,25 +612,31 @@ } public static int countNodes(Node root) { - return countNodes(root, null, false); + return countNodes(root, null, null, false); + } + + public static int countNodes(Node root, Class clazz, Kind nodeKind, boolean countInlinedCallNodes) { + NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz, nodeKind, countInlinedCallNodes); + root.accept(nodeCount); + return nodeCount.nodeCount; } public static int countNodes(Node root, Class clazz, boolean countInlinedCallNodes) { - NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz, countInlinedCallNodes); - root.accept(nodeCount); - return nodeCount.nodeCount; + return countNodes(root, clazz, null, countInlinedCallNodes); } private static final class NodeCountVisitor implements NodeVisitor { private Node root; - private boolean inspectInlinedCalls; + private final boolean inspectInlinedCalls; int nodeCount; + private final Kind kind; private final Class clazz; - private NodeCountVisitor(Node root, Class clazz, boolean inspectInlinedCalls) { + private NodeCountVisitor(Node root, Class clazz, Kind kind, boolean inspectInlinedCalls) { this.root = root; this.clazz = clazz; + this.kind = kind; this.inspectInlinedCalls = inspectInlinedCalls; } @@ -639,7 +646,7 @@ return false; } - if (clazz == null || clazz.isInstance(node)) { + if ((clazz == null || clazz.isInstance(node)) && (kind == null || isKind(node))) { nodeCount++; } @@ -652,6 +659,42 @@ return true; } + + private boolean isKind(Node n) { + return kind == n.getKind(); + } + } + + public static void printInliningTree(final PrintStream stream, RootNode root) { + printRootNode(stream, 0, root); + root.accept(new NodeVisitor() { + int depth = 1; + + public boolean visit(Node node) { + if (node instanceof CallNode) { + RootNode inlinedRoot = ((CallNode) node).getInlinedRoot(); + if (inlinedRoot != null) { + depth++; + printRootNode(stream, depth * 2, inlinedRoot); + inlinedRoot.accept(this); + depth--; + } + } + return true; + } + }); + } + + private static void printRootNode(PrintStream stream, int indent, RootNode root) { + for (int i = 0; i < indent; i++) { + stream.print(" "); + } + stream.print(root.toString()); + stream.print(" ("); + stream.print(countNodes(root)); + stream.print("/"); + stream.print(countNodes(root, null, true)); + stream.println(")"); } public static String printCompactTreeToString(Node node) {