001/*
002 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.truffle.debug;
024
025import static java.util.function.Function.*;
026import static java.util.stream.Collectors.*;
027
028import java.util.*;
029import java.util.function.*;
030import java.util.stream.*;
031
032import jdk.internal.jvmci.code.*;
033
034import com.oracle.graal.nodes.*;
035import com.oracle.graal.truffle.*;
036import com.oracle.graal.truffle.TruffleInlining.CallTreeNodeVisitor;
037import com.oracle.truffle.api.nodes.*;
038import com.oracle.truffle.api.nodes.Node;
039
040public final class CompilationStatisticsListener extends AbstractDebugCompilationListener {
041
042    private long firstCompilation;
043
044    private int compilations;
045    private int invalidations;
046    private int failures;
047    private int success;
048    private int queues;
049    private int dequeues;
050    private int splits;
051
052    private final IntSummaryStatistics deferCompilations = new IntSummaryStatistics();
053    private final LongSummaryStatistics timeToQueue = new LongSummaryStatistics();
054    private final LongSummaryStatistics timeToCompilation = new LongSummaryStatistics();
055
056    private final IntSummaryStatistics nodeCount = new IntSummaryStatistics();
057    private final IntSummaryStatistics nodeCountTrivial = new IntSummaryStatistics();
058    private final IntSummaryStatistics nodeCountNonTrivial = new IntSummaryStatistics();
059    private final IntSummaryStatistics nodeCountMonomorphic = new IntSummaryStatistics();
060    private final IntSummaryStatistics nodeCountPolymorphic = new IntSummaryStatistics();
061    private final IntSummaryStatistics nodeCountMegamorphic = new IntSummaryStatistics();
062    private final IdentityStatistics<Class<?>> nodeStatistics = new IdentityStatistics<>();
063
064    private final IntSummaryStatistics callCount = new IntSummaryStatistics();
065    private final IntSummaryStatistics callCountIndirect = new IntSummaryStatistics();
066    private final IntSummaryStatistics callCountDirect = new IntSummaryStatistics();
067    private final IntSummaryStatistics callCountDirectDispatched = new IntSummaryStatistics();
068    private final IntSummaryStatistics callCountDirectInlined = new IntSummaryStatistics();
069    private final IntSummaryStatistics callCountDirectCloned = new IntSummaryStatistics();
070    private final IntSummaryStatistics callCountDirectNotCloned = new IntSummaryStatistics();
071    private final IntSummaryStatistics loopCount = new IntSummaryStatistics();
072
073    private final LongSummaryStatistics compilationTime = new LongSummaryStatistics();
074    private final LongSummaryStatistics compilationTimeTruffleTier = new LongSummaryStatistics();
075    private final LongSummaryStatistics compilationTimeGraalTier = new LongSummaryStatistics();
076    private final LongSummaryStatistics compilationTimeCodeInstallation = new LongSummaryStatistics();
077
078    private final IntSummaryStatistics truffleTierNodeCount = new IntSummaryStatistics();
079    private final IdentityStatistics<Class<?>> truffleTierNodeStatistics = new IdentityStatistics<>();
080    private final IntSummaryStatistics graalTierNodeCount = new IntSummaryStatistics();
081    private final IdentityStatistics<Class<?>> graalTierNodeStatistics = new IdentityStatistics<>();
082
083    private final IntSummaryStatistics compilationResultCodeSize = new IntSummaryStatistics();
084    private final IntSummaryStatistics compilationResultExceptionHandlers = new IntSummaryStatistics();
085    private final IntSummaryStatistics compilationResultInfopoints = new IntSummaryStatistics();
086    private final IdentityStatistics<String> compilationResultInfopointStatistics = new IdentityStatistics<>();
087    private final IntSummaryStatistics compilationResultMarks = new IntSummaryStatistics();
088    private final IntSummaryStatistics compilationResultTotalFrameSize = new IntSummaryStatistics();
089    private final IntSummaryStatistics compilationResultDataPatches = new IntSummaryStatistics();
090
091    private CompilationStatisticsListener() {
092    }
093
094    public static void install(GraalTruffleRuntime runtime) {
095        if (TruffleCompilerOptions.TruffleCompilationStatistics.getValue() || TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) {
096            runtime.addCompilationListener(new CompilationStatisticsListener());
097        }
098    }
099
100    @Override
101    public void notifyCompilationSplit(OptimizedDirectCallNode callNode) {
102        splits++;
103    }
104
105    @Override
106    public void notifyCompilationQueued(OptimizedCallTarget target) {
107        queues++;
108        if (firstCompilation == 0) {
109            firstCompilation = System.nanoTime();
110        }
111        timeToQueue.accept(System.nanoTime() - target.getCompilationProfile().getTimestamp());
112    }
113
114    @Override
115    public void notifyCompilationDequeued(OptimizedCallTarget target, Object source, CharSequence reason) {
116        dequeues++;
117    }
118
119    @Override
120    public void notifyCompilationFailed(OptimizedCallTarget target, StructuredGraph graph, Throwable t) {
121        failures++;
122    }
123
124    @Override
125    public void notifyCompilationInvalidated(OptimizedCallTarget target, Object source, CharSequence reason) {
126        invalidations++;
127    }
128
129    private final ThreadLocal<CompilationLocal> compilationLocal = new ThreadLocal<>();
130
131    @Override
132    public void notifyCompilationStarted(OptimizedCallTarget target) {
133        compilations++;
134        CompilationLocal local = new CompilationLocal();
135        local.compilationStarted = System.nanoTime();
136        compilationLocal.set(local);
137
138        deferCompilations.accept(target.getCompilationProfile().getDeferedCount());
139        timeToCompilation.accept(local.compilationStarted - target.getCompilationProfile().getTimestamp());
140    }
141
142    @Override
143    public void notifyCompilationTruffleTierFinished(OptimizedCallTarget target, StructuredGraph graph) {
144        compilationLocal.get().truffleTierFinished = System.nanoTime();
145
146        nodeStatistics.accept(target.nodeStream(true).filter(n -> n != null).map(node -> node.getClass()));
147
148        CallTargetNodeStatistics callTargetStat = new CallTargetNodeStatistics(target);
149        nodeCount.accept(callTargetStat.getNodeCount());
150        nodeCountTrivial.accept(callTargetStat.getNodeCountTrivial());
151        nodeCountNonTrivial.accept(callTargetStat.getNodeCountNonTrivial());
152        nodeCountMonomorphic.accept(callTargetStat.getNodeCountMonomorphic());
153        nodeCountPolymorphic.accept(callTargetStat.getNodeCountPolymorphic());
154        nodeCountMegamorphic.accept(callTargetStat.getNodeCountMegamorphic());
155
156        callCount.accept(callTargetStat.getCallCount());
157        callCountIndirect.accept(callTargetStat.getCallCountIndirect());
158        callCountDirect.accept(callTargetStat.getCallCountDirect());
159        callCountDirectDispatched.accept(callTargetStat.getCallCountDirectDispatched());
160        callCountDirectInlined.accept(callTargetStat.getCallCountDirectInlined());
161        callCountDirectCloned.accept(callTargetStat.getCallCountDirectCloned());
162        callCountDirectNotCloned.accept(callTargetStat.getCallCountDirectNotCloned());
163        loopCount.accept(callTargetStat.getLoopCount());
164
165        truffleTierNodeCount.accept(graph.getNodeCount());
166        if (TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) {
167            truffleTierNodeStatistics.accept(nodeClassStream(graph));
168        }
169    }
170
171    @Override
172    public void notifyCompilationGraalTierFinished(OptimizedCallTarget target, StructuredGraph graph) {
173        compilationLocal.get().graalTierFinished = System.nanoTime();
174        graalTierNodeCount.accept(graph.getNodeCount());
175
176        if (TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) {
177            graalTierNodeStatistics.accept(nodeClassStream(graph));
178        }
179    }
180
181    private static Stream<Class<?>> nodeClassStream(StructuredGraph graph) {
182        return StreamSupport.stream(graph.getNodes().spliterator(), false).map(node -> node.getClass());
183    }
184
185    @Override
186    public void notifyCompilationSuccess(OptimizedCallTarget target, StructuredGraph graph, CompilationResult result) {
187        success++;
188        long compilationDone = System.nanoTime();
189
190        CompilationLocal local = compilationLocal.get();
191
192        compilationTime.accept(compilationDone - local.compilationStarted);
193        compilationTimeTruffleTier.accept(local.truffleTierFinished - local.compilationStarted);
194        compilationTimeGraalTier.accept(local.graalTierFinished - local.truffleTierFinished);
195        compilationTimeCodeInstallation.accept(compilationDone - local.graalTierFinished);
196
197        compilationResultCodeSize.accept(result.getTargetCodeSize());
198        compilationResultTotalFrameSize.accept(result.getTotalFrameSize());
199        compilationResultExceptionHandlers.accept(result.getExceptionHandlers().size());
200        compilationResultInfopoints.accept(result.getInfopoints().size());
201        compilationResultInfopointStatistics.accept(result.getInfopoints().stream().map(e -> e.reason.toString()));
202        compilationResultMarks.accept(result.getMarks().size());
203        compilationResultDataPatches.accept(result.getDataPatches().size());
204    }
205
206    @Override
207    public void notifyShutdown(GraalTruffleRuntime rt) {
208        printStatistics(rt);
209    }
210
211    public void printStatistics(GraalTruffleRuntime rt) {
212        long endTime = System.nanoTime();
213        rt.log("Truffle compilation statistics:");
214        printStatistic(rt, "Compilations", compilations);
215        printStatistic(rt, "  Success", success);
216        printStatistic(rt, "  Failed", failures);
217        printStatistic(rt, "  Interrupted", compilations - (success + failures));
218        printStatistic(rt, "Invalidated", invalidations);
219        printStatistic(rt, "Queues", queues);
220        printStatistic(rt, "Dequeues", dequeues);
221        printStatistic(rt, "Splits", splits);
222        printStatistic(rt, "Compilation Accuracy", 1.0 - invalidations / (double) compilations);
223        printStatistic(rt, "Queue Accuracy", 1.0 - dequeues / (double) queues);
224        printStatistic(rt, "Compilation Utilization", compilationTime.getSum() / (double) (endTime - firstCompilation));
225        printStatistic(rt, "Remaining Compilation Queue", rt.getQueuedCallTargets().size());
226        printStatistic(rt, "Times defered until compilation", deferCompilations);
227
228        printStatisticTime(rt, "Time to queue", timeToQueue);
229        printStatisticTime(rt, "Time to compilation", timeToCompilation);
230
231        printStatisticTime(rt, "Compilation time", compilationTime);
232        printStatisticTime(rt, "  Truffle Tier", compilationTimeTruffleTier);
233        printStatisticTime(rt, "  Graal Tier", compilationTimeGraalTier);
234        printStatisticTime(rt, "  Code Installation", compilationTimeCodeInstallation);
235
236        printStatistic(rt, "Truffle node count", nodeCount);
237        printStatistic(rt, "  Trivial", nodeCountTrivial);
238        printStatistic(rt, "  Non Trivial", nodeCountNonTrivial);
239        printStatistic(rt, "    Monomorphic", nodeCountMonomorphic);
240        printStatistic(rt, "    Polymorphic", nodeCountPolymorphic);
241        printStatistic(rt, "    Megamorphic", nodeCountMegamorphic);
242        printStatistic(rt, "Truffle call count", callCount);
243        printStatistic(rt, "  Indirect", callCountIndirect);
244        printStatistic(rt, "  Direct", callCountDirect);
245        printStatistic(rt, "    Dispatched", callCountDirectDispatched);
246        printStatistic(rt, "    Inlined", callCountDirectInlined);
247        printStatistic(rt, "    ----------");
248        printStatistic(rt, "    Cloned", callCountDirectCloned);
249        printStatistic(rt, "    Not Cloned", callCountDirectNotCloned);
250        printStatistic(rt, "Truffle loops", loopCount);
251        printStatistic(rt, "Graal node count");
252        printStatistic(rt, "  After Truffle Tier", truffleTierNodeCount);
253        printStatistic(rt, "  After Graal Tier", graalTierNodeCount);
254
255        printStatistic(rt, "Graal comilation result");
256        printStatistic(rt, "  Code size", compilationResultCodeSize);
257        printStatistic(rt, "  Total frame size", compilationResultTotalFrameSize);
258        printStatistic(rt, "  Exception handlers", compilationResultExceptionHandlers);
259        printStatistic(rt, "  Infopoints", compilationResultInfopoints);
260        compilationResultInfopointStatistics.printStatistics(rt, identity());
261        printStatistic(rt, "  Marks", compilationResultMarks);
262        printStatistic(rt, "  Data references", compilationResultDataPatches);
263
264        if (TruffleCompilerOptions.TruffleCompilationStatisticDetails.getValue()) {
265            printStatistic(rt, "Truffle nodes");
266            nodeStatistics.printStatistics(rt, Class::getSimpleName);
267            printStatistic(rt, "Graal nodes after Truffle tier");
268            truffleTierNodeStatistics.printStatistics(rt, Class::getSimpleName);
269            printStatistic(rt, "Graal nodes after Graal tier");
270            graalTierNodeStatistics.printStatistics(rt, Class::getSimpleName);
271        }
272    }
273
274    private static void printStatistic(GraalTruffleRuntime rt, String label) {
275        rt.log(String.format("  %-50s: ", label));
276    }
277
278    private static void printStatistic(GraalTruffleRuntime rt, String label, int value) {
279        rt.log(String.format("  %-50s: %d", label, value));
280    }
281
282    private static void printStatistic(GraalTruffleRuntime rt, String label, double value) {
283        rt.log(String.format("  %-50s: %f", label, value));
284    }
285
286    private static void printStatistic(GraalTruffleRuntime rt, String label, IntSummaryStatistics value) {
287        rt.log(String.format("  %-50s: count=%4d, sum=%8d, min=%8d, average=%12.2f, max=%8d ", label, value.getCount(), value.getSum(), value.getMin(), value.getAverage(), value.getMax()));
288    }
289
290    private static void printStatisticTime(GraalTruffleRuntime rt, String label, LongSummaryStatistics value) {
291        rt.log(String.format("  %-50s: count=%4d, sum=%8d, min=%8d, average=%12.2f, max=%8d (milliseconds)", label, value.getCount(), value.getSum() / 1000000, value.getMin() / 1000000,
292                        value.getAverage() / 1e6, value.getMax() / 1000000));
293    }
294
295    private static final class IdentityStatistics<T> {
296
297        final Map<T, IntSummaryStatistics> types = new HashMap<>();
298
299        public void printStatistics(GraalTruffleRuntime rt, Function<T, String> toStringFunction) {
300            types.keySet().stream().sorted(Comparator.comparing(c -> -types.get(c).getSum())).//
301            forEach(c -> {
302                printStatistic(rt, String.format("    %s", toStringFunction.apply(c)), types.get(c));
303            });
304        }
305
306        public void accept(Stream<T> classes) {
307            classes.collect(groupingBy(identity(), counting())).//
308            forEach((clazz, count) -> {
309                types.computeIfAbsent(clazz, c -> new IntSummaryStatistics()).accept(count.intValue());
310            });
311        }
312    }
313
314    private static final class CallTargetNodeStatistics {
315
316        // nodeCount = truffleNodeCountTrivial + truffleNodeCountNonTrivial
317        private int nodeCountTrivial;
318        private int nodeCountNonTrivial;
319        private int nodeCountMonomorphic;
320        private int nodeCountPolymorphic;
321        private int nodeCountMegamorphic;
322
323        // callCount = truffleCallCountDirect + truffleCallCountIndirect
324        private int callCountIndirect;
325        // callCountDirect = truffleCallCountDirectDispatched + truffleCallCountDirectInlined
326        private int callCountDirectDispatched;
327        private int callCountDirectInlined;
328        private int callCountDirectCloned;
329        private int callCountDirectNotCloned;
330        private int loopCount;
331
332        public CallTargetNodeStatistics(OptimizedCallTarget target) {
333            target.accept((CallTreeNodeVisitor) this::visitNode, true);
334
335        }
336
337        private boolean visitNode(List<TruffleInlining> stack, Node node) {
338            if (node == null) {
339                return true;
340            }
341
342            NodeCost cost = node.getCost();
343            if (cost.isTrivial()) {
344                nodeCountTrivial++;
345            } else {
346                nodeCountNonTrivial++;
347                if (cost == NodeCost.MONOMORPHIC) {
348                    nodeCountMonomorphic++;
349                } else if (cost == NodeCost.POLYMORPHIC) {
350                    nodeCountPolymorphic++;
351                } else if (cost == NodeCost.MEGAMORPHIC) {
352                    nodeCountMegamorphic++;
353                }
354            }
355
356            if (node instanceof DirectCallNode) {
357                TruffleInliningDecision decision = CallTreeNodeVisitor.getCurrentInliningDecision(stack);
358                if (decision != null && decision.getProfile().getCallNode() == node && decision.isInline()) {
359                    callCountDirectInlined++;
360                } else {
361                    callCountDirectDispatched++;
362                }
363                if (decision != null && decision.getProfile().getCallNode().isCallTargetCloned()) {
364                    callCountDirectCloned++;
365                } else {
366                    callCountDirectNotCloned++;
367                }
368            } else if (node instanceof IndirectCallNode) {
369                callCountIndirect++;
370            } else if (node instanceof LoopNode) {
371                loopCount++;
372            }
373
374            return true;
375        }
376
377        public int getCallCountDirectCloned() {
378            return callCountDirectCloned;
379        }
380
381        public int getCallCountDirectNotCloned() {
382            return callCountDirectNotCloned;
383        }
384
385        public int getNodeCount() {
386            return nodeCountTrivial + nodeCountNonTrivial;
387        }
388
389        public int getCallCount() {
390            return getCallCountDirect() + callCountIndirect;
391        }
392
393        public int getCallCountDirect() {
394            return callCountDirectDispatched + callCountDirectInlined;
395        }
396
397        public int getNodeCountTrivial() {
398            return nodeCountTrivial;
399        }
400
401        public int getNodeCountNonTrivial() {
402            return nodeCountNonTrivial;
403        }
404
405        public int getNodeCountMonomorphic() {
406            return nodeCountMonomorphic;
407        }
408
409        public int getNodeCountPolymorphic() {
410            return nodeCountPolymorphic;
411        }
412
413        public int getNodeCountMegamorphic() {
414            return nodeCountMegamorphic;
415        }
416
417        public int getCallCountIndirect() {
418            return callCountIndirect;
419        }
420
421        public int getCallCountDirectDispatched() {
422            return callCountDirectDispatched;
423        }
424
425        public int getCallCountDirectInlined() {
426            return callCountDirectInlined;
427        }
428
429        public int getLoopCount() {
430            return loopCount;
431        }
432    }
433
434    private static class CompilationLocal {
435
436        private long compilationStarted;
437        private long truffleTierFinished;
438        private long graalTierFinished;
439
440    }
441
442}