/* * Copyright (c) 2015-2016 Jean Phillipe BEMPEL * Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD * Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki */ package org.adoptopenjdk.jitwatch.inline; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BYTES; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_ID; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_METHOD; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_NAME; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_REASON; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_PARSE_HIR; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_CALL; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_INLINE_FAIL; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_INLINE_SUCCESS; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_METHOD; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PARSE; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PHASE; import java.io.PrintStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.adoptopenjdk.jitwatch.compilation.AbstractCompilationVisitable; import org.adoptopenjdk.jitwatch.compilation.ICompilationVisitable; import org.adoptopenjdk.jitwatch.compilation.CompilationUtil; import org.adoptopenjdk.jitwatch.model.Compilation; import org.adoptopenjdk.jitwatch.model.IMetaMember; import org.adoptopenjdk.jitwatch.model.IParseDictionary; import org.adoptopenjdk.jitwatch.model.IReadOnlyJITDataModel; import org.adoptopenjdk.jitwatch.model.LogParseException; import org.adoptopenjdk.jitwatch.model.Tag; import org.adoptopenjdk.jitwatch.treevisitor.ITreeVisitable; import org.adoptopenjdk.jitwatch.util.ParseUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HeadlessInlineVisitor implements ITreeVisitable { private static final Logger logger = LoggerFactory.getLogger(HeadlessInlineVisitor.class); private final Map<String, Map<String, InlineFailureInfo>> failures = new HashMap<>(); private final IReadOnlyJITDataModel model; public HeadlessInlineVisitor(IReadOnlyJITDataModel model) { this.model = model; } @Override public void visit(IMetaMember metaMember) { if (metaMember == null) { return; } if (!metaMember.isCompiled()) { return; } try { String callerName = metaMember.toString(); InlineJournalVisitor inlineJournalVisitor = new InlineJournalVisitor(failures, model, callerName); for (Compilation compilation : metaMember.getCompilations()) { CompilationUtil.visitParseTagsOfCompilation(compilation, inlineJournalVisitor); } } catch (LogParseException e) { logger.error("Error building inlining stats", e); } } @Override public void reset() { } public void printFailedList(PrintStream out) { for (Map.Entry<String, Map<String, InlineFailureInfo>> entry : failures.entrySet()) { out.println("=== " + entry.getKey() + " ==="); Map<String, InlineFailureInfo> members = entry.getValue(); for (InlineFailureInfo inlineFailureInfo : members.values()) { out.println(inlineFailureInfo); } } } private static class InlineJournalVisitor extends AbstractCompilationVisitable implements ICompilationVisitable { private final Map<String, Map<String, InlineFailureInfo>> failures; private final IReadOnlyJITDataModel model; private final String callerName; public InlineJournalVisitor(Map<String, Map<String, InlineFailureInfo>> failures, IReadOnlyJITDataModel model, String callerName) { this.failures = failures; this.model = model; this.callerName = callerName; } @Override public void visitTag(Tag parseTag, IParseDictionary parseDictionary) throws LogParseException { processParseTag(parseTag, parseDictionary); } private void processParseTag(Tag parseTag, IParseDictionary parseDictionary) { String methodID = null; for (Tag child : parseTag.getChildren()) { String tagName = child.getName(); Map<String, String> tagAttrs = child.getAttributes(); switch (tagName) { case TAG_METHOD: { methodID = tagAttrs.get(ATTR_ID); break; } case TAG_CALL: { methodID = tagAttrs.get(ATTR_METHOD); break; } case TAG_INLINE_FAIL: { String reason = tagAttrs.get(ATTR_REASON); Map<String, InlineFailureInfo> inlineFailureInfos = failures.get(reason); if (inlineFailureInfos == null) { inlineFailureInfos = new HashMap<>(); failures.put(reason, inlineFailureInfos); } IMetaMember metaMember = ParseUtil.lookupMember(methodID, parseDictionary, model); if (metaMember == null) { logger.warn("Cannot find name of methodId: ", methodID); } else { String memberName = metaMember.toString(); InlineFailureInfo inlineFailureInfo = inlineFailureInfos.get(memberName); if (inlineFailureInfo == null) { Tag methodTag = parseDictionary.getMethod(methodID); int byteCodeSize = Integer.parseInt(methodTag.getAttributes().get(ATTR_BYTES)); inlineFailureInfo = new InlineFailureInfo(memberName, byteCodeSize); inlineFailureInfos.put(memberName, inlineFailureInfo); } inlineFailureInfo.addCaller(callerName); inlineFailureInfo.incFailureCount(); } methodID = null; break; } case TAG_INLINE_SUCCESS: { break; } case TAG_PARSE: { processParseTag(child, parseDictionary); break; } case TAG_PHASE: { String phaseName = tagAttrs.get(ATTR_NAME); if (S_PARSE_HIR.equals(phaseName)) { processParseTag(child, parseDictionary); } else { logger.warn("Don't know how to handle phase {}", phaseName); } break; } default: handleOther(child); break; } } } } private static class InlineFailureInfo { private String memberName; private int byteCodeSize; private int failureCount; private Set<String> callers = new HashSet<>(); public InlineFailureInfo(String memberName, int byteCodeSize) { this.memberName = memberName; this.byteCodeSize = byteCodeSize; } public void incFailureCount() { failureCount++; } public void addCaller(String name) { callers.add(name); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } InlineFailureInfo that = (InlineFailureInfo) o; return memberName.equals(that.memberName); } @Override public int hashCode() { return memberName.hashCode(); } @Override public String toString() { return "InlineFailureInfo{" + "memberName='" + memberName + '\'' + ", byteCodeSize=" + byteCodeSize + ", failureCount=" + failureCount + ", callers=" + callers + '}'; } } }