Я хочу измерить время запуска сервера без значительных накладных расходов.
На самом деле я хочу измерить время от выполнения серверного процесса до момента, когда сервер начинает прослушивать известный порт.
Например, я хочу измерить время запуска простого Netty Server. то есть время от запуска до момента, когда он готов принимать запросы.
Я разработал агент Java, используя Byte-Buddy.
public class Agent {
public static void premain(String arg, Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.named("io.netty.bootstrap.AbstractBootstrap"))
.transform((builder, typeDescription, classLoader, javaModule) ->
builder.visit(Advice.to(TimeAdvice.class)
.on(ElementMatchers.named("bind").and(ElementMatchers.takesArguments(SocketAddress.class)))))
.installOn(instrumentation);
}
}
Ниже приведен исходный код TimeAdvice.
public class TimeAdvice {
@Advice.OnMethodExit
static void exit(@Advice.Origin String method) {
System.out.println(String.format("Server started. Current Time (ms): %d", System.currentTimeMillis()));
System.out.println(String.format("Server started. Current Uptime (ms): %d",
ManagementFactory.getRuntimeMXBean().getUptime()));
}
}
С этим агентом время запуска составляет около 1400 мс. Однако, когда я измеряю время запуска, изменяя код сервера, время запуска сервера составляет около 650 мс.
Таким образом, кажется, что есть значительные накладные расходы при использовании агента Java с помощником по байтам при рассмотрении времени запуска.
Я также попробовал другой Java-агент с Javassist.
public class Agent {
private static final String NETTY_CLASS = "io/netty/bootstrap/AbstractBootstrap";
public static void premain(String arg, Instrumentation instrumentation) {
instrumentation.addTransformer((classLoader, s, aClass, protectionDomain, bytes) -> {
if (NETTY_CLASS.equals(s)) {
System.out.println(aClass);
long start = System.nanoTime();
// Javassist
try {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("io.netty.bootstrap.AbstractBootstrap");
CtMethod m = cc.getDeclaredMethod("bind", new CtClass[]{cp.get("java.net.SocketAddress")});
m.insertAfter("{ System.out.println(\"Server started. Current Uptime (ms): \" + " +
"java.lang.management.ManagementFactory.getRuntimeMXBean().getUptime());}");
byte[] byteCode = cc.toBytecode();
cc.detach();
return byteCode;
} catch (Exception ex) {
ex.printStackTrace();
} finally {
System.out.println(String.format("Agent - Transformation Time (ms): %d", TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)));
}
}
return null;
});
}
}
С этим агентом время запуска составляет около 800 мс.
Как минимизировать накладные расходы и измерить время запуска? Есть ли способ напрямую преобразовать конкретный класс, не проходя через все классы? Если я могу преобразовать класс напрямую, я думаю, что смогу максимально минимизировать накладные расходы.