6900757: minor bug fixes to LogCompilation tool
Improve internal error reporting (point to XML element causing trouble); fix comparator for sorting by name and start; make tool more robust wrt. incorrect options and files not found; make inlining decision output more clear; adopt uncommon traps history printing; properly mention compiler in generated logs; add options for printing time stamps and omitting compilation IDs; add option for comparing compilation logs; overall code cleanup and API documentation Reviewed-by: kvn, vlivanov
This commit is contained in:
parent
2c695decc2
commit
590ec77481
@ -10,3 +10,4 @@
|
||||
.igv.log
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
\.class$
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -62,7 +62,7 @@ all: logc.jar
|
||||
|
||||
logc.jar: filelist manifest.mf
|
||||
@mkdir -p $(OUTPUT_DIR)
|
||||
$(JAVAC) -source 1.5 -deprecation -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) @filelist
|
||||
$(JAVAC) -deprecation -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) @filelist
|
||||
$(JAR) cvfm logc.jar manifest.mf -C $(OUTPUT_DIR) com
|
||||
|
||||
.PHONY: filelist
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,14 +27,29 @@ package com.sun.hotspot.tools.compiler;
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author never
|
||||
* Provide basic data structures and behaviour for {@link LogEvent}s.
|
||||
*/
|
||||
public abstract class BasicLogEvent implements LogEvent {
|
||||
|
||||
/**
|
||||
* The event's ID. This is a number; we represent it as a string for
|
||||
* convenience.
|
||||
*/
|
||||
protected final String id;
|
||||
|
||||
/**
|
||||
* The event's start time.
|
||||
*/
|
||||
protected final double start;
|
||||
|
||||
/**
|
||||
* The event's end time.
|
||||
*/
|
||||
protected double end;
|
||||
|
||||
/**
|
||||
* The compilation during which this event was signalled.
|
||||
*/
|
||||
protected Compilation compilation;
|
||||
|
||||
BasicLogEvent(double start, String id) {
|
||||
@ -43,33 +58,37 @@ public abstract class BasicLogEvent implements LogEvent {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public double getStart() {
|
||||
public final double getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public double getEnd() {
|
||||
public final double getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(double end) {
|
||||
public final void setEnd(double end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public double getElapsedTime() {
|
||||
public final double getElapsedTime() {
|
||||
return ((int) ((getEnd() - getStart()) * 1000)) / 1000.0;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
public final String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Compilation getCompilation() {
|
||||
public final Compilation getCompilation() {
|
||||
return compilation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the compilation for this event. This is not a {@code final} method
|
||||
* as it is overridden in {@link UncommonTrapEvent}.
|
||||
*/
|
||||
public void setCompilation(Compilation compilation) {
|
||||
this.compilation = compilation;
|
||||
}
|
||||
|
||||
abstract public void print(PrintStream stream);
|
||||
abstract public void print(PrintStream stream, boolean printID);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,41 +29,119 @@ import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Representation of a compilation scope in a compilation log. This class is a
|
||||
* hybrid: its instances can represent original scopes of methods being
|
||||
* compiled, but are also used to represent call sites in given methods.
|
||||
*/
|
||||
public class CallSite {
|
||||
|
||||
/**
|
||||
* The index of the call in the caller. This will be 0 if this instance
|
||||
* represents a compilation root.
|
||||
*/
|
||||
private int bci;
|
||||
|
||||
/**
|
||||
* The method that is called at this call site. This will be {@code null}
|
||||
* if this instance represents a compilation root.
|
||||
*/
|
||||
private Method method;
|
||||
|
||||
/**
|
||||
* The invocation count for this call site.
|
||||
*/
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* The receiver type of the call represented by this instance, if known.
|
||||
*/
|
||||
private String receiver;
|
||||
|
||||
/**
|
||||
* In case the {@linkplain receiver receiver type} of the call represented
|
||||
* by this instance is known, this is how often the type was encountered.
|
||||
*/
|
||||
private int receiver_count;
|
||||
|
||||
/**
|
||||
* The reason for a success or failure of an inlining operation at this
|
||||
* call site.
|
||||
*/
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* A list of all calls in this compilation scope.
|
||||
*/
|
||||
private List<CallSite> calls;
|
||||
|
||||
/**
|
||||
* Number of nodes in the graph at the end of parsing this compilation
|
||||
* scope.
|
||||
*/
|
||||
private int endNodes;
|
||||
|
||||
/**
|
||||
* Number of live nodes in the graph at the end of parsing this compilation
|
||||
* scope.
|
||||
*/
|
||||
private int endLiveNodes;
|
||||
|
||||
/**
|
||||
* Time in seconds since VM startup at which parsing this compilation scope
|
||||
* ended.
|
||||
*/
|
||||
private double timeStamp;
|
||||
|
||||
/**
|
||||
* The inline ID in case the call represented by this instance is inlined,
|
||||
* 0 otherwise.
|
||||
*/
|
||||
private long inlineId;
|
||||
|
||||
CallSite() {
|
||||
}
|
||||
/**
|
||||
* List of uncommon traps in this compilation scope.
|
||||
*/
|
||||
private List<UncommonTrap> traps;
|
||||
|
||||
/**
|
||||
* Default constructor: used to create an instance that represents the top
|
||||
* scope of a compilation.
|
||||
*/
|
||||
CallSite() {}
|
||||
|
||||
/**
|
||||
* Constructor to create an instance that represents an actual method call.
|
||||
*/
|
||||
CallSite(int bci, Method m) {
|
||||
this.bci = bci;
|
||||
this.method = m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a call site to the compilation scope represented by this instance.
|
||||
*/
|
||||
void add(CallSite site) {
|
||||
if (getCalls() == null) {
|
||||
setCalls(new ArrayList<CallSite>());
|
||||
calls = new ArrayList<>();
|
||||
}
|
||||
getCalls().add(site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last of the {@linkplain #getCalls() call sites} in this
|
||||
* compilation scope.
|
||||
*/
|
||||
CallSite last() {
|
||||
return last(-1);
|
||||
return getCalls().get(getCalls().size() - 1);
|
||||
}
|
||||
|
||||
CallSite last(int fromEnd) {
|
||||
return getCalls().get(getCalls().size() + fromEnd);
|
||||
/**
|
||||
* Return the last-but-one of the {@linkplain #getCalls() call sites} in
|
||||
* this compilation scope.
|
||||
*/
|
||||
CallSite lastButOne() {
|
||||
return getCalls().get(getCalls().size() - 2);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@ -84,7 +162,7 @@ public class CallSite {
|
||||
}
|
||||
|
||||
public void print(PrintStream stream) {
|
||||
print(stream, 0);
|
||||
print(stream, 0, true, false);
|
||||
}
|
||||
|
||||
void emit(PrintStream stream, int indent) {
|
||||
@ -92,21 +170,14 @@ public class CallSite {
|
||||
stream.print(' ');
|
||||
}
|
||||
}
|
||||
private static boolean compat = true;
|
||||
|
||||
public void print(PrintStream stream, int indent) {
|
||||
public void print(PrintStream stream, int indent, boolean printInlining, boolean printUncommonTraps) {
|
||||
emit(stream, indent);
|
||||
String m = getMethod().getHolder() + "::" + getMethod().getName();
|
||||
if (getReason() == null) {
|
||||
stream.print(" @ " + getBci() + " " + m + " (" + getMethod().getBytes() + " bytes)");
|
||||
|
||||
} else {
|
||||
if (isCompat()) {
|
||||
stream.print(" @ " + getBci() + " " + m + " " + getReason());
|
||||
} else {
|
||||
stream.print("- @ " + getBci() + " " + m +
|
||||
" (" + getMethod().getBytes() + " bytes) " + getReason());
|
||||
}
|
||||
stream.print(" @ " + getBci() + " " + m + " " + getReason());
|
||||
}
|
||||
stream.printf(" (end time: %6.4f", getTimeStamp());
|
||||
if (getEndNodes() > 0) {
|
||||
@ -116,13 +187,16 @@ public class CallSite {
|
||||
|
||||
if (getReceiver() != null) {
|
||||
emit(stream, indent + 4);
|
||||
// stream.println("type profile " + method.holder + " -> " + receiver + " (" +
|
||||
// receiver_count + "/" + count + "," + (receiver_count * 100 / count) + "%)");
|
||||
stream.println("type profile " + getMethod().getHolder() + " -> " + getReceiver() + " (" +
|
||||
(getReceiverCount() * 100 / getCount()) + "%)");
|
||||
}
|
||||
if (getCalls() != null) {
|
||||
if (printInlining && getCalls() != null) {
|
||||
for (CallSite site : getCalls()) {
|
||||
site.print(stream, indent + 2, printInlining, printUncommonTraps);
|
||||
}
|
||||
}
|
||||
if (printUncommonTraps && getTraps() != null) {
|
||||
for (UncommonTrap site : getTraps()) {
|
||||
site.print(stream, indent + 2);
|
||||
}
|
||||
}
|
||||
@ -180,16 +254,15 @@ public class CallSite {
|
||||
return calls;
|
||||
}
|
||||
|
||||
public void setCalls(List<CallSite> calls) {
|
||||
this.calls = calls;
|
||||
public List<UncommonTrap> getTraps() {
|
||||
return traps;
|
||||
}
|
||||
|
||||
public static boolean isCompat() {
|
||||
return compat;
|
||||
}
|
||||
|
||||
public static void setCompat(boolean aCompat) {
|
||||
compat = aCompat;
|
||||
void add(UncommonTrap e) {
|
||||
if (traps == null) {
|
||||
traps = new ArrayList<UncommonTrap>();
|
||||
}
|
||||
traps.add(e);
|
||||
}
|
||||
|
||||
void setEndNodes(int n) {
|
||||
@ -216,21 +289,30 @@ public class CallSite {
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this call site matches another. Every late inline call
|
||||
* site has a unique inline ID. If the call site we're looking for has one,
|
||||
* then use it; otherwise rely on method name and byte code index.
|
||||
*/
|
||||
private boolean matches(CallSite other) {
|
||||
// Every late inline call site has a unique inline id. If the
|
||||
// call site we're looking for has one then use it other rely
|
||||
// on method name and bci.
|
||||
if (other.inlineId != 0) {
|
||||
return inlineId == other.inlineId;
|
||||
}
|
||||
return method.equals(other.method) && bci == other.bci;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a late inline call site: find, in this instance's
|
||||
* {@linkplain #calls call sites}, the one furthest down the given call
|
||||
* stack.
|
||||
*
|
||||
* Multiple chains of identical call sites with the same method name / bci
|
||||
* combination are possible, so we have to try them all until we find the
|
||||
* late inline call site that has a matching inline ID.
|
||||
*
|
||||
* @return a matching call site, or {@code null} if none was found.
|
||||
*/
|
||||
public CallSite findCallSite(ArrayDeque<CallSite> sites) {
|
||||
// Locate a late inline call site. Multiple chains of
|
||||
// identical call sites with the same method name/bci are
|
||||
// possible so we have to try them all until we find the late
|
||||
// inline call site that has a matching inline id.
|
||||
if (calls == null) {
|
||||
return null;
|
||||
}
|
||||
@ -253,6 +335,11 @@ public class CallSite {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a late inline call site in the tree spanned by all this instance's
|
||||
* {@linkplain #calls call sites}, and return the sequence of call sites
|
||||
* (scopes) leading to that late inline call site.
|
||||
*/
|
||||
public ArrayDeque<CallSite> findCallSite2(CallSite site) {
|
||||
if (calls == null) {
|
||||
return null;
|
||||
@ -260,7 +347,7 @@ public class CallSite {
|
||||
|
||||
for (CallSite c : calls) {
|
||||
if (c.matches(site)) {
|
||||
ArrayDeque<CallSite> stack = new ArrayDeque<CallSite>();
|
||||
ArrayDeque<CallSite> stack = new ArrayDeque<>();
|
||||
stack.push(c);
|
||||
return stack;
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,22 +27,94 @@ package com.sun.hotspot.tools.compiler;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* One particular compilation, represented in the compilation log file as a
|
||||
* {@code task} element.
|
||||
*/
|
||||
public class Compilation implements LogEvent {
|
||||
|
||||
/**
|
||||
* The compilation ID.
|
||||
*/
|
||||
private int id;
|
||||
|
||||
/**
|
||||
* Whether this is a compilation for on-stack replacement (OSR).
|
||||
*/
|
||||
private boolean osr;
|
||||
|
||||
/**
|
||||
* The method being compiled.
|
||||
*/
|
||||
private Method method;
|
||||
|
||||
/**
|
||||
* The {@linkplain CallSite scope} of this compilation. This is created as
|
||||
* an empty {@link CallSite} instance, to be filled with data (and
|
||||
* meaning) later on.
|
||||
*/
|
||||
private CallSite call = new CallSite();
|
||||
|
||||
/**
|
||||
* In case a {@code late_inline} event occurs during the compilation, this
|
||||
* field holds the information about it.
|
||||
*/
|
||||
private CallSite lateInlineCall = new CallSite();
|
||||
private int osrBci;
|
||||
|
||||
/**
|
||||
* The bytecode instruction index for on-stack replacement compilations; -1
|
||||
* if this is not an OSR compilation.
|
||||
*/
|
||||
private int bci;
|
||||
|
||||
/**
|
||||
* The method under compilation's invocation count.
|
||||
*/
|
||||
private String icount;
|
||||
|
||||
/**
|
||||
* The method under compilation's backedge count.
|
||||
*/
|
||||
private String bcount;
|
||||
|
||||
/**
|
||||
* Additional information for special compilations (e.g., adapters).
|
||||
*/
|
||||
private String special;
|
||||
|
||||
/**
|
||||
* The name of the compiler performing this compilation.
|
||||
*/
|
||||
private String compiler;
|
||||
|
||||
/**
|
||||
* Start time stamp.
|
||||
*/
|
||||
private double start;
|
||||
|
||||
/**
|
||||
* End time stamp.
|
||||
*/
|
||||
private double end;
|
||||
|
||||
/**
|
||||
* Trip count of the register allocator.
|
||||
*/
|
||||
private int attempts;
|
||||
|
||||
/**
|
||||
* The compilation result (a native method).
|
||||
*/
|
||||
private NMethod nmethod;
|
||||
private ArrayList<Phase> phases = new ArrayList<Phase>(4);
|
||||
|
||||
/**
|
||||
* The phases through which this compilation goes.
|
||||
*/
|
||||
private ArrayList<Phase> phases = new ArrayList<>(4);
|
||||
|
||||
/**
|
||||
* In case this compilation fails, the reason for that.
|
||||
*/
|
||||
private String failureReason;
|
||||
|
||||
Compilation(int id) {
|
||||
@ -52,9 +124,17 @@ public class Compilation implements LogEvent {
|
||||
void reset() {
|
||||
call = new CallSite();
|
||||
lateInlineCall = new CallSite();
|
||||
phases = new ArrayList<Phase>(4);
|
||||
phases = new ArrayList<>(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a compilation phase by name, or {@code null}.
|
||||
*
|
||||
* @param s the name of the phase to retrieve in this compilation.
|
||||
*
|
||||
* @return a compilation phase, or {@code null} if no phase with the given
|
||||
* name is found.
|
||||
*/
|
||||
Phase getPhase(String s) {
|
||||
for (Phase p : getPhases()) {
|
||||
if (p.getName().equals(s)) {
|
||||
@ -72,20 +152,32 @@ public class Compilation implements LogEvent {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setCompiler(String compiler) {
|
||||
this.compiler = compiler;
|
||||
}
|
||||
|
||||
public String getCompiler() {
|
||||
return compiler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getId());
|
||||
sb.append(" ");
|
||||
sb.append(getCompiler());
|
||||
sb.append(" ");
|
||||
sb.append(getMethod());
|
||||
sb.append(" ");
|
||||
sb.append(getIcount());
|
||||
sb.append("+");
|
||||
sb.append(getBcount());
|
||||
sb.append("\n");
|
||||
for (CallSite site : getCall().getCalls()) {
|
||||
sb.append(site);
|
||||
sb.append("\n");
|
||||
if (getCall() != null && getCall().getCalls() != null) {
|
||||
for (CallSite site : getCall().getCalls()) {
|
||||
sb.append(site);
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
if (getLateInlineCall().getCalls() != null) {
|
||||
sb.append("late inline:\n");
|
||||
@ -101,38 +193,50 @@ public class Compilation implements LogEvent {
|
||||
if (getMethod() == null) {
|
||||
stream.println(getSpecial());
|
||||
} else {
|
||||
int bc = isOsr() ? getOsr_bci() : -1;
|
||||
stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc));
|
||||
int bc = isOsr() ? getBCI() : -1;
|
||||
stream.print(getId() + getMethod().decodeFlags(bc) + " " + compiler + " " + getMethod().format(bc));
|
||||
}
|
||||
}
|
||||
|
||||
public void print(PrintStream stream) {
|
||||
print(stream, 0, false);
|
||||
public void print(PrintStream stream, boolean printID) {
|
||||
print(stream, 0, printID, true, false);
|
||||
}
|
||||
|
||||
public void print(PrintStream stream, boolean printInlining) {
|
||||
print(stream, 0, printInlining);
|
||||
public void print(PrintStream stream, boolean printID, boolean printInlining) {
|
||||
print(stream, 0, printID, printInlining, false);
|
||||
}
|
||||
|
||||
public void print(PrintStream stream, int indent, boolean printInlining) {
|
||||
public void print(PrintStream stream, boolean printID, boolean printInlining, boolean printUncommonTraps) {
|
||||
print(stream, 0, printID, printInlining, printUncommonTraps);
|
||||
}
|
||||
|
||||
public void print(PrintStream stream, int indent, boolean printID, boolean printInlining, boolean printUncommonTraps) {
|
||||
if (getMethod() == null) {
|
||||
stream.println(getSpecial());
|
||||
} else {
|
||||
int bc = isOsr() ? getOsr_bci() : -1;
|
||||
stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc));
|
||||
if (printID) {
|
||||
stream.print(getId());
|
||||
}
|
||||
int bc = isOsr() ? getBCI() : -1;
|
||||
stream.print(getMethod().decodeFlags(bc) + " " + compiler + " " + getMethod().format(bc));
|
||||
stream.println();
|
||||
if (getFailureReason() != null) {
|
||||
stream.println("COMPILE FAILED " + getFailureReason());
|
||||
stream.println("COMPILE SKIPPED: " + getFailureReason() + " (not retryable)");
|
||||
}
|
||||
if (printInlining && call.getCalls() != null) {
|
||||
for (CallSite site : call.getCalls()) {
|
||||
site.print(stream, indent + 2, printInlining, printUncommonTraps);
|
||||
}
|
||||
}
|
||||
if (printUncommonTraps && call.getTraps() != null) {
|
||||
for (UncommonTrap site : call.getTraps()) {
|
||||
site.print(stream, indent + 2);
|
||||
}
|
||||
}
|
||||
if (printInlining && lateInlineCall.getCalls() != null) {
|
||||
stream.println("late inline:");
|
||||
for (CallSite site : lateInlineCall.getCalls()) {
|
||||
site.print(stream, indent + 2);
|
||||
site.print(stream, indent + 2, printInlining, printUncommonTraps);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,12 +258,12 @@ public class Compilation implements LogEvent {
|
||||
this.osr = osr;
|
||||
}
|
||||
|
||||
public int getOsr_bci() {
|
||||
return osrBci;
|
||||
public int getBCI() {
|
||||
return bci;
|
||||
}
|
||||
|
||||
public void setOsr_bci(int osrBci) {
|
||||
this.osrBci = osrBci;
|
||||
public void setBCI(int osrBci) {
|
||||
this.bci = osrBci;
|
||||
}
|
||||
|
||||
public String getIcount() {
|
||||
@ -230,9 +334,13 @@ public class Compilation implements LogEvent {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the method under compilation. If it is already set, ignore the
|
||||
* argument to avoid changing the method by post-parse inlining info.
|
||||
*
|
||||
* @param method the method under compilation. May be ignored.
|
||||
*/
|
||||
public void setMethod(Method method) {
|
||||
// Don't change method if it is already set to avoid changing
|
||||
// it by post parse inlining info.
|
||||
if (getMethod() == null) {
|
||||
this.method = method;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,10 +31,9 @@ import java.util.regex.*;
|
||||
* This class is a filter class to deal with malformed XML that used
|
||||
* to be produced by the JVM when generating LogCompilation. In 1.6
|
||||
* and later releases it shouldn't be required.
|
||||
* @author never
|
||||
*/
|
||||
|
||||
class LogCleanupReader extends Reader {
|
||||
|
||||
private Reader reader;
|
||||
|
||||
private char[] buffer = new char[4096];
|
||||
@ -55,32 +54,38 @@ class LogCleanupReader extends Reader {
|
||||
reader = r;
|
||||
}
|
||||
|
||||
static final private Matcher pattern = Pattern.compile(".+ compile_id='[0-9]+'.*( compile_id='[0-9]+)").matcher("");
|
||||
static final private Matcher pattern2 = Pattern.compile("' (C[12]) compile_id=").matcher("");
|
||||
static final private Matcher pattern3 = Pattern.compile("'(destroy_vm)/").matcher("");
|
||||
static final private Matcher duplicateCompileID = Pattern.compile(".+ compile_id='[0-9]+'.*( compile_id='[0-9]+)").matcher("");
|
||||
static final private Matcher compilerName = Pattern.compile("' (C[12]) compile_id=").matcher("");
|
||||
static final private Matcher destroyVM = Pattern.compile("'(destroy_vm)/").matcher("");
|
||||
|
||||
/**
|
||||
* The log cleanup takes place in this method. If any of the three patterns
|
||||
* ({@link #duplicateCompileID}, {@link #compilerName}, {@link #destroyVM})
|
||||
* match, that indicates a problem in the log. The cleanup is performed by
|
||||
* correcting the input line and writing it back into the {@link #line}
|
||||
* buffer.
|
||||
*/
|
||||
private void fill() throws IOException {
|
||||
rawFill();
|
||||
if (length != -1) {
|
||||
boolean changed = false;
|
||||
String s = new String(line, 0, length);
|
||||
String orig = s;
|
||||
|
||||
pattern2.reset(s);
|
||||
if (pattern2.find()) {
|
||||
s = s.substring(0, pattern2.start(1)) + s.substring(pattern2.end(1) + 1);
|
||||
compilerName.reset(s);
|
||||
if (compilerName.find()) {
|
||||
s = s.substring(0, compilerName.start(1)) + s.substring(compilerName.end(1) + 1);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
pattern.reset(s);
|
||||
if (pattern.lookingAt()) {
|
||||
s = s.substring(0, pattern.start(1)) + s.substring(pattern.end(1) + 1);
|
||||
duplicateCompileID.reset(s);
|
||||
if (duplicateCompileID.lookingAt()) {
|
||||
s = s.substring(0, duplicateCompileID.start(1)) + s.substring(duplicateCompileID.end(1) + 1);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
pattern3.reset(s);
|
||||
if (pattern3.find()) {
|
||||
s = s.substring(0, pattern3.start(1)) + s.substring(pattern3.end(1));
|
||||
destroyVM.reset(s);
|
||||
if (destroyVM.find()) {
|
||||
s = s.substring(0, destroyVM.start(1)) + s.substring(destroyVM.end(1));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,60 +22,102 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The main command line driver of a parser for LogCompilation output.
|
||||
* @author never
|
||||
*/
|
||||
|
||||
package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
import org.xml.sax.*;
|
||||
import org.xml.sax.helpers.*;
|
||||
|
||||
public class LogCompilation extends DefaultHandler implements ErrorHandler, Constants {
|
||||
/**
|
||||
* The LogCompilation tool parses log files generated by HotSpot using the
|
||||
* {@code -XX:+LogCompilation} command line flag, and outputs the data
|
||||
* collected therein in a nicely formatted way. There are various sorting
|
||||
* options available, as well as options that select specific compilation
|
||||
* events (such as inlining decisions) for inclusion in the output.
|
||||
*
|
||||
* The tool is also capable of fixing broken compilation logs as sometimes
|
||||
* generated by Java 1.5 JVMs.
|
||||
*/
|
||||
public class LogCompilation extends DefaultHandler implements ErrorHandler {
|
||||
|
||||
/**
|
||||
* Print usage information and terminate with a given exit code.
|
||||
*/
|
||||
public static void usage(int exitcode) {
|
||||
System.out.println("Usage: LogCompilation [ -v ] [ -c ] [ -s ] [ -e | -n ] file1 ...");
|
||||
System.out.println("By default, the tool will print the logged compilations ordered by start time.");
|
||||
System.out.println(" -c: clean up malformed 1.5 xml");
|
||||
System.out.println(" -i: print inlining decisions");
|
||||
System.out.println(" -S: print compilation statistics");
|
||||
System.out.println(" -s: sort events by start time");
|
||||
System.out.println(" -U: print uncommon trap statistics");
|
||||
System.out.println(" -t: print with time stamps");
|
||||
System.out.println(" -s: sort events by start time (default)");
|
||||
System.out.println(" -e: sort events by elapsed time");
|
||||
System.out.println(" -n: sort events by name and start");
|
||||
System.out.println(" -C: compare logs (give files to compare on command line)");
|
||||
System.out.println(" -d: do not print compilation IDs");
|
||||
System.exit(exitcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process command line arguments, parse log files and trigger desired
|
||||
* functionality.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Comparator<LogEvent> defaultSort = LogParser.sortByStart;
|
||||
Comparator<LogEvent> sort = LogParser.sortByStart;
|
||||
boolean statistics = false;
|
||||
boolean printInlining = false;
|
||||
boolean cleanup = false;
|
||||
boolean trapHistory = false;
|
||||
boolean printTimeStamps = false;
|
||||
boolean compare = false;
|
||||
boolean printID = true;
|
||||
int index = 0;
|
||||
|
||||
while (args.length > index) {
|
||||
if (args[index].equals("-e")) {
|
||||
defaultSort = LogParser.sortByElapsed;
|
||||
String a = args[index];
|
||||
if (a.equals("-e")) {
|
||||
sort = LogParser.sortByElapsed;
|
||||
index++;
|
||||
} else if (args[index].equals("-n")) {
|
||||
defaultSort = LogParser.sortByNameAndStart;
|
||||
} else if (a.equals("-n")) {
|
||||
sort = LogParser.sortByNameAndStart;
|
||||
index++;
|
||||
} else if (args[index].equals("-s")) {
|
||||
defaultSort = LogParser.sortByStart;
|
||||
} else if (a.equals("-s")) {
|
||||
sort = LogParser.sortByStart;
|
||||
index++;
|
||||
} else if (args[index].equals("-c")) {
|
||||
} else if (a.equals("-t")) {
|
||||
printTimeStamps = true;
|
||||
index++;
|
||||
} else if (a.equals("-c")) {
|
||||
cleanup = true;
|
||||
index++;
|
||||
} else if (args[index].equals("-S")) {
|
||||
} else if (a.equals("-S")) {
|
||||
statistics = true;
|
||||
index++;
|
||||
} else if (args[index].equals("-h")) {
|
||||
} else if (a.equals("-U")) {
|
||||
trapHistory = true;
|
||||
index++;
|
||||
} else if (a.equals("-h")) {
|
||||
usage(0);
|
||||
} else if (args[index].equals("-i")) {
|
||||
} else if (a.equals("-i")) {
|
||||
printInlining = true;
|
||||
index++;
|
||||
} else if (a.equals("-C")) {
|
||||
compare = true;
|
||||
index++;
|
||||
} else if (a.equals("-d")) {
|
||||
printID = false;
|
||||
index++;
|
||||
} else {
|
||||
if (a.charAt(0) == '-') {
|
||||
System.out.println("Unknown option '" + a + "', assuming file name.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -84,19 +126,40 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
|
||||
usage(1);
|
||||
}
|
||||
|
||||
if (compare) {
|
||||
compareLogs(index, args);
|
||||
return;
|
||||
}
|
||||
|
||||
while (index < args.length) {
|
||||
ArrayList<LogEvent> events = LogParser.parse(args[index], cleanup);
|
||||
ArrayList<LogEvent> events = null;
|
||||
try {
|
||||
events = LogParser.parse(args[index], cleanup);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
System.out.println("File not found: " + args[index]);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
Collections.sort(events, sort);
|
||||
|
||||
if (statistics) {
|
||||
printStatistics(events, System.out);
|
||||
} else if (trapHistory) {
|
||||
printTrapHistory(events, System.out);
|
||||
} else {
|
||||
Collections.sort(events, defaultSort);
|
||||
for (LogEvent c : events) {
|
||||
if (printInlining && c instanceof Compilation) {
|
||||
Compilation comp = (Compilation)c;
|
||||
comp.print(System.out, true);
|
||||
if (c instanceof NMethod) {
|
||||
// skip these
|
||||
continue;
|
||||
}
|
||||
if (printTimeStamps) {
|
||||
System.out.print(c.getStart() + ": ");
|
||||
}
|
||||
if (c instanceof Compilation) {
|
||||
Compilation comp = (Compilation) c;
|
||||
comp.print(System.out, printID, printInlining);
|
||||
} else {
|
||||
c.print(System.out);
|
||||
c.print(System.out, printID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,17 +167,25 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print extensive statistics from parsed log files.
|
||||
*/
|
||||
public static void printStatistics(ArrayList<LogEvent> events, PrintStream out) {
|
||||
// track code cache size
|
||||
long cacheSize = 0;
|
||||
long maxCacheSize = 0;
|
||||
// track number of nmethods
|
||||
int nmethodsCreated = 0;
|
||||
int nmethodsLive = 0;
|
||||
// track how many compilations were attempted multiple times
|
||||
// (indexed by attempts, mapping to number of compilations)
|
||||
int[] attempts = new int[32];
|
||||
double regallocTime = 0;
|
||||
int maxattempts = 0;
|
||||
|
||||
LinkedHashMap<String, Double> phaseTime = new LinkedHashMap<String, Double>(7);
|
||||
LinkedHashMap<String, Integer> phaseNodes = new LinkedHashMap<String, Integer>(7);
|
||||
// track time spent in compiler phases
|
||||
LinkedHashMap<String, Double> phaseTime = new LinkedHashMap<>(7);
|
||||
// track nodes created per phase
|
||||
LinkedHashMap<String, Integer> phaseNodes = new LinkedHashMap<>(7);
|
||||
double elapsed = 0;
|
||||
|
||||
for (LogEvent e : events) {
|
||||
@ -137,18 +208,17 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
|
||||
v2 = Integer.valueOf(0);
|
||||
}
|
||||
phaseNodes.put(phase.getName(), Integer.valueOf(v2.intValue() + phase.getNodes()));
|
||||
/* Print phase name, elapsed time, nodes at the start of the phase,
|
||||
nodes created in the phase, live nodes at the start of the phase,
|
||||
live nodes added in the phase.
|
||||
*/
|
||||
out.printf("\t%s %6.4f %d %d %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes(), phase.getStartLiveNodes(), phase.getLiveNodes());
|
||||
// Print phase name, elapsed time, nodes at the start of
|
||||
// the phase, nodes created in the phase, live nodes at the
|
||||
// start of the phase, live nodes added in the phase.
|
||||
out.printf("\t%s %6.4f %d %d %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes(), phase.getStartLiveNodes(), phase.getAddedLiveNodes());
|
||||
}
|
||||
} else if (e instanceof MakeNotEntrantEvent) {
|
||||
MakeNotEntrantEvent mne = (MakeNotEntrantEvent) e;
|
||||
NMethod nm = mne.getNMethod();
|
||||
if (mne.isZombie()) {
|
||||
if (nm == null) {
|
||||
System.err.println(mne.getId());
|
||||
System.err.println("zombie make not entrant event without nmethod: " + mne.getId());
|
||||
}
|
||||
cacheSize -= nm.getSize();
|
||||
nmethodsLive--;
|
||||
@ -161,8 +231,7 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
|
||||
maxCacheSize = Math.max(cacheSize, maxCacheSize);
|
||||
}
|
||||
}
|
||||
out.printf("NMethods: %d created %d live %d bytes (%d peak) in the code cache\n",
|
||||
nmethodsCreated, nmethodsLive, cacheSize, maxCacheSize);
|
||||
out.printf("NMethods: %d created %d live %d bytes (%d peak) in the code cache\n", nmethodsCreated, nmethodsLive, cacheSize, maxCacheSize);
|
||||
out.println("Phase times:");
|
||||
for (String name : phaseTime.keySet()) {
|
||||
Double v = phaseTime.get(name);
|
||||
@ -178,4 +247,265 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Container class for a pair of a method and a bytecode instruction index
|
||||
* used by a compiler. This is used in
|
||||
* {@linkplain #compareLogs() comparing logs}.
|
||||
*/
|
||||
static class MethodBCIPair {
|
||||
public MethodBCIPair(Method m, int b, String c) {
|
||||
method = m;
|
||||
bci = b;
|
||||
compiler = c;
|
||||
}
|
||||
|
||||
Method method;
|
||||
int bci;
|
||||
String compiler;
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof MethodBCIPair)) {
|
||||
return false;
|
||||
}
|
||||
MethodBCIPair otherp = (MethodBCIPair)other;
|
||||
return (otherp.bci == bci &&
|
||||
otherp.method.equals(method) &&
|
||||
otherp.compiler.equals(compiler));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return method.hashCode() + bci;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (bci != -1) {
|
||||
return method + "@" + bci + " (" + compiler + ")";
|
||||
} else {
|
||||
return method + " (" + compiler + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare a number of compilation log files. Each of the logs is parsed,
|
||||
* and all compilations found therein are written to a sorted file (prefix
|
||||
* {@code sorted-}. A summary is written to a new file {@code summary.txt}.
|
||||
*
|
||||
* @param index the index in the command line arguments at which to start
|
||||
* looking for files to compare.
|
||||
* @param args the command line arguments with which {@link LogCompilation}
|
||||
* was originally invoked.
|
||||
*
|
||||
* @throws Exception in case any exceptions are thrown in the called
|
||||
* methods.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static void compareLogs(int index, String[] args) throws Exception {
|
||||
HashMap<MethodBCIPair,MethodBCIPair> methods = new HashMap<>();
|
||||
ArrayList<HashMap<MethodBCIPair,Object>> logs = new ArrayList<>();
|
||||
PrintStream[] outs = new PrintStream[args.length - index];
|
||||
PrintStream summary = new PrintStream(new FileOutputStream("summary.txt"));
|
||||
int o = 0;
|
||||
// Process all logs given on the command line: collect compilation
|
||||
// data; in particular, method/bci pairs.
|
||||
while (index < args.length) {
|
||||
String basename = new File(args[index]).getName();
|
||||
String outname = "sorted-" + basename;
|
||||
System.out.println("Sorting " + basename + " to " + outname);
|
||||
outs[o] = new PrintStream(new FileOutputStream(outname));
|
||||
o++;
|
||||
System.out.println("Parsing " + args[index]);
|
||||
ArrayList<LogEvent> events = LogParser.parse(args[index], false);
|
||||
HashMap<MethodBCIPair,Object> compiles = new HashMap<>();
|
||||
logs.add(compiles);
|
||||
for (LogEvent c : events) {
|
||||
if (c instanceof Compilation) {
|
||||
Compilation comp = (Compilation) c;
|
||||
MethodBCIPair key = new MethodBCIPair(comp.getMethod(), comp.getBCI(),
|
||||
comp.getCompiler());
|
||||
MethodBCIPair e = methods.get(key);
|
||||
if (e == null) {
|
||||
methods.put(key, key);
|
||||
} else {
|
||||
key = e;
|
||||
}
|
||||
Object other = compiles.get(key);
|
||||
if (other == null) {
|
||||
compiles.put(key, comp);
|
||||
} else {
|
||||
if (!(other instanceof List)) {
|
||||
List<Object> l = new LinkedList<>();
|
||||
l.add(other);
|
||||
l.add(comp);
|
||||
compiles.put(key, l);
|
||||
} else {
|
||||
List<Object> l = (List<Object>) other;
|
||||
l.add(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// Process the collected method/bci pairs and write the output.
|
||||
for (MethodBCIPair pair : methods.keySet()) {
|
||||
summary.print(pair + " ");
|
||||
int base = -1;
|
||||
String first = null;
|
||||
boolean mismatch = false;
|
||||
boolean different = false;
|
||||
String[] output = new String[outs.length];
|
||||
o = 0;
|
||||
for (HashMap<MethodBCIPair,Object> set : logs) {
|
||||
Object e = set.get(pair);
|
||||
String thisone = null;
|
||||
Compilation lastc = null;
|
||||
int n;
|
||||
if (e == null) {
|
||||
n = 0;
|
||||
} else if (e instanceof Compilation) {
|
||||
n = 1;
|
||||
lastc = (Compilation) e;
|
||||
} else {
|
||||
// Compare the last compilation that was done for this method
|
||||
n = ((List<Object>) e).size();
|
||||
lastc = (Compilation) ((List<Object>) e).get(n - 1);
|
||||
}
|
||||
if (lastc != null) {
|
||||
n = 1;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintStream ps = new PrintStream(baos);
|
||||
lastc.print(ps, false);
|
||||
ps.close();
|
||||
thisone = new String(baos.toByteArray());
|
||||
}
|
||||
if (base == -1) {
|
||||
base = n;
|
||||
} else if (base != n) {
|
||||
mismatch = true;
|
||||
}
|
||||
output[o++] = thisone;
|
||||
if (thisone != null) {
|
||||
if (first == null) {
|
||||
first = thisone;
|
||||
} else {
|
||||
if (!first.equals(thisone)) {
|
||||
different = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (different) {
|
||||
summary.print(n + "d ");
|
||||
} else {
|
||||
summary.print(n + " ");
|
||||
}
|
||||
}
|
||||
if (mismatch) {
|
||||
summary.print("mismatch");
|
||||
}
|
||||
summary.println();
|
||||
if (different) {
|
||||
for (int i = 0; i < outs.length; i++) {
|
||||
if (output[i] != null) {
|
||||
outs[i].println(output[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < outs.length; i++) {
|
||||
outs[i].close();
|
||||
}
|
||||
if (summary != System.out) {
|
||||
summary.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the history of uncommon trap events.
|
||||
*/
|
||||
public static void printTrapHistory(ArrayList<LogEvent> events, PrintStream out) {
|
||||
// map method names to a list of log events
|
||||
LinkedHashMap<String, ArrayList<LogEvent>> traps = new LinkedHashMap<>();
|
||||
// map compilation IDs to compilations
|
||||
HashMap<Integer, Compilation> comps = new HashMap<>();
|
||||
|
||||
// First, iterate over all logged events, collecting data about
|
||||
// uncommon trap events.
|
||||
for (LogEvent e : events) {
|
||||
if (e instanceof NMethod) {
|
||||
// skip these
|
||||
continue;
|
||||
}
|
||||
if (e instanceof Compilation) {
|
||||
Compilation c = (Compilation) e;
|
||||
String name = c.getMethod().getFullName();
|
||||
ArrayList<LogEvent> elist = traps.get(name);
|
||||
if (elist != null && comps.get(c.getId()) == null) {
|
||||
comps.put(c.getId(), c);
|
||||
// If there were previous events for the method
|
||||
// then keep track of later compiles too.
|
||||
elist.add(c);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (e instanceof BasicLogEvent) {
|
||||
BasicLogEvent ble = (BasicLogEvent) e;
|
||||
Compilation c = ble.getCompilation();
|
||||
if (c == null) {
|
||||
if (!(ble instanceof NMethod)) {
|
||||
throw new InternalError("only nmethods should have a null compilation; here's a " + ble.getClass());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
String name = c.getMethod().getFullName();
|
||||
ArrayList<LogEvent> elist = traps.get(name);
|
||||
if (elist == null) {
|
||||
elist = new ArrayList<LogEvent>();
|
||||
traps.put(name, elist);
|
||||
}
|
||||
int bleId = Integer.parseInt(ble.getId());
|
||||
if (comps.get(bleId) == null) {
|
||||
comps.put(bleId, c);
|
||||
// Add the associated compile to the list. It
|
||||
// will likely go at the end but we need to search
|
||||
// backwards for the proper insertion point.
|
||||
double start = c.getStart();
|
||||
int ipoint = 0;
|
||||
while (ipoint < elist.size() && elist.get(ipoint).getStart() < start) {
|
||||
ipoint++;
|
||||
}
|
||||
if (ipoint == elist.size()) {
|
||||
elist.add(c);
|
||||
} else {
|
||||
elist.add(ipoint, c);
|
||||
}
|
||||
}
|
||||
elist.add(ble);
|
||||
}
|
||||
}
|
||||
|
||||
// Second, iterate over collected traps and output information.
|
||||
for (String c: traps.keySet()) {
|
||||
ArrayList<LogEvent> elist = traps.get(c);
|
||||
String name = ((Compilation) elist.get(0)).getMethod().getFullName();
|
||||
System.out.println(name);
|
||||
double start = 0;
|
||||
for (LogEvent e: elist) {
|
||||
if (start > e.getStart() && e.getStart() != 0) {
|
||||
throw new InternalError("wrong sorting order for traps");
|
||||
}
|
||||
start = e.getStart();
|
||||
out.print(e.getStart() + ": ");
|
||||
if (e instanceof Compilation) {
|
||||
((Compilation) e).print(out, true, true, true);
|
||||
} else {
|
||||
e.print(out, true);
|
||||
}
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,14 +25,31 @@
|
||||
package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The interface of an event from a HotSpot compilation log. Events can have a
|
||||
* duration, e.g., a compiler {@link Phase} is an event, and so is an entire
|
||||
* {@link Compilation}.
|
||||
*/
|
||||
public interface LogEvent {
|
||||
|
||||
/**
|
||||
* The event's start time.
|
||||
*/
|
||||
public double getStart();
|
||||
|
||||
/**
|
||||
* The event's duration in milliseconds.
|
||||
*/
|
||||
public double getElapsedTime();
|
||||
|
||||
/**
|
||||
* The compilation during which this event was signalled.
|
||||
*/
|
||||
public Compilation getCompilation();
|
||||
|
||||
public void print(PrintStream stream);
|
||||
/**
|
||||
* Print the event to the given stream.
|
||||
*/
|
||||
public void print(PrintStream stream, boolean printID);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -21,14 +21,25 @@
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
* In a compilation log, represent the event of making a given compiled method
|
||||
* not-entrant, e.g., during an OSR compilation.
|
||||
*/
|
||||
class MakeNotEntrantEvent extends BasicLogEvent {
|
||||
|
||||
/**
|
||||
* Denote whether the method is marked as a zombie, i.e., no further
|
||||
* activations exist.
|
||||
*/
|
||||
private final boolean zombie;
|
||||
|
||||
/**
|
||||
* The method in question.
|
||||
*/
|
||||
private NMethod nmethod;
|
||||
|
||||
MakeNotEntrantEvent(double s, String i, boolean z, NMethod nm) {
|
||||
@ -41,7 +52,7 @@ class MakeNotEntrantEvent extends BasicLogEvent {
|
||||
return nmethod;
|
||||
}
|
||||
|
||||
public void print(PrintStream stream) {
|
||||
public void print(PrintStream stream, boolean printID) {
|
||||
if (isZombie()) {
|
||||
stream.printf("%s make_zombie\n", getId());
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,16 +26,58 @@ package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Method implements Constants {
|
||||
import static com.sun.hotspot.tools.compiler.Constants.*;
|
||||
|
||||
/**
|
||||
* Representation of a Java method in a compilation log.
|
||||
*/
|
||||
public class Method {
|
||||
|
||||
/**
|
||||
* The name of the class holding the method.
|
||||
*/
|
||||
private String holder;
|
||||
|
||||
/**
|
||||
* The method's name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The return type of the method, as a fully qualified (source-level) class
|
||||
* or primitive type name.
|
||||
*/
|
||||
private String returnType;
|
||||
private String arguments;
|
||||
|
||||
/**
|
||||
* The method's signature, in internal form.
|
||||
*/
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* The length of the method's byte code.
|
||||
*/
|
||||
private String bytes;
|
||||
|
||||
/**
|
||||
* The number of times this method was invoked in the interpreter.
|
||||
*/
|
||||
private String iicount;
|
||||
|
||||
/**
|
||||
* The method's flags, in the form of a {@code String} representing the
|
||||
* {@code int} encoding them.
|
||||
*/
|
||||
private String flags;
|
||||
|
||||
/**
|
||||
* Decode the {@link flags} numerical string to a format for console
|
||||
* output. The result does not honour all possible flags but includes
|
||||
* information about OSR compilation.
|
||||
*
|
||||
* @param osr_bci the byte code index at which an OSR compilation takes
|
||||
* place, or -1 if the compilation is not an OSR one.
|
||||
*/
|
||||
String decodeFlags(int osr_bci) {
|
||||
int f = Integer.parseInt(getFlags());
|
||||
char[] c = new char[4];
|
||||
@ -49,6 +91,12 @@ public class Method implements Constants {
|
||||
return new String(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format this method for console output.
|
||||
*
|
||||
* @param osr_bci the byte code index at which OSR takes place, or -1 if no
|
||||
* OSR compilation is going on.
|
||||
*/
|
||||
String format(int osr_bci) {
|
||||
if (osr_bci >= 0) {
|
||||
return getHolder() + "::" + getName() + " @ " + osr_bci + " (" + getBytes() + " bytes)";
|
||||
@ -62,6 +110,10 @@ public class Method implements Constants {
|
||||
return getHolder() + "::" + getName() + " (" + getBytes() + " bytes)";
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return getHolder().replace('/', '.') + "." + getName() + signature;
|
||||
}
|
||||
|
||||
public String getHolder() {
|
||||
return holder;
|
||||
}
|
||||
@ -86,12 +138,16 @@ public class Method implements Constants {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
public String getArguments() {
|
||||
return arguments;
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setArguments(String arguments) {
|
||||
this.arguments = arguments;
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature.replace('/', '.');
|
||||
}
|
||||
|
||||
public String getArguments() {
|
||||
return signature.substring(0, signature.indexOf(')') + 1);
|
||||
}
|
||||
|
||||
public String getBytes() {
|
||||
@ -121,10 +177,13 @@ public class Method implements Constants {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Method) {
|
||||
Method other = (Method)o;
|
||||
return holder.equals(other.holder) && name.equals(other.name) &&
|
||||
arguments.equals(other.arguments) && returnType.equals(other.returnType);
|
||||
Method other = (Method) o;
|
||||
return holder.equals(other.holder) && name.equals(other.name) && signature.equals(other.signature);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return holder.hashCode() ^ name.hashCode();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,9 +26,20 @@ package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
* A compilation log event that is signalled whenever a new nmethod (a native
|
||||
* method, a compilation result) is created.
|
||||
*/
|
||||
public class NMethod extends BasicLogEvent {
|
||||
|
||||
/**
|
||||
* The nmethod's starting address in memory.
|
||||
*/
|
||||
private long address;
|
||||
|
||||
/**
|
||||
* The nmethod's size in bytes.
|
||||
*/
|
||||
private long size;
|
||||
|
||||
NMethod(double s, String i, long a, long sz) {
|
||||
@ -37,7 +48,7 @@ public class NMethod extends BasicLogEvent {
|
||||
size = sz;
|
||||
}
|
||||
|
||||
public void print(PrintStream out) {
|
||||
public void print(PrintStream out, boolean printID) {
|
||||
// XXX Currently we do nothing
|
||||
// throw new InternalError();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,11 +26,30 @@ package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
* Representation of a compilation phase as a log event.
|
||||
*/
|
||||
public class Phase extends BasicLogEvent {
|
||||
|
||||
/**
|
||||
* The number of nodes in the compilation at the beginning of this phase.
|
||||
*/
|
||||
private final int startNodes;
|
||||
|
||||
/**
|
||||
* The number of nodes in the compilation at the end of this phase.
|
||||
*/
|
||||
private int endNodes;
|
||||
|
||||
/**
|
||||
* The number of live nodes in the compilation at the beginning of this
|
||||
* phase.
|
||||
*/
|
||||
private final int startLiveNodes;
|
||||
|
||||
/**
|
||||
* The number of live nodes in the compilation at the end of this phase.
|
||||
*/
|
||||
private int endLiveNodes;
|
||||
|
||||
Phase(String n, double s, int nodes, int live) {
|
||||
@ -58,8 +77,11 @@ public class Phase extends BasicLogEvent {
|
||||
public int getEndNodes() {
|
||||
return endNodes;
|
||||
}
|
||||
/* Number of live nodes added by the phase */
|
||||
int getLiveNodes() {
|
||||
|
||||
/**
|
||||
* The number of live nodes added by this phase.
|
||||
*/
|
||||
int getAddedLiveNodes() {
|
||||
return getEndLiveNodes() - getStartLiveNodes();
|
||||
}
|
||||
|
||||
@ -76,7 +98,7 @@ public class Phase extends BasicLogEvent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(PrintStream stream) {
|
||||
public void print(PrintStream stream, boolean printID) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
* An instance of this class represents an uncommon trap associated with a
|
||||
* given bytecode instruction. An uncommon trap is described in terms of its
|
||||
* reason and action to be taken. An instance of this class is always relative
|
||||
* to a specific method and only contains the relevant bytecode instruction
|
||||
* index.
|
||||
*/
|
||||
class UncommonTrap {
|
||||
|
||||
private int bci;
|
||||
private String reason;
|
||||
private String action;
|
||||
private String bytecode;
|
||||
|
||||
public UncommonTrap(int b, String r, String a, String bc) {
|
||||
bci = b;
|
||||
reason = r;
|
||||
action = a;
|
||||
bytecode = bc;
|
||||
}
|
||||
|
||||
public int getBCI() {
|
||||
return bci;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public String getBytecode() {
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
void emit(PrintStream stream, int indent) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
stream.print(' ');
|
||||
}
|
||||
}
|
||||
|
||||
public void print(PrintStream stream, int indent) {
|
||||
emit(stream, indent);
|
||||
stream.println(this);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "@ " + bci + " " + getBytecode() + " uncommon trap " + getReason() + " " + getAction();
|
||||
}
|
||||
}
|
@ -21,17 +21,33 @@
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.sun.hotspot.tools.compiler;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an uncommon trap encountered during a compilation.
|
||||
*/
|
||||
class UncommonTrapEvent extends BasicLogEvent {
|
||||
|
||||
private final String reason;
|
||||
private final String action;
|
||||
|
||||
/**
|
||||
* Denote how many times this trap has been encountered.
|
||||
*/
|
||||
private int count;
|
||||
private String jvms = "";
|
||||
|
||||
/**
|
||||
* The name of the bytecode instruction at which the trap occurred.
|
||||
*/
|
||||
private String bytecode;
|
||||
|
||||
private List<String> jvmsMethods = new ArrayList<>();
|
||||
|
||||
private List<Integer> jvmsBCIs = new ArrayList<>();
|
||||
|
||||
UncommonTrapEvent(double s, String i, String r, String a, int c) {
|
||||
super(s, i);
|
||||
@ -40,20 +56,26 @@ class UncommonTrapEvent extends BasicLogEvent {
|
||||
count = c;
|
||||
}
|
||||
|
||||
|
||||
public void addJVMS(String method, int bci) {
|
||||
setJvms(getJvms() + " @" + bci + " " + method + "\n");
|
||||
}
|
||||
|
||||
public void updateCount(UncommonTrapEvent trap) {
|
||||
setCount(Math.max(getCount(), trap.getCount()));
|
||||
}
|
||||
|
||||
public void print(PrintStream stream) {
|
||||
stream.printf("%s uncommon trap %.3f %s %s\n", getId(), getStart(), getReason(), getAction());
|
||||
stream.print(getJvms());
|
||||
public void print(PrintStream stream, boolean printID) {
|
||||
if (printID) {
|
||||
stream.print(getId() + " ");
|
||||
}
|
||||
stream.printf("uncommon trap %s %s %s\n", bytecode, getReason(), getAction());
|
||||
int indent = 2;
|
||||
for (int j = 0; j < jvmsMethods.size(); j++) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
stream.print(' ');
|
||||
}
|
||||
stream.println("@ " + jvmsBCIs.get(j) + " " + jvmsMethods.get(j));
|
||||
indent += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
@ -70,15 +92,56 @@ class UncommonTrapEvent extends BasicLogEvent {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public String getJvms() {
|
||||
return jvms;
|
||||
}
|
||||
|
||||
public void setJvms(String jvms) {
|
||||
this.jvms = jvms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the compilation for this event. This involves identifying the call
|
||||
* site to which this uncommon trap event belongs. In addition to setting
|
||||
* the {@link #compilation} link, this method will consequently also set
|
||||
* the {@link #bytecode} field.
|
||||
*/
|
||||
public void setCompilation(Compilation compilation) {
|
||||
this.compilation = compilation;
|
||||
super.setCompilation(compilation);
|
||||
// Attempt to associate a bytecode with with this trap
|
||||
CallSite site = compilation.getCall();
|
||||
int i = 0;
|
||||
try {
|
||||
List<UncommonTrap> traps = site.getTraps();
|
||||
while (i + 1 < jvmsMethods.size()) {
|
||||
if (!jvmsMethods.get(i).equals(site.getMethod().getFullName())) {
|
||||
throw new InternalError(jvmsMethods.get(i) + " != " + site.getMethod().getFullName());
|
||||
}
|
||||
CallSite result = null;
|
||||
for (CallSite call : site.getCalls()) {
|
||||
if (call.getBci() == jvmsBCIs.get(i) &&
|
||||
call.getMethod().getFullName().equals(jvmsMethods.get(i + 1)) &&
|
||||
call.getReceiver() == null) {
|
||||
result = call;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
throw new InternalError("couldn't find call site");
|
||||
}
|
||||
site = result;
|
||||
traps = site.getTraps();
|
||||
}
|
||||
for (UncommonTrap trap : traps) {
|
||||
if (trap.getBCI() == jvmsBCIs.get(i) &&
|
||||
trap.getReason().equals(getReason()) &&
|
||||
trap.getAction().equals(getAction())) {
|
||||
bytecode = trap.getBytecode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new InternalError("couldn't find bytecode");
|
||||
} catch (Exception e) {
|
||||
bytecode = "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
public void addMethodAndBCI(String method, int bci) {
|
||||
jvmsMethods.add(0, method);
|
||||
jvmsBCIs.add(0, bci);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -501,8 +501,8 @@ void CompileTask::log_task(xmlStream* log) {
|
||||
methodHandle method(thread, this->method());
|
||||
ResourceMark rm(thread);
|
||||
|
||||
// <task id='9' method='M' osr_bci='X' level='1' blocking='1' stamp='1.234'>
|
||||
log->print(" compile_id='%d'", _compile_id);
|
||||
// <task compiler='Cx' id='9' method='M' osr_bci='X' level='1' blocking='1' stamp='1.234'>
|
||||
log->print(" compiler='%s' compile_id='%d'", _comp_level <= CompLevel_full_profile ? "C1" : "C2", _compile_id);
|
||||
if (_osr_bci != CompileBroker::standard_entry_bci) {
|
||||
log->print(" compile_kind='osr'"); // same as nmethod::compile_kind
|
||||
} // else compile_kind='c2c'
|
||||
|
Loading…
Reference in New Issue
Block a user