aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/src/main/java/me/lucko/spark/common/CommandHandler.java12
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/Sampler.java8
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java10
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java2
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java52
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)";
+ }
+ }
+
+}