task generateProfilerSource {
def agentSrcDir = file("$buildDir/profiler-src/comet/agent")
doFirst {
agentSrcDir.mkdirs()
def javaFile = new File(agentSrcDir, "ProfilerAgent.java")
javaFile.text = """
package comet.agent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.bind.annotation.*;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.LongAdder;
import java.text.SimpleDateFormat;
public class ProfilerAgent {
public static final ConcurrentHashMap<String, Stats> metrics = new ConcurrentHashMap<>();
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void premain(String agentArgs, Instrumentation inst) {
String[] parts = (agentArgs != null) ? agentArgs.split(";") : new String[0];
String configPath = parts.length > 0 ? parts[0] : "profiler_targets.txt";
int interval = parts.length > 1 ? Integer.parseInt(parts[1]) : 60;
String outputDir = parts.length > 2 ? parts[2] : ".";
List<String> targetClasses = loadClasses(configPath);
startReporter(interval, outputDir);
AgentBuilder agentBuilder = new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION);
for (String className : targetClasses) {
agentBuilder = agentBuilder
.type(ElementMatchers.named(className.trim()))
.transform((builder, td, cl, m) ->
builder.method(ElementMatchers.any()
.and(ElementMatchers.not(ElementMatchers.isAbstract()))
.and(ElementMatchers.not(ElementMatchers.isNative())))
.intercept(MethodDelegation.to(Interceptor.class))
);
}
agentBuilder.installOn(inst);
}
private static List<String> loadClasses(String path) {
try { return Files.readAllLines(Paths.get(path)); }
catch (Exception e) { return Collections.emptyList(); }
}
public static class Interceptor {
@RuntimeType
public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable) throws Exception {
long start = System.nanoTime();
try { return callable.call(); }
finally {
long duration = System.nanoTime() - start;
String key = method.getDeclaringClass().getSimpleName() + "." + method.getName();
metrics.computeIfAbsent(key, k -> new Stats()).record(duration);
}
}
}
public static class Stats {
public final LongAdder count = new LongAdder();
public final LongAdder totalTime = new LongAdder();
public void record(long nanos) {
count.increment();
totalTime.add(nanos);
}
}
private static void startReporter(int seconds, final String outputDir) {
File csvFile = new File(outputDir, "profiler_combined_report.csv");
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
String timestamp = sdf.format(new Date());
boolean writeHeader = !csvFile.exists() || csvFile.length() == 0;
try (PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(csvFile, true)))) {
if (writeHeader) {
pw.println("Timestamp,Method,Calls,Avg_MS,Total_MS");
}
metrics.forEach((k, v) -> {
long c = v.count.sumThenReset();
long t = v.totalTime.sumThenReset();
if (c > 0) {
pw.printf("%s,%s,%d,%.4f,%.2f%n", timestamp, k, c, (t / (double)c) / 1e6, t / 1e6);
}
});
pw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}, seconds, seconds, TimeUnit.SECONDS);
}
}
"""
}
}
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)