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}