switched to telnet interface

This commit is contained in:
Sander Hautvast 2018-04-06 16:31:37 +02:00
parent d87b77edcb
commit bf6ec2acb6
3 changed files with 98 additions and 33 deletions

109
src/main/java/perfix/Agent.java Normal file → Executable file
View file

@ -2,8 +2,13 @@ package perfix;
import javassist.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.instrument.Instrumentation;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -11,33 +16,84 @@ import java.util.List;
public class Agent {
public static void premain(String agentArgs, Instrumentation inst) {
List<String> excludes = determineExcludes();
System.out.println("Perfix agent active");
startListeningOnSocket();
List<String> includes = determineIncludes();
inst.addTransformer((classLoader, resource, aClass, protectionDomain, uninstrumentedByteCode) -> {
if (!shouldExclude(resource, excludes).get()) {
System.out.println("instrumenting "+resource);
if (!isInnerClass(resource) && shouldInclude(resource, includes)) {
// System.out.println("instrumenting " + resource);
try {
return instrumentMethod(resource);
byte[] instrumentedBytecode = instrumentMethod(resource);
if (instrumentedBytecode != null) {
return instrumentedBytecode;
}
} catch (Exception ex) {
ex.printStackTrace(System.err);
//suppress
}
}
return uninstrumentedByteCode;
});
}
private static byte[] instrumentMethod(String resource) throws NotFoundException, IOException, CannotCompileException {
private static void startListeningOnSocket() {
try {
ServerSocket serverSocket = new ServerSocket(2048);
new Thread(() -> {
for (; ; ) {
try {
Socket client = serverSocket.accept();
PrintStream out = new PrintStream(client.getOutputStream());
out.println("press [enter] for report or [q and enter] to quit");
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.equals("q")) {
try {
client.close();
break;
} catch (IOException e) {
e.printStackTrace();
}
} else {
Registry.report(out);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
private static boolean isInnerClass(String resource) {
return resource.contains("$");
}
private static byte[] instrumentMethod(String resource) throws
NotFoundException, IOException, CannotCompileException {
ClassPool cp = ClassPool.getDefault();
CtClass methodClass = cp.get("perfix.Method");
CtClass cc = cp.get(resource.replaceAll("/", "."));
Arrays.stream(cc.getDeclaredMethods()).forEach(m -> {
instrumentMethod(methodClass, m);
});
byte[] byteCode = cc.toBytecode();
cc.detach();
return byteCode;
CtClass classToInstrument = cp.get(resource.replaceAll("/", "."));
if (!classToInstrument.isInterface()) {
Arrays.stream(classToInstrument.getDeclaredMethods()).forEach(m -> {
instrumentMethod(methodClass, m);
});
byte[] byteCode = classToInstrument.toBytecode();
classToInstrument.detach();
return byteCode;
} else {
return null;
}
}
private static void instrumentMethod(CtClass methodClass, CtMethod m) {
@ -46,24 +102,22 @@ public class Agent {
m.insertBefore("perfixmethod = perfix.Method.start(\"" + m.getLongName() + "\");");
m.insertAfter("perfixmethod.stop();");
} catch (CannotCompileException e) {
e.printStackTrace(System.err);
throw new RuntimeException(e);
}
}
private static List<String> determineExcludes() {
List<String> excludes = new ArrayList<>(Arrays.asList(System.getProperty("perfix.excludes").split(",")));
excludes.add("perfix");
return excludes;
private static List<String> determineIncludes() {
return new ArrayList<>(Arrays.asList(System.getProperty("perfix.includes").split(",")));
}
private static BooleanWrapper shouldExclude(String resource, List<String> excludes) {
BooleanWrapper excluded = new BooleanWrapper(false);
excludes.forEach(exclude -> {
if (resource.startsWith(exclude)) {
excluded.set(true);
private static boolean shouldInclude(String resource, List<String> excludes) {
BooleanWrapper included = new BooleanWrapper(false);
excludes.forEach(include -> {
if (resource.startsWith(include)) {
included.set(true);
}
});
return excluded;
return included.get();
}
static class BooleanWrapper {
@ -80,6 +134,11 @@ public class Agent {
boolean get() {
return value;
}
@Override
public String toString() {
return Boolean.toString(value);
}
}
}

0
src/main/java/perfix/Method.java Normal file → Executable file
View file

22
src/main/java/perfix/Registry.java Normal file → Executable file
View file

@ -1,5 +1,6 @@
package perfix;
import java.io.PrintStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
@ -8,26 +9,31 @@ import java.util.concurrent.atomic.LongAdder;
public class Registry {
static final Map<String, List<Method>> methods = new ConcurrentHashMap<>();
private static final double NANO_2_MILLI = 1000000D;
static void add(Method method) {
methods.computeIfAbsent(method.getName(), key -> new ArrayList<>()).add(method);
}
public static void report() {
System.out.println("Invoked methods, by duration desc:");
public static void report(PrintStream out) {
out.println("Invoked methods, by duration desc:");
out.println("Method name;#Invocations;Total duration;Average Duration");
sortedMethodsByDuration().forEach((k, report) -> {
System.out.println("method: " + report.name);
System.out.println("\tInvocations: " + report.invocations);
System.out.println("\tTotal duration: " + report.totalDuration + " nanosecs.");
System.out.println("\tAverage duration " + report.average() + " nanosecs.");
out.println(report.name + ";" + report.invocations + ";" + (long)(report.totalDuration / NANO_2_MILLI) + ";" + (long)(report.average() / NANO_2_MILLI));
});
out.println("----------------------------------------");
}
private static SortedMap<Long, Report> sortedMethodsByDuration() {
SortedMap<Long, Report> sortedByTotal = new ConcurrentSkipListMap<>(Comparator.reverseOrder());
methods.forEach((name, measurements) -> {
long totalDuration = measurements.stream().mapToLong(Method::getDuration).sum();
sortedByTotal.put(totalDuration, new Report(name, measurements.size(), totalDuration));
// long totalDuration = measurements.stream().mapToLong(Method::getDuration).sum();
LongAdder totalDuration = new LongAdder();
measurements.stream()
.filter(Objects::nonNull)
.forEach(m -> totalDuration.add(m.getDuration()));
sortedByTotal.put(totalDuration.longValue(), new Report(name, measurements.size(), totalDuration.longValue()));
});
return sortedByTotal;
}