package com.gmail.woodyc40.common.timing;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import javassist.*;
import net.tridentsdk.util.TridentLogger;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.UnmodifiableClassException;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Provides the entry point necessary to provide sampling data
*
* @author Pierre C
*/
public class TimingService {
private static final Map<String, List<TimingMethod>> TIMING_METHODS = Maps.newHashMap();
private final Class<?> def;
private final String clazz;
private TimingService(Class<?> clazz) {
this.def = clazz;
this.clazz = clazz.getName();
}
public static TimingService in(Class<?> c) {
return new TimingService(c);
}
public static TimingService in(String clazz) {
try {
return new TimingService(Class.forName(clazz));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public void sampleMethod(String method) {
String id = new StringBuilder(clazz).append("::").append(method).toString();
String varId = UUID.randomUUID().toString().replaceAll("-", "");
TridentLogger.log("Instrumenting " + id);
try {
final ClassPool pool = ClassPool.getDefault();
pool.appendClassPath(new LoaderClassPath(getClass().getClassLoader()));
final CtClass compiledClass = pool.get(clazz);
final CtMethod me = compiledClass.getDeclaredMethod(method);
me.addLocalVariable("start_" + varId, CtClass.longType);
me.insertBefore("start_" + varId + " = System.nanoTime();");
me.insertAfter("{" +
"final long end_" + varId + " = System.nanoTime();" +
"com.gmail.woodyc40.common.timing.TimerService" +
".putTime(\"" + id + "\", " + "(end_" + varId + " - start_" + varId + "));" +
"}");
Instrument.get().redefineClasses(new ClassDefinition(def, compiledClass.toBytecode()));
} catch (CannotCompileException | NotFoundException | IOException | ClassNotFoundException | UnmodifiableClassException e) {
TridentLogger.error("Failed to write class to sample method " + method + "(...)");
TridentLogger.error(e);
}
}
public static void useMethod(String id, TimingMethod method) {
List<TimingMethod> methods = TIMING_METHODS.get(id);
if (methods == null) {
TIMING_METHODS.put(id, Lists.newArrayList(method));
} else {
methods.add(method);
}
}
public static void putTime(String id, long time) {
List<TimingMethod> methods = TIMING_METHODS.get(id);
if (methods == null) {
TIMING_METHODS.put(id, methods = Lists.newArrayList(new DefaultTimingMethod()));
}
for (TimingMethod method : methods) {
method.submit(time);
}
}
}