# HG changeset patch # User Christian Humer # Date 1414689230 -3600 # Node ID c489edfac1c7cce3138fe9d373dc41a53be3e23f # Parent 546cfe7a19b65f029db7b2316ef007a67b7ff31b Truffle: implemented new flag -G:+TruffleCompilationStatistics diff -r 546cfe7a19b6 -r c489edfac1c7 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 Oct 30 18:12:45 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Thu Oct 30 18:13:50 2014 +0100 @@ -65,6 +65,7 @@ TraceInliningListener.install(this); TraceSplittingListener.install(this); PrintCallTargetProfiling.install(this); + CompilationStatisticsListener.install(this); } protected void lookupCallMethods(MetaAccessProvider metaAccess) { diff -r 546cfe7a19b6 -r c489edfac1c7 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 Oct 30 18:12:45 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu Oct 30 18:13:50 2014 +0100 @@ -77,7 +77,6 @@ public static final OptionValue TruffleSplittingAggressive = new OptionValue<>(false); - @Option(help = "Disable call target splitting if tree size exceeds this limit") public static final OptionValue TruffleSplittingMaxCalleeSize = new OptionValue<>(100); @Option(help = "Number of most recently used methods in truffle cache") @@ -130,5 +129,9 @@ public static final OptionValue TraceTruffleStackTraceLimit = new OptionValue<>(20); @Option(help = "Print a summary of execution counts for all executed CallTargets. Introduces counter overhead for each call.") public static final OptionValue TruffleCallTargetProfiling = new StableOptionValue<>(false); + @Option(help = "Print Truffle compilation statistics at the end of a run.") + public static final OptionValue TruffleCompilationStatistics = new OptionValue<>(false); + @Option(help = "Print additional more verbose Truffle compilation statistics at the end of a run.") + public static final OptionValue TruffleCompilationStatisticDetails = new OptionValue<>(false); // @formatter:on } diff -r 546cfe7a19b6 -r c489edfac1c7 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/CompilationStatisticsListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/CompilationStatisticsListener.java Thu Oct 30 18:13:50 2014 +0100 @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2014, 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 static java.util.function.Function.*; +import static java.util.stream.Collectors.*; + +import java.io.*; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import com.oracle.graal.api.code.*; +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; + +public class CompilationStatisticsListener extends AbstractDebugCompilationListener { + + private long firstCompilation; + + private int compilations; + private int invalidations; + private int failures; + private int success; + private int queues; + private int dequeues; + private int splits; + + private final IntSummaryStatistics nodeCount = new IntSummaryStatistics(); + private final IntSummaryStatistics nodeCountTrivial = new IntSummaryStatistics(); + private final IntSummaryStatistics nodeCountNonTrivial = new IntSummaryStatistics(); + private final IntSummaryStatistics nodeCountMonomorphic = new IntSummaryStatistics(); + private final IntSummaryStatistics nodeCountPolymorphic = new IntSummaryStatistics(); + private final IntSummaryStatistics nodeCountMegamorphic = new IntSummaryStatistics(); + private final IdentityStatistics> nodeStatistics = new IdentityStatistics<>(); + + private final IntSummaryStatistics callCount = new IntSummaryStatistics(); + private final IntSummaryStatistics callCountIndirect = new IntSummaryStatistics(); + private final IntSummaryStatistics callCountDirect = new IntSummaryStatistics(); + private final IntSummaryStatistics callCountDirectDispatched = new IntSummaryStatistics(); + private final IntSummaryStatistics callCountDirectInlined = new IntSummaryStatistics(); + private final IntSummaryStatistics callCountDirectCloned = new IntSummaryStatistics(); + private final IntSummaryStatistics callCountDirectNotCloned = new IntSummaryStatistics(); + private final IntSummaryStatistics loopCount = new IntSummaryStatistics(); + + private final LongSummaryStatistics compilationTime = new LongSummaryStatistics(); + private final LongSummaryStatistics compilationTimeTruffleTier = new LongSummaryStatistics(); + private final LongSummaryStatistics compilationTimeGraalTier = new LongSummaryStatistics(); + private final LongSummaryStatistics compilationTimeCodeInstallation = new LongSummaryStatistics(); + + private final IntSummaryStatistics truffleTierNodeCount = new IntSummaryStatistics(); + private final IdentityStatistics> truffleTierNodeStatistics = new IdentityStatistics<>(); + private final IntSummaryStatistics graalTierNodeCount = new IntSummaryStatistics(); + private final IdentityStatistics> graalTierNodeStatistics = new IdentityStatistics<>(); + + private final IntSummaryStatistics compilationResultCodeSize = new IntSummaryStatistics(); + private final IntSummaryStatistics compilationResultExceptionHandlers = new IntSummaryStatistics(); + private final IntSummaryStatistics compilationResultInfopoints = new IntSummaryStatistics(); + private final IdentityStatistics compilationResultInfopointStatistics = new IdentityStatistics<>(); + private final IntSummaryStatistics compilationResultMarks = new IntSummaryStatistics(); + private final IntSummaryStatistics compilationResultTotalFrameSize = new IntSummaryStatistics(); + private final IntSummaryStatistics compilationResultDataReferences = new IntSummaryStatistics(); + private final IdentityStatistics compilationResultDataReferencesStatistics = new IdentityStatistics<>(); + + private CompilationStatisticsListener() { + } + + public static void install(GraalTruffleRuntime runtime) { + if (TruffleCompilerOptions.TruffleCompilationStatistics.getValue() || TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) { + runtime.addCompilationListener(new CompilationStatisticsListener()); + } + } + + @Override + public void notifyCompilationSplit(OptimizedDirectCallNode callNode) { + splits++; + } + + @Override + public void notifyCompilationQueued(OptimizedCallTarget target) { + queues++; + if (firstCompilation == 0) { + firstCompilation = System.nanoTime(); + } + } + + @Override + public void notifyCompilationDequeued(OptimizedCallTarget target, Object source, CharSequence reason) { + dequeues++; + } + + @Override + public void notifyCompilationFailed(OptimizedCallTarget target, StructuredGraph graph, Throwable t) { + failures++; + } + + @Override + public void notifyCompilationInvalidated(OptimizedCallTarget target, Object source, CharSequence reason) { + invalidations++; + } + + private final ThreadLocal compilationLocal = new ThreadLocal<>(); + + @Override + public void notifyCompilationStarted(OptimizedCallTarget target) { + compilations++; + CompilationLocal local = new CompilationLocal(); + local.compilationStarted = System.nanoTime(); + compilationLocal.set(local); + } + + @Override + public void notifyCompilationTruffleTierFinished(OptimizedCallTarget target, StructuredGraph graph) { + compilationLocal.get().truffleTierFinished = System.nanoTime(); + + nodeStatistics.accept(target.nodeStream(true).filter(n -> n != null).map(node -> node.getClass())); + + CallTargetNodeStatistics callTargetStat = new CallTargetNodeStatistics(target); + nodeCount.accept(callTargetStat.getNodeCount()); + nodeCountTrivial.accept(callTargetStat.getNodeCountTrivial()); + nodeCountNonTrivial.accept(callTargetStat.getNodeCountNonTrivial()); + nodeCountMonomorphic.accept(callTargetStat.getNodeCountMonomorphic()); + nodeCountPolymorphic.accept(callTargetStat.getNodeCountPolymorphic()); + nodeCountMegamorphic.accept(callTargetStat.getNodeCountMegamorphic()); + + callCount.accept(callTargetStat.getCallCount()); + callCountIndirect.accept(callTargetStat.getCallCountIndirect()); + callCountDirect.accept(callTargetStat.getCallCountDirect()); + callCountDirectDispatched.accept(callTargetStat.getCallCountDirectDispatched()); + callCountDirectInlined.accept(callTargetStat.getCallCountDirectInlined()); + callCountDirectCloned.accept(callTargetStat.getCallCountDirectCloned()); + callCountDirectNotCloned.accept(callTargetStat.getCallCountDirectNotCloned()); + loopCount.accept(callTargetStat.getLoopCount()); + + truffleTierNodeCount.accept(graph.getNodeCount()); + if (TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) { + truffleTierNodeStatistics.accept(nodeClassStream(graph)); + } + } + + @Override + public void notifyCompilationGraalTierFinished(OptimizedCallTarget target, StructuredGraph graph) { + compilationLocal.get().graalTierFinished = System.nanoTime(); + graalTierNodeCount.accept(graph.getNodeCount()); + + if (TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) { + graalTierNodeStatistics.accept(nodeClassStream(graph)); + } + } + + private static Stream> nodeClassStream(StructuredGraph graph) { + return StreamSupport.stream(graph.getNodes().spliterator(), false).map(node -> node.getClass()); + } + + @Override + public void notifyCompilationSuccess(OptimizedCallTarget target, StructuredGraph graph, CompilationResult result) { + success++; + long compilationDone = System.nanoTime(); + + CompilationLocal local = compilationLocal.get(); + + compilationTime.accept(compilationDone - local.compilationStarted); + compilationTimeTruffleTier.accept(local.truffleTierFinished - local.compilationStarted); + compilationTimeGraalTier.accept(local.graalTierFinished - local.truffleTierFinished); + compilationTimeCodeInstallation.accept(compilationDone - local.graalTierFinished); + + compilationResultCodeSize.accept(result.getTargetCodeSize()); + compilationResultTotalFrameSize.accept(result.getTotalFrameSize()); + compilationResultExceptionHandlers.accept(result.getExceptionHandlers().size()); + compilationResultInfopoints.accept(result.getInfopoints().size()); + compilationResultInfopointStatistics.accept(result.getInfopoints().stream().map(e -> e.reason.toString())); + compilationResultMarks.accept(result.getMarks().size()); + compilationResultDataReferences.accept(result.getDataReferences().size()); + compilationResultDataReferencesStatistics.accept(result.getDataReferences().stream().map(d -> d.data.getKind().toString())); + } + + @Override + public void notifyShutdown(TruffleRuntime runtime) { + printStatistics((GraalTruffleRuntime) runtime, OUT); + } + + public void printStatistics(GraalTruffleRuntime runtime, PrintStream out) { + long endTime = System.nanoTime(); + out.println("Truffle compilation statistics:"); + printStatistic("Compilations", compilations); + printStatistic(" Success", success); + printStatistic(" Failed", failures); + printStatistic(" Interrupted", compilations - (success + failures)); + printStatistic("Invalidated", invalidations); + printStatistic("Queues", queues); + printStatistic("Dequeues", dequeues); + printStatistic("Splits", splits); + printStatistic("Compilation Accuracy", 1.0 - invalidations / (double) compilations); + printStatistic("Queue Accuracy", 1.0 - dequeues / (double) queues); + printStatistic("Compilation Utilization", compilationTime.getSum() / (double) (endTime - firstCompilation)); + printStatistic("Remaining Compilation Queue", runtime.getQueuedCallTargets().size()); + + printStatisticTime("Compilation time", compilationTime); + printStatisticTime(" Truffle Tier", compilationTimeTruffleTier); + printStatisticTime(" Graal Tier", compilationTimeGraalTier); + printStatisticTime(" Code Installation", compilationTimeCodeInstallation); + + printStatistic("Truffle node count", nodeCount); + printStatistic(" Trivial", nodeCountTrivial); + printStatistic(" Non Trivial", nodeCountNonTrivial); + printStatistic(" Monomorphic", nodeCountMonomorphic); + printStatistic(" Polymorphic", nodeCountPolymorphic); + printStatistic(" Megamorphic", nodeCountMegamorphic); + printStatistic("Truffle call count", callCount); + printStatistic(" Indirect", callCountIndirect); + printStatistic(" Direct", callCountDirect); + printStatistic(" Dispatched", callCountDirectDispatched); + printStatistic(" Inlined", callCountDirectInlined); + printStatistic(" ----------"); + printStatistic(" Cloned", callCountDirectCloned); + printStatistic(" Not Cloned", callCountDirectNotCloned); + printStatistic("Truffle loops", loopCount); + printStatistic("Graal node count"); + printStatistic(" After Truffle Tier", truffleTierNodeCount); + printStatistic(" After Graal Tier", graalTierNodeCount); + + printStatistic("Graal comilation result"); + printStatistic(" Code size", compilationResultCodeSize); + printStatistic(" Total frame size", compilationResultTotalFrameSize); + printStatistic(" Exception handlers", compilationResultExceptionHandlers); + printStatistic(" Infopoints", compilationResultInfopoints); + compilationResultInfopointStatistics.printStatistics(identity()); + printStatistic(" Marks", compilationResultMarks); + printStatistic(" Data references", compilationResultDataReferences); + compilationResultDataReferencesStatistics.printStatistics(identity()); + + if (TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) { + printStatistic("Truffle nodes"); + nodeStatistics.printStatistics(Class::getSimpleName); + printStatistic("Graal nodes after Truffle tier"); + truffleTierNodeStatistics.printStatistics(Class::getSimpleName); + printStatistic("Graal nodes after Graal tier"); + graalTierNodeStatistics.printStatistics(Class::getSimpleName); + } + } + + private static void printStatistic(String label) { + OUT.printf(" %-50s: %n", label); + } + + private static void printStatistic(String label, int value) { + OUT.printf(" %-50s: %d%n", label, value); + } + + private static void printStatistic(String label, double value) { + OUT.printf(" %-50s: %f%n", label, value); + } + + private static void printStatistic(String label, IntSummaryStatistics value) { + OUT.printf(" %-50s: count=%4d, sum=%8d, min=%8d, average=%12.2f, max=%8d %n", label, value.getCount(), value.getSum(), value.getMin(), value.getAverage(), value.getMax()); + } + + private static void printStatisticTime(String label, LongSummaryStatistics value) { + OUT.printf(" %-50s: count=%4d, sum=%8d, min=%8d, average=%12.2f, max=%8d (milliseconds)%n", label, value.getCount(), value.getSum() / 1000000, value.getMin() / 1000000, + value.getAverage() / 1e6, value.getMax() / 1000000); + } + + private static final class IdentityStatistics { + + final Map types = new HashMap<>(); + + public void printStatistics(Function toStringFunction) { + types.keySet().stream().sorted(Comparator.comparing(c -> -types.get(c).getSum()))// + .forEach(c -> { + printStatistic(String.format(" %s", toStringFunction.apply(c)), types.get(c)); + }); + } + + public void accept(Stream classes) { + classes.collect(groupingBy(identity(), counting())).// + forEach((clazz, count) -> { + types.computeIfAbsent(clazz, c -> new IntSummaryStatistics()).accept(count.intValue()); + }); + } + } + + private static final class CallTargetNodeStatistics { + + // nodeCount = truffleNodeCountTrivial + truffleNodeCountNonTrivial + private int nodeCountTrivial; + private int nodeCountNonTrivial; + private int nodeCountMonomorphic; + private int nodeCountPolymorphic; + private int nodeCountMegamorphic; + + // callCount = truffleCallCountDirect + truffleCallCountIndirect + private int callCountIndirect; + // callCountDirect = truffleCallCountDirectDispatched + truffleCallCountDirectInlined + private int callCountDirectDispatched; + private int callCountDirectInlined; + private int callCountDirectCloned; + private int callCountDirectNotCloned; + private int loopCount; + + public CallTargetNodeStatistics(OptimizedCallTarget target) { + target.accept((CallTreeNodeVisitor) this::visitNode, true); + + } + + private boolean visitNode(List stack, Node node) { + if (node == null) { + return true; + } + + NodeCost cost = node.getCost(); + if (cost.isTrivial()) { + nodeCountTrivial++; + } else { + nodeCountNonTrivial++; + if (cost == NodeCost.MONOMORPHIC) { + nodeCountMonomorphic++; + } else if (cost == NodeCost.POLYMORPHIC) { + nodeCountPolymorphic++; + } else if (cost == NodeCost.MEGAMORPHIC) { + nodeCountMegamorphic++; + } + } + + if (node instanceof DirectCallNode) { + TruffleInliningDecision decision = CallTreeNodeVisitor.getCurrentInliningDecision(stack); + if (decision != null && decision.getProfile().getCallNode() == node && decision.isInline()) { + callCountDirectInlined++; + } else { + callCountDirectDispatched++; + } + if (decision.getProfile().getCallNode().isCallTargetCloned()) { + callCountDirectCloned++; + } else { + callCountDirectNotCloned++; + } + } else if (node instanceof IndirectCallNode) { + callCountDirectInlined++; + } else if (node instanceof LoopNode) { + loopCount++; + } + + return true; + } + + public int getCallCountDirectCloned() { + return callCountDirectCloned; + } + + public int getCallCountDirectNotCloned() { + return callCountDirectNotCloned; + } + + public int getNodeCount() { + return nodeCountTrivial + nodeCountNonTrivial; + } + + public int getCallCount() { + return getCallCountDirect() + callCountIndirect; + } + + public int getCallCountDirect() { + return callCountDirectDispatched + callCountDirectInlined; + } + + public int getNodeCountTrivial() { + return nodeCountTrivial; + } + + public int getNodeCountNonTrivial() { + return nodeCountNonTrivial; + } + + public int getNodeCountMonomorphic() { + return nodeCountMonomorphic; + } + + public int getNodeCountPolymorphic() { + return nodeCountPolymorphic; + } + + public int getNodeCountMegamorphic() { + return nodeCountMegamorphic; + } + + public int getCallCountIndirect() { + return callCountIndirect; + } + + public int getCallCountDirectDispatched() { + return callCountDirectDispatched; + } + + public int getCallCountDirectInlined() { + return callCountDirectInlined; + } + + public int getLoopCount() { + return loopCount; + } + } + + private static class CompilationLocal { + + private long compilationStarted; + private long truffleTierFinished; + private long graalTierFinished; + + } + +}