/* * Copyright (c) 2013-2017 Chris Newland. * Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD * Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki */ package org.adoptopenjdk.jitwatch.model; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_COMPILER; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_COMPILE_ID; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_COMPILE_KIND; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C1; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C2; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C2N; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_DOT; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.MODIFIERS; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.OSR; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_EMPTY; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_SPACE; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.adoptopenjdk.jitwatch.model.bytecode.SourceMapper; import org.adoptopenjdk.jitwatch.util.ParseUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JITDataModel implements IReadOnlyJITDataModel { private static final Logger logger = LoggerFactory.getLogger(JITDataModel.class); private PackageManager packageManager; private JITStats stats; // Not using CopyOnWriteArrayList as writes will vastly out number reads private List<JITEvent> jitEvents = new ArrayList<>(); // written during parse, make copy for graphing as needs sort private List<CodeCacheEvent> codeCacheTagList = new ArrayList<>(); private Tag endOfLog; private String vmVersionRelease; public JITDataModel() { packageManager = new PackageManager(); stats = new JITStats(); } public void setVmVersionRelease(String release) { this.vmVersionRelease = release; } @Override public String getVmVersionRelease() { return vmVersionRelease; } public void reset() { if (DEBUG_LOGGING) { logger.debug("JITDataModel.reset()"); } packageManager.clear(); SourceMapper.clear(); stats.reset(); jitEvents.clear(); codeCacheTagList.clear(); } @Override public PackageManager getPackageManager() { return packageManager; } @Override public JITStats getJITStats() { return stats; } // ugly but better than using COWAL with so many writes public void addEvent(JITEvent event) { synchronized (jitEvents) { jitEvents.add(event); } } @Override public List<JITEvent> getEventListCopy() { synchronized (jitEvents) { return new ArrayList<>(jitEvents); } } public void addNativeBytes(long count) { stats.addNativeBytes(count); } public void updateStats(IMetaMember member, Map<String, String> attrs) { String fullSignature = member.toString(); for (String modifier : MODIFIERS) { if (fullSignature.contains(modifier + S_SPACE)) { String incMethodName = "incCount" + modifier.substring(0, 1).toUpperCase() + modifier.substring(1); try { MethodType mt = MethodType.methodType(void.class); MethodHandle mh = MethodHandles.lookup().findVirtual(JITStats.class, incMethodName, mt); mh.invokeExact(stats); } catch (Throwable t) { logger.error("Exception: {}", t.getMessage(), t); } } } String compiler = attrs.get(ATTR_COMPILER); if (compiler != null) { if (C1.equalsIgnoreCase(compiler)) { stats.incCountC1(); } else if (C2.equalsIgnoreCase(compiler)) { stats.incCountC2(); } } String compileKind = attrs.get(ATTR_COMPILE_KIND); boolean isC2N = false; if (compileKind != null) { if (OSR.equalsIgnoreCase(compileKind)) { stats.incCountOSR(); } else if (C2N.equalsIgnoreCase(compileKind)) { stats.incCountC2N(); isC2N = true; } } String compileID = attrs.get(ATTR_COMPILE_ID); Compilation compilation = member.getCompilationByCompileID(compileID); if (compilation != null) { if (!isC2N) { stats.recordDelay(compilation.getCompileTime()); } } else { logger.warn("Didn't find compilation with ID {} on member {}", compileID, member.getFullyQualifiedMemberName()); } } @Override public IMetaMember findMetaMember(MemberSignatureParts msp) { IMetaMember result = null; MetaClass metaClass = packageManager.getMetaClass(msp.getFullyQualifiedClassName()); if (metaClass == null) // possible if no TraceClassLoading logs { if (DEBUG_LOGGING) { logger.debug("No metaClass found, trying late load {}", msp.getFullyQualifiedClassName()); } metaClass = ParseUtil.lateLoadMetaClass(this, msp.getFullyQualifiedClassName()); } if (metaClass != null) { List<IMetaMember> metaList = metaClass.getMetaMembers(); if (DEBUG_LOGGING) { logger.debug("Comparing msp against {} members of metaClass {}", metaList.size(), metaClass.toString()); } for (IMetaMember member : metaList) { if (member.matchesSignature(msp, true)) { result = member; break; } } } else { if (DEBUG_LOGGING) { logger.debug("No metaClass found for fqClassName {}", msp.getFullyQualifiedClassName()); } } return result; } @Override public MetaClass buildAndGetMetaClass(Class<?> clazz) { MetaClass resultMetaClass = null; String fqClassName = clazz.getName(); String packageName; String className; int lastDotIndex = fqClassName.lastIndexOf(C_DOT); if (lastDotIndex != -1) { packageName = fqClassName.substring(0, lastDotIndex); className = fqClassName.substring(lastDotIndex + 1); } else { packageName = S_EMPTY; className = fqClassName; } if (DEBUG_LOGGING) { logger.debug("buildAndGetMetaClass {} {}", packageName, fqClassName); } MetaPackage metaPackage = packageManager.getMetaPackage(packageName); if (metaPackage == null) { metaPackage = packageManager.buildPackage(packageName); } resultMetaClass = new MetaClass(metaPackage, className); packageManager.addMetaClass(resultMetaClass); metaPackage.addClass(resultMetaClass); stats.incCountClass(); if (clazz.isInterface()) { resultMetaClass.setInterface(true); } // Class.getDeclaredMethods() or Class.getDeclaredConstructors() // can cause a NoClassDefFoundError / ClassNotFoundException // for a parameter or return type. try { // TODO HERE check for static for (Method m : clazz.getDeclaredMethods()) { MetaMethod metaMethod = new MetaMethod(m, resultMetaClass); resultMetaClass.addMember(metaMethod); stats.incCountMethod(); } for (Constructor<?> c : clazz.getDeclaredConstructors()) { MetaConstructor metaConstructor = new MetaConstructor(c, resultMetaClass); resultMetaClass.addMember(metaConstructor); stats.incCountConstructor(); } } catch (NoClassDefFoundError ncdfe) { logger.warn("NoClassDefFoundError: '{}' while building class {}", ncdfe.getMessage(), fqClassName); throw ncdfe; } catch (Throwable t) { logger.error("Something unexpected happened building meta class {}", fqClassName, t); } return resultMetaClass; } public void addCodeCacheEvent(CodeCacheEvent event) { synchronized (codeCacheTagList) { codeCacheTagList.add(event); } } public void setEndOfLog(Tag tag) { this.endOfLog = tag; } @Override public Tag getEndOfLogTag() { return endOfLog; } @Override public List<CodeCacheEvent> getCodeCacheEvents() { synchronized (codeCacheTagList) { return new ArrayList<>(codeCacheTagList); } } }