From e1d504f633614a3e9c904b66b9dd7385f6ec03aa Mon Sep 17 00:00:00 2001 From: Haowei Wen Date: Sat, 30 Apr 2022 13:27:54 +0800 Subject: [PATCH] add performance metrics --- .../httpd/DebugApiEndpoint.java | 43 +++++++++++++++++++ .../authlibinjector/httpd/URLProcessor.java | 7 ++- .../transform/ClassTransformer.java | 13 +++++- .../transform/PerformanceMetrics.java | 31 +++++++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/main/java/moe/yushi/authlibinjector/httpd/DebugApiEndpoint.java create mode 100644 src/main/java/moe/yushi/authlibinjector/transform/PerformanceMetrics.java diff --git a/src/main/java/moe/yushi/authlibinjector/httpd/DebugApiEndpoint.java b/src/main/java/moe/yushi/authlibinjector/httpd/DebugApiEndpoint.java new file mode 100644 index 0000000..94515a0 --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/httpd/DebugApiEndpoint.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 Haowei Wen and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package moe.yushi.authlibinjector.httpd; + +import static moe.yushi.authlibinjector.util.IOUtils.CONTENT_TYPE_JSON; +import moe.yushi.authlibinjector.AuthlibInjector; +import moe.yushi.authlibinjector.internal.fi.iki.elonen.IHTTPSession; +import moe.yushi.authlibinjector.internal.fi.iki.elonen.Response; +import moe.yushi.authlibinjector.internal.fi.iki.elonen.Status; +import moe.yushi.authlibinjector.internal.org.json.simple.JSONObject; +import moe.yushi.authlibinjector.transform.PerformanceMetrics; + +/** + * Authlib-injector's debug API + */ +public class DebugApiEndpoint { + + public Response serve(IHTTPSession session) { + if (session.getUri().equals("/debug/metrics") && session.getMethod().equals("GET")) { + PerformanceMetrics metrics = AuthlibInjector.getClassTransformer().performanceMetrics; + JSONObject response = new JSONObject(); + response.put("classesProcessed", metrics.getClassesProcessed()); + response.put("totalTime", metrics.getTotalTime()); + return Response.newFixedLength(Status.OK, CONTENT_TYPE_JSON, response.toJSONString()); + } else { + return Response.newFixedLength(Status.NOT_FOUND, null, null); + } + } +} diff --git a/src/main/java/moe/yushi/authlibinjector/httpd/URLProcessor.java b/src/main/java/moe/yushi/authlibinjector/httpd/URLProcessor.java index e771382..7f5441d 100644 --- a/src/main/java/moe/yushi/authlibinjector/httpd/URLProcessor.java +++ b/src/main/java/moe/yushi/authlibinjector/httpd/URLProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Haowei Wen and contributors + * Copyright (C) 2022 Haowei Wen and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -98,6 +98,7 @@ public class URLProcessor { return redirector.redirect(domain, path); } + private DebugApiEndpoint debugApi = new DebugApiEndpoint(); private volatile NanoHTTPD httpd; private final Object httpdLock = new Object(); @@ -120,6 +121,10 @@ public class URLProcessor { return new NanoHTTPD("127.0.0.1", 0) { @Override public Response serve(IHTTPSession session) { + if (session.getUri().startsWith("/debug/")) { + return debugApi.serve(session); + } + Matcher matcher = LOCAL_URL_REGEX.matcher(session.getUri()); if (matcher.find()) { String protocol = matcher.group("protocol"); diff --git a/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java index c3f494c..040d7f3 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Haowei Wen and contributors + * Copyright (C) 2022 Haowei Wen and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -44,6 +44,7 @@ public class ClassTransformer implements ClassFileTransformer { public final List units = new CopyOnWriteArrayList<>(); public final List listeners = new CopyOnWriteArrayList<>(); public final Set ignores = Collections.newSetFromMap(new ConcurrentHashMap<>()); + public final PerformanceMetrics performanceMetrics = new PerformanceMetrics(); private static class TransformContextImpl implements TransformContext { @@ -168,6 +169,8 @@ public class ClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String internalClassName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (internalClassName != null && classfileBuffer != null) { try { + long t0 = System.nanoTime(); + String className = internalClassName.replace('/', '.'); for (String prefix : ignores) { if (className.startsWith(prefix)) { @@ -184,6 +187,14 @@ public class ClassTransformer implements ClassFileTransformer { if (Config.printUntransformedClass && !transformResult.isPresent()) { log(DEBUG, "No transformation is applied to [" + className + "]"); } + + long t1 = System.nanoTime(); + + synchronized (performanceMetrics) { + performanceMetrics.classesProcessed++; + performanceMetrics.totalTime += t1 - t0; + } + return transformResult.orElse(null); } catch (Throwable e) { log(WARNING, "Failed to transform [" + internalClassName + "]", e); diff --git a/src/main/java/moe/yushi/authlibinjector/transform/PerformanceMetrics.java b/src/main/java/moe/yushi/authlibinjector/transform/PerformanceMetrics.java new file mode 100644 index 0000000..b17bc90 --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/PerformanceMetrics.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 Haowei Wen and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package moe.yushi.authlibinjector.transform; + +public class PerformanceMetrics { + + volatile long totalTime; + volatile long classesProcessed; + + public synchronized long getTotalTime() { + return totalTime; + } + + public synchronized long getClassesProcessed() { + return classesProcessed; + } +}