changeset 19926:575d7607f827

Truffle: implemented new -G:+PrintTruffleExpansionHistogram tool.
author Christian Humer <christian.humer@oracle.com>
date Wed, 18 Mar 2015 02:15:37 +0100
parents 72afcc30c4a0
children b6af1acf00d6 5119e7f07d93 517cbecdc20f
files graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java
diffstat 3 files changed, 190 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Mar 18 02:17:34 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Mar 18 02:15:37 2015 +0100
@@ -319,11 +319,18 @@
         plugins.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
         plugins.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
         callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
-        plugins.setInlineInvokePlugin(new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
+        InlineInvokePlugin inlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), providers.getReplacements());
+        if (PrintTruffleExpansionHistogram.getValue()) {
+            inlinePlugin = new HistogramInlineInvokePlugin(graph, inlinePlugin);
+        }
+        plugins.setInlineInvokePlugin(inlinePlugin);
         plugins.setLoopExplosionPlugin(new PELoopExplosionPlugin());
         InvocationPlugins invocationPlugins = newConfig.getPlugins().getInvocationPlugins();
         new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig,
                         TruffleCompilerImpl.Optimizations, null).apply(graph);
+        if (PrintTruffleExpansionHistogram.getValue()) {
+            ((HistogramInlineInvokePlugin) inlinePlugin).print(callTarget, System.out);
+        }
         Debug.dump(graph, "After FastPE");
 
         // Perform deoptimize to guard conversion.
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Wed Mar 18 02:17:34 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Wed Mar 18 02:15:37 2015 +0100
@@ -156,6 +156,9 @@
     @Option(help = "Print source secions for printed expansion trees", type = OptionType.Debug)
     public static final OptionValue<Boolean> TraceTruffleExpansionSource = new OptionValue<>(false);
 
+    @Option(help = "Prints a histogram of all expanded Java methods.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> PrintTruffleExpansionHistogram = new OptionValue<>(false);
+
     @Option(help = "Print detailed information for the Truffle compilation cache", type = OptionType.Debug)
     public static final OptionValue<Boolean> TraceTruffleCacheDetails = new OptionValue<>(false);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java	Wed Mar 18 02:15:37 2015 +0100
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015, 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.debug;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.truffle.*;
+
+public class HistogramInlineInvokePlugin implements InlineInvokePlugin {
+
+    private final Map<ResolvedJavaMethod, MethodStatistics> histogram = new HashMap<>();
+    private final StructuredGraph graph;
+    private final InlineInvokePlugin delegate;
+
+    private HistogramInlineInvokePlugin.MethodStatistic currentStatistic;
+
+    public HistogramInlineInvokePlugin(StructuredGraph graph, InlineInvokePlugin delegate) {
+        this.graph = graph;
+        this.delegate = delegate;
+    }
+
+    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        InlineInfo inlineInfo = delegate.getInlineInfo(b, method, args, returnType);
+        if (inlineInfo != null) {
+            currentStatistic = new MethodStatistic(currentStatistic, inlineInfo.methodToInline, graph.getNodeCount(), graph.getNodes(MethodCallTargetNode.TYPE).count());
+        }
+        return inlineInfo;
+    }
+
+    public void postInline(ResolvedJavaMethod inlinedTargetMethod) {
+        delegate.postInline(inlinedTargetMethod);
+
+        if (currentStatistic != null) {
+            currentStatistic.applyNodeCountAfter(graph.getNodeCount());
+            currentStatistic.applyCallsAfter(graph.getNodes(MethodCallTargetNode.TYPE).count());
+            accept(currentStatistic);
+            currentStatistic = currentStatistic.getParent();
+        }
+    }
+
+    private void accept(MethodStatistic current) {
+        ResolvedJavaMethod method = current.getMethod();
+        HistogramInlineInvokePlugin.MethodStatistics statistics = histogram.get(method);
+        if (statistics == null) {
+            statistics = new MethodStatistics(method);
+            histogram.put(method, statistics);
+        }
+        statistics.accept(current);
+    }
+
+    public void print(OptimizedCallTarget target, PrintStream out) {
+        out.printf("Truffle expansion histogram for %s", target);
+        out.println("  Invocations = Number of expanded invocations");
+        out.println("  Nodes = Number of Graal nodes created for this method during partial evaluation.");
+        out.println("  Calls = Number of not expanded calls created for this method during partial evaluation.");
+        out.printf(" %-11s |Nodes %5s %5s %5s %8s |Calls %5s %5s %5s %8s | Method Name%n", "Invocations", "Sum", "Min", "Max", "Avg", "Sum", "Min", "Max", "Avg");
+        histogram.values().stream().sorted().forEach(statistics -> statistics.print(out));
+    }
+
+    private static class MethodStatistics implements Comparable<MethodStatistics> {
+
+        private final ResolvedJavaMethod method;
+
+        private int count;
+        private final IntSummaryStatistics shallowCount = new IntSummaryStatistics();
+        private final IntSummaryStatistics callCount = new IntSummaryStatistics();
+
+        public MethodStatistics(ResolvedJavaMethod method) {
+            this.method = method;
+        }
+
+        public void print(PrintStream out) {
+            out.printf(" %11d |        %5d %5d %5d %8.2f |      %5d %5d %5d %8.2f | %s%n", //
+                            count, shallowCount.getSum(), shallowCount.getMin(), shallowCount.getMax(), //
+                            shallowCount.getAverage(), callCount.getSum(), callCount.getMin(), callCount.getMax(), //
+                            callCount.getAverage(), method.format("%h.%n(%p)"));
+        }
+
+        public int compareTo(MethodStatistics o) {
+            int result = (int) (o.shallowCount.getSum() - shallowCount.getSum());
+            if (result == 0) {
+                return o.count - count;
+            }
+            return result;
+        }
+
+        public void accept(MethodStatistic statistic) {
+            if (!statistic.method.equals(method)) {
+                throw new IllegalArgumentException("invalid statistic");
+            }
+            count++;
+            callCount.accept(statistic.getShallowCallCount());
+            shallowCount.accept(statistic.getShallowNodeCount());
+        }
+    }
+
+    private static class MethodStatistic {
+
+        private final MethodStatistic parent;
+        private final List<MethodStatistic> children = new ArrayList<>();
+
+        private final ResolvedJavaMethod method;
+        private int deepNodeCount;
+        private int callCount;
+
+        public MethodStatistic(MethodStatistic parent, ResolvedJavaMethod method, int nodeCountBefore, int callsBefore) {
+            this.parent = parent;
+            this.method = method;
+            this.callCount = callsBefore;
+            this.deepNodeCount = nodeCountBefore;
+            if (parent != null) {
+                this.parent.getChildren().add(this);
+            }
+        }
+
+        public ResolvedJavaMethod getMethod() {
+            return method;
+        }
+
+        public List<MethodStatistic> getChildren() {
+            return children;
+        }
+
+        public int getShallowNodeCount() {
+            int shallowCount = deepNodeCount;
+            for (MethodStatistic child : children) {
+                shallowCount -= child.deepNodeCount;
+            }
+            return shallowCount;
+        }
+
+        public int getShallowCallCount() {
+            int shallowCount = callCount;
+            for (MethodStatistic child : children) {
+                shallowCount -= child.callCount;
+            }
+            return shallowCount;
+        }
+
+        public void applyNodeCountAfter(int nodeCountAfter) {
+            deepNodeCount = nodeCountAfter - this.deepNodeCount;
+        }
+
+        public void applyCallsAfter(int callsAfter) {
+            callCount = callsAfter - this.callCount;
+        }
+
+        public MethodStatistic getParent() {
+            return parent;
+        }
+
+    }
+
+}