org.gridkit.jvmtool.hflame.ThreadStateInferer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sjk-hflame Show documentation
Show all versions of sjk-hflame Show documentation
HTML based flame graph visualizer
package org.gridkit.jvmtool.hflame;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.gridkit.jvmtool.stacktrace.GenericStackElement;
import org.gridkit.jvmtool.stacktrace.ThreadSnapshot;
import org.gridkit.jvmtool.stacktrace.analytics.BasicFilterFactory;
import org.gridkit.jvmtool.stacktrace.analytics.ThreadSnapshotFilter;
import org.gridkit.jvmtool.stacktrace.analytics.TraceFilterPredicateParser;
public class ThreadStateInferer implements TraceMapper {
public static final GenericTerminatingStackElement UNKNOWN = new GenericTerminatingStackElement("UNKNOWN");
private static final List PROPS = Arrays.asList("name", "rule", "prop");
public static ThreadStateInferer loadFromResource(String source) {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(source);
if (is == null) {
throw new IllegalArgumentException("Unable to load resource: [source]");
}
Reader rdr = new InputStreamReader(is, Charset.forName("UTF8"));
try {
return new ThreadStateInferer(new BasicFilterFactory(), rdr);
} catch (IOException e) {
throw new IllegalArgumentException("Unable to parse resource: [source]", e);
}
}
private List rules = new ArrayList();
private Map states = new HashMap();
public ThreadStateInferer(BasicFilterFactory filterFactory, Reader reader) throws IOException {
new Loader(filterFactory).load(reader);
for(PseudoState ps: states.values()) {
if (ps.caption == null) {
ps.caption = ps.id;
}
ps.element = new GenericTerminatingStackElement(ps.caption, ps.props);
}
}
@Override
public GenericStackElement generateTraceTerminator(ThreadSnapshot snap) {
for(Rule rule: rules) {
if (rule.filter.evaluate(snap)) {
return rule.state.element;
}
}
return UNKNOWN;
}
@SuppressWarnings("serial")
private class Loader extends Properties {
private final BasicFilterFactory filterFactory;
public Loader(BasicFilterFactory filterFactory) {
this.filterFactory = filterFactory;
}
@Override
public synchronized Object put(Object key, Object value) {
String k = (String) key;
String v = (String) value;
String[] split = k.split("[.]");
if (split.length < 2) {
throw invalidStatement(k, v);
}
String id = split[0];
String prop = split[1];
if (!PROPS.contains(prop)) {
throw invalidStatement(k, v);
}
PseudoState state = states.get(id);
if (state == null) {
states.put(id, state = new PseudoState(id));
}
if (prop.equals("name")) {
if (split.length > 2) {
throw invalidStatement(k, v);
}
state.caption = v;
}
else if (prop.equals("prop")) {
if (split.length < 3) {
throw invalidStatement(k, v);
}
StringBuilder sb = new StringBuilder();
for(int i = 2; i < split.length; ++i) {
if (sb.length() > 0) {
sb.append('.');
}
sb.append(split[i]);
}
state.props.put(sb.toString(), v);
}
else if (prop.equals("rule")) {
ThreadSnapshotFilter filter = TraceFilterPredicateParser.parseFilter(v, filterFactory);
Rule rule = new Rule();
rule.filter = filter;
rule.state = state;
rules.add(rule);
}
return super.put(key, value);
}
private IllegalArgumentException invalidStatement(String k, String v) {
throw new IllegalArgumentException("Invalid statement - " + k + ": " + v);
}
}
private static class Rule {
ThreadSnapshotFilter filter;
PseudoState state;
}
private static class PseudoState {
String id;
String caption;
GenericTerminatingStackElement element;
Map props = new HashMap();
public PseudoState(String id) {
this.id = id;
}
}
}