/* * 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.launch; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_NEWLINE; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_SPACE; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.HEADLESS_SEPARATOR; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_NEWLINE; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; import org.adoptopenjdk.jitwatch.core.IJITListener; import org.adoptopenjdk.jitwatch.core.JITWatchConfig; import org.adoptopenjdk.jitwatch.inline.HeadlessInlineVisitor; import org.adoptopenjdk.jitwatch.model.IReadOnlyJITDataModel; import org.adoptopenjdk.jitwatch.model.JITEvent; import org.adoptopenjdk.jitwatch.parser.ILogParseErrorListener; import org.adoptopenjdk.jitwatch.parser.ILogParser; import org.adoptopenjdk.jitwatch.parser.ParserFactory; import org.adoptopenjdk.jitwatch.report.Report; import org.adoptopenjdk.jitwatch.report.comparator.ScoreComparator; import org.adoptopenjdk.jitwatch.report.suggestion.SuggestionWalker; import org.adoptopenjdk.jitwatch.treevisitor.TreeVisitor; import org.adoptopenjdk.jitwatch.util.HeadlessUtil; import org.adoptopenjdk.jitwatch.util.StringUtil; public class LaunchHeadless implements IJITListener, ILogParseErrorListener { private boolean showTimeLine; private boolean showErrors; private boolean showModel; private boolean showOnlyCompiledMethods; private boolean showSuggestions; private boolean outputFile; private boolean showInlineFailedCalls; private ILogParser parser; private JITWatchConfig config; private StringBuilder timelineBuilder = new StringBuilder(); private StringBuilder errorBuilder = new StringBuilder(); public LaunchHeadless(String[] args) throws IOException { String logFile = args[args.length - 1]; parseOptions(args); timelineBuilder.append("Timestamp").append(HEADLESS_SEPARATOR); timelineBuilder.append("Event").append(HEADLESS_SEPARATOR); timelineBuilder.append("Class").append(HEADLESS_SEPARATOR); timelineBuilder.append("Member").append(S_NEWLINE); config = new JITWatchConfig(); parser = ParserFactory.getParser(this); parser.setConfig(config); parser.processLogFile(new File(logFile), this); } @Override public void handleLogEntry(String entry) { } @Override public void handleErrorEntry(String entry) { if (showErrors) { errorBuilder.append(entry).append(S_NEWLINE); } } @Override public void handleJITEvent(JITEvent event) { if (showTimeLine) { timelineBuilder.append(StringUtil.formatTimestamp(event.getStamp(), true)).append(HEADLESS_SEPARATOR); timelineBuilder.append(event.getEventType().getText()).append(HEADLESS_SEPARATOR); timelineBuilder.append(event.getEventMember().getMetaClass().getFullyQualifiedName()).append(HEADLESS_SEPARATOR); timelineBuilder.append(event.getEventMember().toStringUnqualifiedMethodName(true, true)).append(S_NEWLINE); } } @Override public void handleReadStart() { } @Override public void handleError(String title, String body) { if (showErrors) { errorBuilder.append(title).append(HEADLESS_SEPARATOR).append(body).append(S_NEWLINE); } } public static void main(String[] args) throws IOException { if (args.length < 2) { System.err.println("Usage: LaunchHeadless <options> <hotspot log file>"); System.err.println("options:"); System.err.println("-e\tShow parse errors"); System.err.println("-m\tShow model"); System.err.println("-c\tShow only compiled methods in model (use with -m)"); System.err.println("-s\tShow code suggestions"); System.err.println("-t\tShow compilation timeline"); System.err.println("-f\tWrite output to headless.csv"); System.err.println("-i\tShow inline failed calls"); // System.err.println("-o\tShow optimized virtual calls"); System.exit(-1); } new LaunchHeadless(args); } private void parseOptions(String[] args) { for (int i = 0; i < args.length - 1; i++) { String arg = args[i]; switch (arg) { case "-c": showOnlyCompiledMethods = true; break; case "-e": showErrors = true; break; case "-m": showModel = true; break; case "-s": showSuggestions = true; break; case "-t": showTimeLine = true; break; case "-f": outputFile = true; break; case "-i": showInlineFailedCalls = true; break; // case "-o": // showOptimizedVirtualCalls = true; // break;s } } } @Override public void handleReadComplete() { StringBuilder outputBuilder = new StringBuilder(); if (showTimeLine) { outputBuilder.append(timelineBuilder.toString()).append(S_NEWLINE); } if (showErrors) { outputBuilder.append(errorBuilder.toString()).append(S_NEWLINE); } if (showModel) { IReadOnlyJITDataModel model = parser.getModel(); String modelString = HeadlessUtil.modelToString(model, showOnlyCompiledMethods); outputBuilder.append(modelString).append(S_NEWLINE); } if (showSuggestions) { SuggestionWalker walker = new SuggestionWalker(parser.getModel()); List<Report> suggestions = walker.getReports(new ScoreComparator()); outputBuilder.append(getSuggestions(suggestions)); } if (outputFile) { outputBuilder.insert(0, "sep=" + HEADLESS_SEPARATOR + S_NEWLINE); try { Files.write(Paths.get("headless.csv"), outputBuilder.toString().getBytes()); System.out.println("Wrote to headless.csv"); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println(outputBuilder.toString()); } if (showInlineFailedCalls) { HeadlessInlineVisitor inlineVisitor = new HeadlessInlineVisitor(parser.getModel()); TreeVisitor.walkTree(parser.getModel(), inlineVisitor); inlineVisitor.printFailedList(System.out); } // if (showOptimizedVirtualCalls) // { // OptimizedVirtualCallVisitable optimizedVCallVisitable = new // OptimizedVirtualCallVisitable(); // // List<OptimizedVirtualCall> optimizedVirtualCalls = // optimizedVCallVisitable.buildOptimizedCalleeReport(parser.getModel(), // config.getAllClassLocations()); // // showOptimizedVCalls(optimizedVirtualCalls); // } } private String getSuggestions(List<Report> suggestions) { StringBuilder builder = new StringBuilder(); builder.append("Type").append(HEADLESS_SEPARATOR); builder.append("Score").append(HEADLESS_SEPARATOR); builder.append("Caller Class").append(HEADLESS_SEPARATOR); builder.append("Caller Member").append(HEADLESS_SEPARATOR); builder.append("BCI").append(HEADLESS_SEPARATOR); builder.append("Suggestion").append(S_NEWLINE); for (Report suggestion : suggestions) { String callerClass; String callerMember; if (suggestion.getCaller() != null) { callerClass = suggestion.getCaller().getMetaClass().getFullyQualifiedName(); callerMember = suggestion.getCaller().toStringUnqualifiedMethodName(true, true); } else { callerClass = "Unknown"; callerMember = "Unknown"; } String cleanText = suggestion.getText().replace(C_NEWLINE, C_SPACE); builder.append(suggestion.getType()).append(HEADLESS_SEPARATOR); builder.append(suggestion.getScore()).append(HEADLESS_SEPARATOR); builder.append(callerClass).append(HEADLESS_SEPARATOR); builder.append(callerMember).append(HEADLESS_SEPARATOR); builder.append(suggestion.getBytecodeOffset()).append(HEADLESS_SEPARATOR); builder.append(cleanText).append(S_NEWLINE); } return builder.toString(); } // private void showOptimizedVCalls(List<OptimizedVirtualCall> vCalls) // { // StringBuilder builder = new StringBuilder(); // // builder.append("Caller class").append(HEADLESS_SEPARATOR); // builder.append("Caller member").append(HEADLESS_SEPARATOR); // builder.append("Source line").append(HEADLESS_SEPARATOR); // builder.append("BCI").append(HEADLESS_SEPARATOR); // builder.append("Instruction").append(HEADLESS_SEPARATOR); // builder.append("Callee class").append(HEADLESS_SEPARATOR); // builder.append("Callee member").append(S_NEWLINE); // // for (OptimizedVirtualCall vCall : vCalls) // { // builder.append(vCall.getCallerMember().getMetaClass().getFullyQualifiedName()).append(HEADLESS_SEPARATOR); // builder.append(vCall.getCallerMember().toString()).append(HEADLESS_SEPARATOR); // builder.append(vCall.getCallsite().getSourceLine()).append(HEADLESS_SEPARATOR); // builder.append(vCall.getCallsite().getBytecodeOffset()).append(HEADLESS_SEPARATOR); // builder.append(vCall.getBytecodeInstruction().getOpcode()).append(HEADLESS_SEPARATOR); // builder.append(vCall.getCallerMember().getMetaClass().getFullyQualifiedName()).append(HEADLESS_SEPARATOR); // builder.append(vCall.getCalleeMember().toString()).append(S_NEWLINE); // } // // System.out.println(builder.toString()); // } }