fixed bugs, reduced memory overhead
This commit is contained in:
parent
77404d0be6
commit
63b8694eb2
7 changed files with 53 additions and 81 deletions
|
|
@ -4,25 +4,19 @@ package perfix;
|
|||
* contains start and stop time for method/query/servlet
|
||||
*/
|
||||
public class MethodInvocation {
|
||||
private final long t0;
|
||||
private final String name;
|
||||
long t1;
|
||||
private final long timestamp;
|
||||
long duration;
|
||||
|
||||
MethodInvocation(String name) {
|
||||
t0 = System.nanoTime();
|
||||
if (name != null) {
|
||||
this.name = name;
|
||||
} else {
|
||||
this.name = "<error occurred>";
|
||||
}
|
||||
timestamp = System.nanoTime();
|
||||
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
long getDuration() {
|
||||
return t1 - t0;
|
||||
public void registerEndingTime(long t1) {
|
||||
duration = t1 - timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ public class MethodNode {
|
|||
public final String name;
|
||||
public final List<MethodNode> children;
|
||||
public MethodNode parent;
|
||||
public Report report;
|
||||
private MethodInvocation invocation;
|
||||
|
||||
public MethodNode(String name) {
|
||||
this.name = name;
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addChild(MethodNode child){
|
||||
public void addChild(MethodNode child) {
|
||||
children.add(child);
|
||||
}
|
||||
|
||||
|
|
@ -23,10 +23,6 @@ public class MethodNode {
|
|||
return name;
|
||||
}
|
||||
|
||||
public Report getReport() {
|
||||
return report;
|
||||
}
|
||||
|
||||
public List<MethodNode> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
|
@ -51,5 +47,11 @@ public class MethodNode {
|
|||
return Objects.hash(name);
|
||||
}
|
||||
|
||||
public MethodInvocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
|
||||
public void setInvocation(MethodInvocation invocation) {
|
||||
this.invocation = invocation;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,9 @@ import perfix.instrument.Util;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
public class Registry {
|
||||
|
||||
private static final Map<String, List<MethodInvocation>> methods = new ConcurrentHashMap<>();
|
||||
private static final List<MethodNode> callstack = new ArrayList<>();
|
||||
private static final ThreadLocal<MethodNode> currentMethod = new ThreadLocal<>();
|
||||
|
||||
|
|
@ -26,7 +24,7 @@ public class Registry {
|
|||
@SuppressWarnings("unused")
|
||||
public static MethodInvocation start(String name) {
|
||||
MethodInvocation methodInvocation = new MethodInvocation(name);
|
||||
MethodNode newNode = new MethodNode(methodInvocation.getName());
|
||||
MethodNode newNode = new MethodNode(name);
|
||||
|
||||
MethodNode parent = currentMethod.get();
|
||||
if (parent != null) {
|
||||
|
|
@ -52,44 +50,43 @@ public class Registry {
|
|||
@SuppressWarnings("unused")
|
||||
public static void stop(MethodInvocation methodInvocation) {
|
||||
if (methodInvocation != null) {
|
||||
methodInvocation.t1 = System.nanoTime();
|
||||
methods.computeIfAbsent(methodInvocation.getName(), key -> new ArrayList<>()).add(methodInvocation);
|
||||
methodInvocation.registerEndingTime(System.nanoTime());
|
||||
}
|
||||
MethodNode methodNode = currentMethod.get();
|
||||
if (methodNode != null) {
|
||||
methodNode.setInvocation(methodInvocation);
|
||||
|
||||
currentMethod.set(methodNode.parent);
|
||||
}
|
||||
}
|
||||
|
||||
public static SortedMap<Long, Report> sortedMethodsByDuration() {
|
||||
//walk the stack to group methods by their name
|
||||
Map<String, List<MethodInvocation>> methods = new ConcurrentHashMap<>();
|
||||
collectInvocationsPerMethodName(methods, callstack);
|
||||
|
||||
//gather invocations by method name and calculate statistics
|
||||
SortedMap<Long, Report> sortedByTotal = new ConcurrentSkipListMap<>(Comparator.reverseOrder());
|
||||
methods.forEach((name, measurements) -> {
|
||||
LongAdder totalDuration = new LongAdder();
|
||||
measurements.stream()
|
||||
long totalDuration = measurements.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(m -> totalDuration.add(m.getDuration()));
|
||||
sortedByTotal.put(totalDuration.longValue(), new Report(name, measurements.size(), totalDuration.longValue()));
|
||||
.mapToLong(MethodInvocation::getDuration).sum();
|
||||
sortedByTotal.put(totalDuration, new Report(name, measurements.size(), totalDuration));
|
||||
});
|
||||
return sortedByTotal;
|
||||
}
|
||||
|
||||
private static void collectInvocationsPerMethodName(Map<String, List<MethodInvocation>> invocations, List<MethodNode> nodes) {
|
||||
nodes.forEach(methodNode -> {
|
||||
invocations.computeIfAbsent(methodNode.getName(), key -> new ArrayList<>()).add(methodNode.getInvocation());
|
||||
collectInvocationsPerMethodName(invocations, methodNode.children);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static List<MethodNode> getCallStack() {
|
||||
addReport(callstack);
|
||||
return callstack;
|
||||
}
|
||||
|
||||
private static void addReport(List<MethodNode> callstack) {
|
||||
callstack.forEach(methodNode -> {
|
||||
LongAdder totalDuration = new LongAdder();
|
||||
List<MethodInvocation> methodInvocations = methods.get(methodNode.name);
|
||||
methodInvocations.forEach(methodInvocation -> totalDuration.add(methodInvocation.getDuration()));
|
||||
methodNode.report = new Report(methodNode.name, methodInvocations.size(), totalDuration.longValue());
|
||||
addReport(methodNode.children);
|
||||
});
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
methods.clear();
|
||||
callstack.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public class SynthSerializerFactory implements SerializerFactory {
|
|||
/*
|
||||
* Creates the source, handling the for JSON different types of classes
|
||||
*/
|
||||
private <T> String createToJSONStringMethodSource(CtClass beanClass) throws NotFoundException {
|
||||
private String createToJSONStringMethodSource(CtClass beanClass) throws NotFoundException {
|
||||
String source = "public String handle(Object object){\n";
|
||||
if (beanClass.isArray()) {
|
||||
source += "\tObject[] array=(Object[])object;\n";
|
||||
|
|
@ -191,14 +191,10 @@ public class SynthSerializerFactory implements SerializerFactory {
|
|||
}
|
||||
|
||||
private boolean isCollection(CtClass beanClass) throws NotFoundException {
|
||||
List<CtClass> interfaces = new ArrayList<CtClass>(asList(beanClass.getInterfaces()));
|
||||
List<CtClass> interfaces = new ArrayList<>(asList(beanClass.getInterfaces()));
|
||||
interfaces.add(beanClass);
|
||||
for (CtClass interfaze : interfaces) {
|
||||
if (interfaze.getName().equals(COLLECTION) || interfaze.getName().equals(LIST) || interfaze.getName().equals(SET)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
boolean is = interfaces.stream().anyMatch(interfaze -> interfaze.getName().equals(COLLECTION) || interfaze.getName().equals(LIST) || interfaze.getName().equals(SET));
|
||||
return is;
|
||||
}
|
||||
|
||||
private boolean isMap(CtClass beanClass) throws NotFoundException {
|
||||
|
|
@ -212,7 +208,7 @@ public class SynthSerializerFactory implements SerializerFactory {
|
|||
*/
|
||||
private String addPair(CtClass classToSerialize, String source, CtMethod getter) throws NotFoundException {
|
||||
source += jsonKey(getter);
|
||||
source += ": "; // what is the rule when it comes to spaces in json?
|
||||
source += ":";
|
||||
source += jsonValue(classToSerialize, getter);
|
||||
return source;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class App {
|
|||
try {
|
||||
someJdbcStatementMethod();
|
||||
someJdbcPreparedStatementMethod();
|
||||
someOtherMethod();
|
||||
someOtherMethod(0);
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -31,7 +31,7 @@ public class App {
|
|||
|
||||
private static void someJdbcStatementMethod() {
|
||||
try {
|
||||
BasicDataSource dataSource=new BasicDataSource();
|
||||
BasicDataSource dataSource = new BasicDataSource();
|
||||
dataSource.setDriverClassName("org.h2.Driver");
|
||||
dataSource.setUrl("jdbc:h2:mem:default");
|
||||
dataSource.setUsername("sa");
|
||||
|
|
@ -61,11 +61,15 @@ public class App {
|
|||
}
|
||||
}
|
||||
|
||||
private static void someOtherMethod() {
|
||||
private static void someOtherMethod(int level) {
|
||||
try {
|
||||
TimeUnit.NANOSECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (level < 1000) {
|
||||
someOtherMethod(level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,35 +26,15 @@ body {
|
|||
left:-20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.tree li input ~ ul{
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
/*
|
||||
.tree input {
|
||||
background: url(toggle-small-expand.png) no-repeat;
|
||||
height: 1em;
|
||||
|
||||
|
||||
content: "\00a0\00a0\00a0";
|
||||
overflow: hidden;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.tree input:checked{
|
||||
background: url(toggle-small.png) no-repeat;
|
||||
}*/
|
||||
|
||||
.tree li input:checked ~ ul{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* .tree li input:checked { display: block; margin: 0 0 0.125em; 2px} */
|
||||
/* .tree li input:checked li:last-child { margin: 0 0 0.063em; 1px } */
|
||||
|
||||
.tree ul {margin-left:1em} /* (indentation/2) */
|
||||
|
||||
.tree li:before {
|
||||
|
|
|
|||
|
|
@ -24,10 +24,9 @@ class Tree extends Component {
|
|||
return (<ul className="tree">
|
||||
{children.map(
|
||||
r =>
|
||||
<li key={r.report.name}><input type="checkbox" className="tree"></input>
|
||||
{Math.floor(r.report.average / 1000) / 1000} ms
|
||||
- {r.report.invocations} inv.
|
||||
{r.report.name}
|
||||
<li key={r.name}><input type="checkbox" className="tree"/>
|
||||
{Math.floor(r.invocation.duration / 1000) / 1000} ms
|
||||
{r.name}
|
||||
{this.renderChildren(r.children)}
|
||||
</li>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue