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:
Sharath Ballal 2017-06-02 12:30:49 +05:30 committed by Sharath Ballal
parent a449b10079
commit 536c210f77
5 changed files with 213 additions and 2 deletions
hotspot/src
jdk.hotspot.agent/share/classes/sun/jvm/hotspot
share/vm/runtime

@ -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.
*
* 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 stackBaseField;
private static CIntegerField stackSizeField;
private static CIntegerField terminatedField;
private static JavaThreadPDAccess access;
@ -66,6 +67,9 @@ public class JavaThread extends Thread {
private static int BLOCKED;
private static int BLOCKED_TRANS;
private static int NOT_TERMINATED;
private static int EXITING;
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
@ -87,6 +91,7 @@ public class JavaThread extends Thread {
osThreadField = type.getAddressField("_osthread");
stackBaseField = type.getAddressField("_stack_base");
stackSizeField = type.getCIntegerField("_stack_size");
terminatedField = type.getCIntegerField("_terminated");
UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").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();
BLOCKED = db.lookupIntConstant("_thread_blocked").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) {
@ -128,6 +137,14 @@ public class JavaThread extends Thread {
example, "SolarisSPARCCompilerThread".) */
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; }
/** Get the last Java stack pointer */
@ -329,6 +346,10 @@ public class JavaThread extends Thread {
return stackSizeField.getValue(addr);
}
public int getTerminated() {
return (int) terminatedField.getValue(addr);
}
/** Gets the Java-side thread object for this JavaThread */
public Oop getThreadObj() {
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;
int serialNum = 1;
public HeapHprofBinWriter() {
this.KlassMap = new ArrayList<Klass>();
}
public synchronized void write(String fileName) throws IOException {
// open file stream and create buffered data output stream
fos = new FileOutputStream(fileName);
@ -426,6 +430,9 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
// HPROF_LOAD_CLASS records for all classes
writeClasses();
// write HPROF_FRAME and HPROF_TRACE records
dumpStackTraces();
// write CLASS_DUMP records
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 {
out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ);
writeObjectID(jt.getThreadObj());
@ -1030,6 +1098,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
out.writeInt(serialNum);
writeObjectID(clazz);
KlassMap.add(serialNum - 1, k);
out.writeInt(DUMMY_STACK_TRACE_ID);
writeSymbolID(k.getName());
serialNum++;
@ -1045,6 +1114,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
out.writeInt(serialNum);
writeObjectID(clazz);
KlassMap.add(serialNum - 1, k);
out.writeInt(DUMMY_STACK_TRACE_ID);
writeSymbolID(k.getName());
serialNum++;
@ -1157,6 +1227,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
private Debugger dbg;
private ObjectHeap objectHeap;
private SymbolTable symTbl;
private ArrayList<Klass> KlassMap;
// oopSize of the debuggee
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.
*
* 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, _satb_mark_queue, SATBMarkQueue) \
nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \
volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \
nonstatic_field(Thread, _resource_area, ResourceArea*) \
nonstatic_field(CompilerThread, _env, ciEnv*) \
\
@ -2213,6 +2214,7 @@ typedef RehashableHashtable<Symbol*, mtSymbol> RehashableSymbolHashtable;
declare_toplevel_type(JavaThread*) \
declare_toplevel_type(java_lang_Class) \
declare_integer_type(JavaThread::AsyncRequests) \
declare_integer_type(JavaThread::TerminatedTypes) \
declare_toplevel_type(jbyte*) \
declare_toplevel_type(jbyte**) \
declare_toplevel_type(jint*) \
@ -2435,6 +2437,8 @@ typedef RehashableHashtable<Symbol*, mtSymbol> RehashableSymbolHashtable;
declare_constant(_thread_in_Java_trans) \
declare_constant(_thread_blocked) \
declare_constant(_thread_blocked_trans) \
declare_constant(JavaThread::_not_terminated) \
declare_constant(JavaThread::_thread_exiting) \
\
/******************************/ \
/* Klass misc. enum constants */ \