From cf76202775195301192bffad1f6223071558b1b2 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Wed, 30 Mar 2022 18:06:52 +0200 Subject: [PATCH] Improve performance + Flatten recursion --- src/main/java/de/steamwar/Sampler.java | 44 ++++++++++++++++---------- src/main/java/de/steamwar/Trace.java | 28 ++++++---------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/main/java/de/steamwar/Sampler.java b/src/main/java/de/steamwar/Sampler.java index bdf2116..a39b8cc 100644 --- a/src/main/java/de/steamwar/Sampler.java +++ b/src/main/java/de/steamwar/Sampler.java @@ -14,12 +14,15 @@ public class Sampler { private static final Set waitingMethods = new HashSet<>(); static { - waitingMethods.add("io.netty.channel.epoll.Native.epollWait"); - waitingMethods.add("org.jline.utils.NonBlockingInputStream.read"); - waitingMethods.add("org.bukkit.craftbukkit.libs.jline.internal.NonBlockingInputStream.read"); - waitingMethods.add("org.bukkit.craftbukkit.v1_15_R1.util.TerminalConsoleWriterThread.run"); - waitingMethods.add("sun.nio.ch.SocketDispatcher.read0"); - waitingMethods.add("openj9.internal.tools.attach.target.IPC.waitSemaphore"); + waitingMethods.add("io.netty.channel.epoll.Native.epollWait:-2"); + waitingMethods.add("io.netty.channel.epoll.Native.epollWait0:-2"); + //waitingMethods.add("org.jline.utils.NonBlockingInputStream.read"); + waitingMethods.add("org.bukkit.craftbukkit.libs.jline.internal.NonBlockingInputStream.read:248"); + //waitingMethods.add("org.bukkit.craftbukkit.v1_15_R1.util.TerminalConsoleWriterThread.run"); + waitingMethods.add("net.minecraft.terminalconsole.SimpleTerminalConsole.readCommands:180"); + waitingMethods.add("sun.nio.ch.SocketDispatcher.read0:-2"); + waitingMethods.add("openj9.internal.tools.attach.target.IPC.waitSemaphore:-2"); + waitingMethods.add("sun.nio.ch.Net.poll:-2"); } private static final List omittedMethods = new ArrayList<>(); @@ -91,30 +94,39 @@ public class Sampler { sampleRuns++; Map stackTraces = Thread.getAllStackTraces(); - List filteredStack = new LinkedList<>(); + Set previousIds = new HashSet<>(); for(Map.Entry entry : stackTraces.entrySet()) { Thread thread = entry.getKey(); StackTraceElement[] stack = entry.getValue(); - if(stack.length == 0 || thread.getName().equals("Sampler")) + String threadName = thread.getName(); + if(stack.length == 0 || threadName.equals("Sampler")) continue; + previousIds.clear(); + Thread.State state = thread.getState(); - filteredStack.clear(); - for(StackTraceElement ste : stack) { - String id = ste.getClassName() + "." + ste.getMethodName(); + String[] ids = new String[stack.length]; + for(int i = 0; i < stack.length; i++) { + StackTraceElement ste = stack[i]; + String id = ste.getClassName() + "." + ste.getMethodName() + ":" + ste.getLineNumber(); + ids[i] = id; + if (waitingMethods.contains(id)) state = Thread.State.WAITING; - if(omittedMethods.stream().noneMatch(id::startsWith)) - filteredStack.add(0, ste); } - Trace predecessor = traces.computeIfAbsent(thread.getName(), name -> new Trace(this, thread)); + Trace predecessor = traces.computeIfAbsent(threadName, name -> new Trace(this, threadName)); predecessor.add(state, null); - for(StackTraceElement ste : filteredStack) { - Trace trace = traces.computeIfAbsent(ste.getClassName() + "." + ste.getMethodName() + ":" + ste.getLineNumber(), id -> new Trace(this, ste)); + for(int i = stack.length - 1; i >= 0; i--) { + String id = ids[i]; + + if(!previousIds.add(id) || omittedMethods.stream().anyMatch(id::startsWith)) + continue; + + Trace trace = traces.computeIfAbsent(id, id1 -> new Trace(this, id1)); trace.add(state, predecessor); predecessor = trace; } diff --git a/src/main/java/de/steamwar/Trace.java b/src/main/java/de/steamwar/Trace.java index bc16ab1..f3335c9 100644 --- a/src/main/java/de/steamwar/Trace.java +++ b/src/main/java/de/steamwar/Trace.java @@ -3,7 +3,7 @@ package de.steamwar; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.DecimalFormat; -import java.util.EnumMap; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -16,19 +16,9 @@ public class Trace { private final int id; private final String name; - private final Map samples = new EnumMap<>(Thread.State.class); + private final int[] samples = new int[6]; private final Map predecessors = new HashMap<>(); - public Trace(Sampler sampler, StackTraceElement ste) { - this.sampler = sampler; - id = idCounter++; - name = ste.getClassName() + "." + ste.getMethodName() + ":" + ste.getLineNumber(); - } - - public Trace(Sampler sampler, Thread thread) { - this(sampler, thread.getName()); - } - public Trace(Sampler sampler, String name) { this.sampler = sampler; id = idCounter++; @@ -36,15 +26,15 @@ public class Trace { } private int ownSampleRuns() { - return samples.values().stream().mapToInt(i -> i).sum(); + return Arrays.stream(samples).sum(); } private boolean filtered() { - return (samples.getOrDefault(Thread.State.RUNNABLE, 0) + samples.getOrDefault(Thread.State.BLOCKED, 0)) / (double) sampler.getSampleRuns() < Sampler.FILTER; + return (samples[1] + samples[2]) / (double) sampler.getSampleRuns() < Sampler.FILTER; } public void add(Thread.State state, Trace predecessor) { - samples.compute(state, (s, sample) -> sample == null ? 1 : sample + 1); + samples[state.ordinal()] += 1; if (predecessor != null) predecessors.compute(predecessor, (pre, sample) -> sample == null ? 1 : sample + 1); } @@ -57,9 +47,9 @@ public class Trace { if (filtered()) return; - int waiting = samples.getOrDefault(Thread.State.WAITING, 0) + samples.getOrDefault(Thread.State.TIMED_WAITING, 0) + samples.getOrDefault(Thread.State.TERMINATED, 0); - int runnable = samples.getOrDefault(Thread.State.RUNNABLE, 0) + samples.getOrDefault(Thread.State.NEW, 0); - int blocked = samples.getOrDefault(Thread.State.BLOCKED, 0); + int waiting = samples[3] + samples[4] + samples[5]; + int runnable = samples[1] + samples[0]; + int blocked = samples[2]; int total = waiting + runnable + blocked; int r = (255 * blocked + 192 * waiting) / total; @@ -75,7 +65,7 @@ public class Trace { if (entry.getKey().filtered() || entry.getValue() / (double)sampler.getSampleRuns() < Sampler.FILTER) continue; - writer.append(String.valueOf(entry.getKey().id)).append(" -> ").append(String.valueOf(id)).append(" [label=\"").append(percentage(entry.getValue())).append("%\"];\n"); + writer.append(String.valueOf(entry.getKey().id)).append(" -> ").append(String.valueOf(id)).append(" [label=\"").append(percentage(entry.getValue())).append("%\",weight=").append(String.valueOf(entry.getValue())).append("];\n"); } } }