diff options
5 files changed, 79 insertions, 5 deletions
diff --git a/common/src/main/java/me/lucko/spark/common/CommandHandler.java b/common/src/main/java/me/lucko/spark/common/CommandHandler.java index 7e7bc50..6664c18 100644 --- a/common/src/main/java/me/lucko/spark/common/CommandHandler.java +++ b/common/src/main/java/me/lucko/spark/common/CommandHandler.java @@ -9,6 +9,7 @@ import me.lucko.spark.common.http.Bytebin; import me.lucko.spark.profiler.Sampler; import me.lucko.spark.profiler.SamplerBuilder; import me.lucko.spark.profiler.ThreadDumper; +import me.lucko.spark.profiler.ThreadGrouper; import java.io.IOException; import java.util.ArrayList; @@ -92,6 +93,7 @@ public abstract class CommandHandler<T> { sendMessage(sender, "&b&l> &7/profiler start"); sendMessage(sender, " &8[&7--timeout&8 <timeout seconds>]"); sendMessage(sender, " &8[&7--thread&8 <thread name>]"); + sendMessage(sender, " &8[&7--not-combined]"); sendMessage(sender, " &8[&7--interval&8 <interval millis>]"); sendMessage(sender, "&b&l> &7/profiler info"); sendMessage(sender, "&b&l> &7/profiler stop"); @@ -122,11 +124,18 @@ public abstract class CommandHandler<T> { // use the server thread threadDumper = getDefaultThreadDumper(); } else if (threads.contains("*")) { - threadDumper = new ThreadDumper.All(); + threadDumper = ThreadDumper.ALL; } else { threadDumper = new ThreadDumper.Specific(threads); } + ThreadGrouper threadGrouper; + if (arguments.containsKey("not-combined")) { + threadGrouper = ThreadGrouper.BY_NAME; + } else { + threadGrouper = ThreadGrouper.BY_POOL; + } + Sampler sampler; synchronized (this.activeSamplerMutex) { if (this.activeSampler != null) { @@ -138,6 +147,7 @@ public abstract class CommandHandler<T> { SamplerBuilder builder = new SamplerBuilder(); builder.threadDumper(threadDumper); + builder.threadGrouper(threadGrouper); if (timeoutSeconds != -1) { builder.completeAfter(timeoutSeconds, TimeUnit.SECONDS); } diff --git a/common/src/main/java/me/lucko/spark/profiler/Sampler.java b/common/src/main/java/me/lucko/spark/profiler/Sampler.java index 9696c03..d03b4b6 100644 --- a/common/src/main/java/me/lucko/spark/profiler/Sampler.java +++ b/common/src/main/java/me/lucko/spark/profiler/Sampler.java @@ -61,14 +61,17 @@ public class Sampler extends TimerTask { private final int interval; /** The instance used to generate thread information for use in sampling */ private final ThreadDumper threadDumper; + /** The instance used to group threads together */ + private final ThreadGrouper threadGrouper; /** The time when sampling first began */ private long startTime = -1; /** The unix timestamp (in millis) when this sampler should automatically complete.*/ private final long endTime; // -1 for nothing - public Sampler(int interval, ThreadDumper threadDumper, long endTime) { + public Sampler(int interval, ThreadDumper threadDumper, ThreadGrouper threadGrouper, long endTime) { this.interval = interval; this.threadDumper = threadDumper; + this.threadGrouper = threadGrouper; this.endTime = endTime; } @@ -84,7 +87,8 @@ public class Sampler extends TimerTask { private void insertData(QueuedThreadInfo data) { try { - StackNode node = this.threadData.computeIfAbsent(data.threadName, StackNode::new); + String group = this.threadGrouper.getGroup(data.threadName); + StackNode node = this.threadData.computeIfAbsent(group, StackNode::new); node.log(data.stack, Sampler.this.interval); } catch (Exception e) { e.printStackTrace(); diff --git a/common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java b/common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java index 8e79b33..fa2898b 100644 --- a/common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java +++ b/common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java @@ -12,7 +12,8 @@ public class SamplerBuilder { private int samplingInterval = 10; private long timeout = -1; - private ThreadDumper threadDumper = new ThreadDumper.All(); + private ThreadDumper threadDumper = ThreadDumper.ALL; + private ThreadGrouper threadGrouper = ThreadGrouper.BY_NAME; public SamplerBuilder() { } @@ -33,8 +34,13 @@ public class SamplerBuilder { return this; } + public SamplerBuilder threadGrouper(ThreadGrouper threadGrouper) { + this.threadGrouper = threadGrouper; + return this; + } + public Sampler start(Timer samplingThread) { - Sampler sampler = new Sampler(this.samplingInterval, this.threadDumper, this.timeout); + Sampler sampler = new Sampler(this.samplingInterval, this.threadDumper, this.threadGrouper, this.timeout); sampler.start(samplingThread); return sampler; } diff --git a/common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java b/common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java index 9c2e974..68d7dc9 100644 --- a/common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java +++ b/common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java @@ -41,6 +41,8 @@ public interface ThreadDumper { /** * Implementation of {@link ThreadDumper} that generates data for all threads. */ + ThreadDumper ALL = new All(); + final class All implements ThreadDumper { @Override public ThreadInfo[] dumpThreads(ThreadMXBean threadBean) { diff --git a/common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java b/common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java new file mode 100644 index 0000000..56a6cc4 --- /dev/null +++ b/common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java @@ -0,0 +1,52 @@ +package me.lucko.spark.profiler; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Function for grouping threads together + */ +@FunctionalInterface +public interface ThreadGrouper { + + /** + * Gets the group for the given thread. + * + * @param threadName the name of the thread + * @return the group + */ + String getGroup(String threadName); + + /** + * Implementation of {@link ThreadGrouper} that just groups by thread name. + */ + ThreadGrouper BY_NAME = new ByName(); + + final class ByName implements ThreadGrouper { + @Override + public String getGroup(String threadName) { + return threadName; + } + } + + /** + * Implementation of {@link ThreadGrouper} that attempts to group by the name of the pool + * the thread originated from. + */ + ThreadGrouper BY_POOL = new ByPool(); + + final class ByPool implements ThreadGrouper { + private static final Pattern THREAD_POOL_PATTERN = Pattern.compile("^(.*)[-#] ?\\d+$"); + + @Override + public String getGroup(String threadName) { + Matcher matcher = THREAD_POOL_PATTERN.matcher(threadName); + if (!matcher.matches()) { + return threadName; + } + + return matcher.group(1).trim() + " (Combined)"; + } + } + +} |