mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
6760477: Update SA to include stack traces in the heap dump
Update SA to include HPROF_TRACE and HPROF_FRAME records in the heap dump Reviewed-by: dsamersoff
This commit is contained in:
parent
a449b10079
commit
536c210f77
5 changed files with 213 additions and 2 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -50,6 +50,7 @@ public class JavaThread extends Thread {
|
||||||
private static AddressField osThreadField;
|
private static AddressField osThreadField;
|
||||||
private static AddressField stackBaseField;
|
private static AddressField stackBaseField;
|
||||||
private static CIntegerField stackSizeField;
|
private static CIntegerField stackSizeField;
|
||||||
|
private static CIntegerField terminatedField;
|
||||||
|
|
||||||
private static JavaThreadPDAccess access;
|
private static JavaThreadPDAccess access;
|
||||||
|
|
||||||
|
@ -66,6 +67,9 @@ public class JavaThread extends Thread {
|
||||||
private static int BLOCKED;
|
private static int BLOCKED;
|
||||||
private static int BLOCKED_TRANS;
|
private static int BLOCKED_TRANS;
|
||||||
|
|
||||||
|
private static int NOT_TERMINATED;
|
||||||
|
private static int EXITING;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
VM.registerVMInitializedObserver(new Observer() {
|
VM.registerVMInitializedObserver(new Observer() {
|
||||||
public void update(Observable o, Object data) {
|
public void update(Observable o, Object data) {
|
||||||
|
@ -87,6 +91,7 @@ public class JavaThread extends Thread {
|
||||||
osThreadField = type.getAddressField("_osthread");
|
osThreadField = type.getAddressField("_osthread");
|
||||||
stackBaseField = type.getAddressField("_stack_base");
|
stackBaseField = type.getAddressField("_stack_base");
|
||||||
stackSizeField = type.getCIntegerField("_stack_size");
|
stackSizeField = type.getCIntegerField("_stack_size");
|
||||||
|
terminatedField = type.getCIntegerField("_terminated");
|
||||||
|
|
||||||
UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue();
|
UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue();
|
||||||
NEW = db.lookupIntConstant("_thread_new").intValue();
|
NEW = db.lookupIntConstant("_thread_new").intValue();
|
||||||
|
@ -99,6 +104,10 @@ public class JavaThread extends Thread {
|
||||||
IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue();
|
IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue();
|
||||||
BLOCKED = db.lookupIntConstant("_thread_blocked").intValue();
|
BLOCKED = db.lookupIntConstant("_thread_blocked").intValue();
|
||||||
BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue();
|
BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue();
|
||||||
|
|
||||||
|
NOT_TERMINATED = db.lookupIntConstant("JavaThread::_not_terminated").intValue();
|
||||||
|
EXITING = db.lookupIntConstant("JavaThread::_thread_exiting").intValue();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JavaThread(Address addr) {
|
public JavaThread(Address addr) {
|
||||||
|
@ -128,6 +137,14 @@ public class JavaThread extends Thread {
|
||||||
example, "SolarisSPARCCompilerThread".) */
|
example, "SolarisSPARCCompilerThread".) */
|
||||||
public boolean isJavaThread() { return true; }
|
public boolean isJavaThread() { return true; }
|
||||||
|
|
||||||
|
public boolean isExiting () {
|
||||||
|
return (getTerminated() == EXITING) || isTerminated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTerminated() {
|
||||||
|
return (getTerminated() != NOT_TERMINATED) && (getTerminated() != EXITING);
|
||||||
|
}
|
||||||
|
|
||||||
public static AddressField getAnchorField() { return anchorField; }
|
public static AddressField getAnchorField() { return anchorField; }
|
||||||
|
|
||||||
/** Get the last Java stack pointer */
|
/** Get the last Java stack pointer */
|
||||||
|
@ -329,6 +346,10 @@ public class JavaThread extends Thread {
|
||||||
return stackSizeField.getValue(addr);
|
return stackSizeField.getValue(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTerminated() {
|
||||||
|
return (int) terminatedField.getValue(addr);
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the Java-side thread object for this JavaThread */
|
/** Gets the Java-side thread object for this JavaThread */
|
||||||
public Oop getThreadObj() {
|
public Oop getThreadObj() {
|
||||||
Oop obj = null;
|
Oop obj = null;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.jvm.hotspot.runtime;
|
||||||
|
|
||||||
|
import sun.jvm.hotspot.oops.*;
|
||||||
|
|
||||||
|
public class StackFrameInfo {
|
||||||
|
private Method method;
|
||||||
|
int bci;
|
||||||
|
Oop classHolder;
|
||||||
|
|
||||||
|
public StackFrameInfo(JavaVFrame vf) {
|
||||||
|
this.method = vf.getMethod();
|
||||||
|
this.bci = vf.getBCI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Method getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBCI() {
|
||||||
|
return bci;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.jvm.hotspot.runtime;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ThreadStackTrace {
|
||||||
|
private JavaThread thread;
|
||||||
|
private int depth; // number of stack frames added
|
||||||
|
private ArrayList<StackFrameInfo> frames;
|
||||||
|
|
||||||
|
public ThreadStackTrace(JavaThread t) {
|
||||||
|
this.thread = t;
|
||||||
|
this.depth = 0;
|
||||||
|
this.frames = new ArrayList<StackFrameInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStackDepth() {
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StackFrameInfo stackFrameAt(int index) {
|
||||||
|
return frames.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dumpStack(int maxDepth) {
|
||||||
|
if (!thread.isJavaThread()) {
|
||||||
|
System.out.println("dumpStack: not java Thread returning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
|
||||||
|
StackFrameInfo frame = new StackFrameInfo(vf);
|
||||||
|
frames.add(frame);
|
||||||
|
depth++;
|
||||||
|
|
||||||
|
if (maxDepth > 0 && depth == maxDepth) {
|
||||||
|
// Skip frames if more than maxDepth
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Error occurred during stack walking:");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -379,6 +379,10 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
|
||||||
private static final long MAX_U4_VALUE = 0xFFFFFFFFL;
|
private static final long MAX_U4_VALUE = 0xFFFFFFFFL;
|
||||||
int serialNum = 1;
|
int serialNum = 1;
|
||||||
|
|
||||||
|
public HeapHprofBinWriter() {
|
||||||
|
this.KlassMap = new ArrayList<Klass>();
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void write(String fileName) throws IOException {
|
public synchronized void write(String fileName) throws IOException {
|
||||||
// open file stream and create buffered data output stream
|
// open file stream and create buffered data output stream
|
||||||
fos = new FileOutputStream(fileName);
|
fos = new FileOutputStream(fileName);
|
||||||
|
@ -426,6 +430,9 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
|
||||||
// HPROF_LOAD_CLASS records for all classes
|
// HPROF_LOAD_CLASS records for all classes
|
||||||
writeClasses();
|
writeClasses();
|
||||||
|
|
||||||
|
// write HPROF_FRAME and HPROF_TRACE records
|
||||||
|
dumpStackTraces();
|
||||||
|
|
||||||
// write CLASS_DUMP records
|
// write CLASS_DUMP records
|
||||||
writeClassDumpRecords();
|
writeClassDumpRecords();
|
||||||
|
|
||||||
|
@ -700,6 +707,67 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dumpStackTraces() throws IOException {
|
||||||
|
// write a HPROF_TRACE record without any frames to be referenced as object alloc sites
|
||||||
|
writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE );
|
||||||
|
out.writeInt(DUMMY_STACK_TRACE_ID);
|
||||||
|
out.writeInt(0); // thread number
|
||||||
|
out.writeInt(0); // frame count
|
||||||
|
|
||||||
|
int frameSerialNum = 0;
|
||||||
|
int numThreads = 0;
|
||||||
|
Threads threads = VM.getVM().getThreads();
|
||||||
|
|
||||||
|
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||||
|
Oop threadObj = thread.getThreadObj();
|
||||||
|
if (threadObj != null && !thread.isExiting() && !thread.isHiddenFromExternalView()) {
|
||||||
|
|
||||||
|
// dump thread stack trace
|
||||||
|
ThreadStackTrace st = new ThreadStackTrace(thread);
|
||||||
|
st.dumpStack(-1);
|
||||||
|
numThreads++;
|
||||||
|
|
||||||
|
// write HPROF_FRAME records for this thread's stack trace
|
||||||
|
int depth = st.getStackDepth();
|
||||||
|
int threadFrameStart = frameSerialNum;
|
||||||
|
for (int j=0; j < depth; j++) {
|
||||||
|
StackFrameInfo frame = st.stackFrameAt(j);
|
||||||
|
Method m = frame.getMethod();
|
||||||
|
int classSerialNum = KlassMap.indexOf(m.getMethodHolder()) + 1;
|
||||||
|
// the class serial number starts from 1
|
||||||
|
assert classSerialNum > 0:"class not found";
|
||||||
|
dumpStackFrame(++frameSerialNum, classSerialNum, m, frame.getBCI());
|
||||||
|
}
|
||||||
|
|
||||||
|
// write HPROF_TRACE record for one thread
|
||||||
|
writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE + depth * (int)VM.getVM().getOopSize());
|
||||||
|
int stackSerialNum = numThreads + DUMMY_STACK_TRACE_ID;
|
||||||
|
out.writeInt(stackSerialNum); // stack trace serial number
|
||||||
|
out.writeInt(numThreads); // thread serial number
|
||||||
|
out.writeInt(depth); // frame count
|
||||||
|
for (int j=1; j <= depth; j++) {
|
||||||
|
writeObjectID(threadFrameStart + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dumpStackFrame(int frameSN, int classSN, Method m, int bci) throws IOException {
|
||||||
|
int lineNumber;
|
||||||
|
if (m.isNative()) {
|
||||||
|
lineNumber = -3; // native frame
|
||||||
|
} else {
|
||||||
|
lineNumber = m.getLineNumberFromBCI(bci);
|
||||||
|
}
|
||||||
|
writeHeader(HPROF_FRAME, 4 * (int)VM.getVM().getOopSize() + 2 * (int)INT_SIZE);
|
||||||
|
writeObjectID(frameSN); // frame serial number
|
||||||
|
writeSymbolID(m.getName()); // method's name
|
||||||
|
writeSymbolID(m.getSignature()); // method's signature
|
||||||
|
writeSymbolID(m.getMethodHolder().getSourceFileName()); // source file name
|
||||||
|
out.writeInt(classSN); // class serial number
|
||||||
|
out.writeInt(lineNumber); // line number
|
||||||
|
}
|
||||||
|
|
||||||
protected void writeJavaThread(JavaThread jt, int index) throws IOException {
|
protected void writeJavaThread(JavaThread jt, int index) throws IOException {
|
||||||
out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ);
|
out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ);
|
||||||
writeObjectID(jt.getThreadObj());
|
writeObjectID(jt.getThreadObj());
|
||||||
|
@ -1030,6 +1098,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
|
||||||
writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
|
writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
|
||||||
out.writeInt(serialNum);
|
out.writeInt(serialNum);
|
||||||
writeObjectID(clazz);
|
writeObjectID(clazz);
|
||||||
|
KlassMap.add(serialNum - 1, k);
|
||||||
out.writeInt(DUMMY_STACK_TRACE_ID);
|
out.writeInt(DUMMY_STACK_TRACE_ID);
|
||||||
writeSymbolID(k.getName());
|
writeSymbolID(k.getName());
|
||||||
serialNum++;
|
serialNum++;
|
||||||
|
@ -1045,6 +1114,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
|
||||||
writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
|
writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
|
||||||
out.writeInt(serialNum);
|
out.writeInt(serialNum);
|
||||||
writeObjectID(clazz);
|
writeObjectID(clazz);
|
||||||
|
KlassMap.add(serialNum - 1, k);
|
||||||
out.writeInt(DUMMY_STACK_TRACE_ID);
|
out.writeInt(DUMMY_STACK_TRACE_ID);
|
||||||
writeSymbolID(k.getName());
|
writeSymbolID(k.getName());
|
||||||
serialNum++;
|
serialNum++;
|
||||||
|
@ -1157,6 +1227,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
|
||||||
private Debugger dbg;
|
private Debugger dbg;
|
||||||
private ObjectHeap objectHeap;
|
private ObjectHeap objectHeap;
|
||||||
private SymbolTable symTbl;
|
private SymbolTable symTbl;
|
||||||
|
private ArrayList<Klass> KlassMap;
|
||||||
|
|
||||||
// oopSize of the debuggee
|
// oopSize of the debuggee
|
||||||
private int OBJ_ID_SIZE;
|
private int OBJ_ID_SIZE;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -971,6 +971,7 @@ typedef RehashableHashtable<Symbol*, mtSymbol> RehashableSymbolHashtable;
|
||||||
nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \
|
nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \
|
||||||
nonstatic_field(JavaThread, _satb_mark_queue, SATBMarkQueue) \
|
nonstatic_field(JavaThread, _satb_mark_queue, SATBMarkQueue) \
|
||||||
nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \
|
nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \
|
||||||
|
volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \
|
||||||
nonstatic_field(Thread, _resource_area, ResourceArea*) \
|
nonstatic_field(Thread, _resource_area, ResourceArea*) \
|
||||||
nonstatic_field(CompilerThread, _env, ciEnv*) \
|
nonstatic_field(CompilerThread, _env, ciEnv*) \
|
||||||
\
|
\
|
||||||
|
@ -2213,6 +2214,7 @@ typedef RehashableHashtable<Symbol*, mtSymbol> RehashableSymbolHashtable;
|
||||||
declare_toplevel_type(JavaThread*) \
|
declare_toplevel_type(JavaThread*) \
|
||||||
declare_toplevel_type(java_lang_Class) \
|
declare_toplevel_type(java_lang_Class) \
|
||||||
declare_integer_type(JavaThread::AsyncRequests) \
|
declare_integer_type(JavaThread::AsyncRequests) \
|
||||||
|
declare_integer_type(JavaThread::TerminatedTypes) \
|
||||||
declare_toplevel_type(jbyte*) \
|
declare_toplevel_type(jbyte*) \
|
||||||
declare_toplevel_type(jbyte**) \
|
declare_toplevel_type(jbyte**) \
|
||||||
declare_toplevel_type(jint*) \
|
declare_toplevel_type(jint*) \
|
||||||
|
@ -2435,6 +2437,8 @@ typedef RehashableHashtable<Symbol*, mtSymbol> RehashableSymbolHashtable;
|
||||||
declare_constant(_thread_in_Java_trans) \
|
declare_constant(_thread_in_Java_trans) \
|
||||||
declare_constant(_thread_blocked) \
|
declare_constant(_thread_blocked) \
|
||||||
declare_constant(_thread_blocked_trans) \
|
declare_constant(_thread_blocked_trans) \
|
||||||
|
declare_constant(JavaThread::_not_terminated) \
|
||||||
|
declare_constant(JavaThread::_thread_exiting) \
|
||||||
\
|
\
|
||||||
/******************************/ \
|
/******************************/ \
|
||||||
/* Klass misc. enum constants */ \
|
/* Klass misc. enum constants */ \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue