org.gridkit.jvmtool.stacktrace.StackTraceWriterV2 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sjk-stacktrace Show documentation
Show all versions of sjk-stacktrace Show documentation
Thread dumps: capture and encoding
package org.gridkit.jvmtool.stacktrace;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.Thread.State;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.DeflaterOutputStream;
class StackTraceWriterV2 implements StackTraceWriter {
private DataOutputStream dos;
private Map stringDic = new HashMap();
private Map frameDic = new HashMap();
private RotatingStringDictionary dynDic = new RotatingStringDictionary(512);
private List counterKeys = new ArrayList();
public StackTraceWriterV2(OutputStream os) throws IOException {
os.write(StackTraceCodec.MAGIC2);
DeflaterOutputStream def = new DeflaterOutputStream(os);
this.dos = new DataOutputStream(def);
}
@Override
public void write(ThreadSnapshot snap) throws IOException {
for(StackFrame ste: snap.stackTrace()) {
intern(ste.toStackTraceElement());
}
for(String ckey: snap.counters()) {
ensureCounter(ckey);
}
int threadNameRef = 0;
if (snap.threadName() != null) {
threadNameRef = internDyn(snap.threadName());
}
dos.writeByte(StackTraceCodec.TAG_EVENT);
StackTraceCodec.writeVarLong(dos, snap.threadId());
StackTraceCodec.writeVarInt(dos, threadNameRef);
StackTraceCodec.writeTimestamp(dos, snap.timestamp());
writeState(snap.threadState());
writeCounters(snap.counters());
writeTrace(snap.stackTrace());
}
private void writeCounters(CounterCollection counters) throws IOException {
int n = 0;
while(n < counterKeys.size()) {
byte mask = 0;
for(int i = 0; i < 8; ++i) {
if (n + i >= counterKeys.size()) {
break;
}
long val = counters.getValue(counterKeys.get(i));
if (val >= 0) {
mask |= 1 << i;
}
}
dos.writeByte(mask);
n += 8;
}
for(String key: counterKeys) {
long val = counters.getValue(key);
if (val >= 0) {
StackTraceCodec.writeVarLong(dos, val);
}
}
}
private void writeState(State state) throws IOException {
StackTraceCodec.writeVarInt(dos, state == null ? 0 : (state.ordinal() + 1));
}
private void writeTrace(StackFrameList trace) throws IOException {
int n = 0;
for(@SuppressWarnings("unused") StackFrame sf: trace) {
++n;
}
StackTraceCodec.writeVarInt(dos, n);
for(StackFrame ste: trace) {
StackTraceCodec.writeVarInt(dos, intern(ste.toStackTraceElement()));
}
}
private int intern(StackTraceElement ste) throws IOException {
if (!frameDic.containsKey(ste)) {
String pkg = ste.getClassName();
int c = pkg.lastIndexOf('.');
String cn = c < 0 ? pkg : pkg.substring(c + 1);
pkg = c < 0 ? null : pkg.substring(0, c);
String mtd = ste.getMethodName();
String file = ste.getFileName();
int line = ste.getLineNumber() + 2;
if (line < 0) {
line = 0;
}
int npkg = intern(pkg);
int ncn = intern(cn);
int nmtd = intern(mtd);
int nfile = intern(file);
dos.writeByte(StackTraceCodec.TAG_FRAME);
StackTraceCodec.writeVarInt(dos, npkg);
StackTraceCodec.writeVarInt(dos, ncn);
StackTraceCodec.writeVarInt(dos, nmtd);
StackTraceCodec.writeVarInt(dos, nfile);
StackTraceCodec.writeVarInt(dos, line);
int n = frameDic.size() + 1;
frameDic.put(ste, n);
}
return frameDic.get(ste);
}
private int intern(String str) throws IOException {
if (str == null) {
return 0;
}
if (!stringDic.containsKey(str)) {
dos.write(StackTraceCodec.TAG_STRING);
dos.writeUTF(str);
int n = stringDic.size() + 1;
stringDic.put(str, n);
}
return stringDic.get(str);
}
private int internDyn(String str) throws IOException {
if (str == null) {
return 0;
}
int n = dynDic.intern(str);
if (n < 0) {
n = ~n;
dos.write(StackTraceCodec.TAG_DYN_STRING);
StackTraceCodec.writeVarInt(dos, n + 1);
dos.writeUTF(str);
}
n = n + 1; // leave zero to be null
return n;
}
private void ensureCounter(String key) throws IOException {
int n = counterKeys.indexOf(key);
if (n < 0) {
n = counterKeys.size();
counterKeys.add(key);
dos.write(StackTraceCodec.TAG_COUNTER);
dos.writeUTF(key);
}
}
@Override
public void close() {
try {
dos.close();
} catch (IOException e) {
// ignore
}
stringDic.clear();
frameDic.clear();
}
}