aboutsummaryrefslogtreecommitdiff
path: root/common/src/main/java/me/lucko/spark/profiler
diff options
context:
space:
mode:
authorLuck <git@lucko.me>2018-06-06 15:39:16 +0100
committerLuck <git@lucko.me>2018-06-06 15:39:16 +0100
commit7d6808cbcfbb0f61f93e536d36968eeda5bd302c (patch)
tree3271db1ffa6e4d6c1fa5ea4ccc1335b1ac746f46 /common/src/main/java/me/lucko/spark/profiler
parent38f0c12483e6eda79ca36dc829ef678a736d2cef (diff)
downloadspark-7d6808cbcfbb0f61f93e536d36968eeda5bd302c.tar.gz
spark-7d6808cbcfbb0f61f93e536d36968eeda5bd302c.tar.bz2
spark-7d6808cbcfbb0f61f93e536d36968eeda5bd302c.zip
Convert to Gradle
Diffstat (limited to 'common/src/main/java/me/lucko/spark/profiler')
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/AsyncDataAggregator.java77
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/DataAggregator.java32
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/Sampler.java170
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java63
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/StackNode.java141
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/StackTraceNode.java71
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java77
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java52
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/TickCounter.java39
-rw-r--r--common/src/main/java/me/lucko/spark/profiler/TickedDataAggregator.java147
10 files changed, 0 insertions, 869 deletions
diff --git a/common/src/main/java/me/lucko/spark/profiler/AsyncDataAggregator.java b/common/src/main/java/me/lucko/spark/profiler/AsyncDataAggregator.java
deleted file mode 100644
index 9a4090e..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/AsyncDataAggregator.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package me.lucko.spark.profiler;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Implementation of {@link DataAggregator} that makes use of a "worker" thread pool for inserting
- * data.
- */
-public class AsyncDataAggregator implements DataAggregator {
-
- /** A map of root stack nodes for each thread with sampling data */
- private final Map<String, StackNode> threadData = new ConcurrentHashMap<>();
-
- /** The worker pool for inserting stack nodes */
- private final ExecutorService workerPool;
-
- /** The instance used to group threads together */
- private final ThreadGrouper threadGrouper;
-
- /** The interval to wait between sampling, in milliseconds */
- private final int interval;
-
- public AsyncDataAggregator(ExecutorService workerPool, ThreadGrouper threadGrouper, int interval) {
- this.workerPool = workerPool;
- this.threadGrouper = threadGrouper;
- this.interval = interval;
- }
-
- @Override
- public void insertData(String threadName, StackTraceElement[] stack) {
- // form the queued data
- QueuedThreadInfo queuedData = new QueuedThreadInfo(threadName, stack);
- // schedule insertion of the data
- this.workerPool.execute(queuedData);
- }
-
- @Override
- public Map<String, StackNode> getData() {
- // wait for all pending data to be inserted
- this.workerPool.shutdown();
- try {
- this.workerPool.awaitTermination(15, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- return this.threadData;
- }
-
- void insertData(QueuedThreadInfo data) {
- try {
- String group = this.threadGrouper.getGroup(data.threadName);
- StackNode node = this.threadData.computeIfAbsent(group, StackNode::new);
- node.log(data.stack, this.interval);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private final class QueuedThreadInfo implements Runnable {
- private final String threadName;
- private final StackTraceElement[] stack;
-
- QueuedThreadInfo(String threadName, StackTraceElement[] stack) {
- this.threadName = threadName;
- this.stack = stack;
- }
-
- @Override
- public void run() {
- insertData(this);
- }
- }
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/DataAggregator.java b/common/src/main/java/me/lucko/spark/profiler/DataAggregator.java
deleted file mode 100644
index 1afa52c..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/DataAggregator.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package me.lucko.spark.profiler;
-
-import java.util.Map;
-
-/**
- * Aggregates sampling data.
- */
-public interface DataAggregator {
-
- /**
- * Called before the sampler begins to insert data
- */
- default void start() {
-
- }
-
- /**
- * Forms the output data
- *
- * @return the output data
- */
- Map<String, StackNode> getData();
-
- /**
- * Inserts sampling data into this aggregator
- *
- * @param threadName the name of the thread
- * @param stack the call stack
- */
- void insertData(String threadName, StackTraceElement[] stack);
-
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/Sampler.java b/common/src/main/java/me/lucko/spark/profiler/Sampler.java
deleted file mode 100644
index 3476f03..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/Sampler.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * WarmRoast
- * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package me.lucko.spark.profiler;
-
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.google.gson.stream.JsonWriter;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.lang.management.ManagementFactory;
-import java.lang.management.ThreadInfo;
-import java.lang.management.ThreadMXBean;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.zip.GZIPOutputStream;
-
-/**
- * Main sampler class.
- */
-public class Sampler extends TimerTask {
- private static final AtomicInteger THREAD_ID = new AtomicInteger(0);
-
- /** The worker pool for inserting stack nodes */
- private final ExecutorService workerPool = Executors.newFixedThreadPool(
- 6, new ThreadFactoryBuilder().setNameFormat("spark-worker-" + THREAD_ID.getAndIncrement()).build()
- );
-
- /** The thread management interface for the current JVM */
- private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
- /** The instance used to generate thread information for use in sampling */
- private final ThreadDumper threadDumper;
- /** Responsible for aggregating and then outputting collected sampling data */
- private final DataAggregator dataAggregator;
-
- /** A future to encapsulation the completion of this sampler instance */
- private final CompletableFuture<Sampler> future = new CompletableFuture<>();
-
- /** The interval to wait between sampling, in milliseconds */
- private final int interval;
- /** 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, ThreadGrouper threadGrouper, long endTime) {
- this.threadDumper = threadDumper;
- this.dataAggregator = new AsyncDataAggregator(this.workerPool, threadGrouper, interval);
- this.interval = interval;
- this.endTime = endTime;
- }
-
- public Sampler(int interval, ThreadDumper threadDumper, ThreadGrouper threadGrouper, long endTime, TickCounter tickCounter, int tickLengthThreshold) {
- this.threadDumper = threadDumper;
- this.dataAggregator = new TickedDataAggregator(this.workerPool, tickCounter, threadGrouper, interval, tickLengthThreshold);
- this.interval = interval;
- this.endTime = endTime;
- }
-
- /**
- * Starts the sampler.
- *
- * @param samplingThread the timer to schedule the sampling on
- */
- public void start(Timer samplingThread) {
- this.startTime = System.currentTimeMillis();
- this.dataAggregator.start();
- samplingThread.scheduleAtFixedRate(this, 0, this.interval);
- }
-
- public long getStartTime() {
- if (this.startTime == -1) {
- throw new IllegalStateException("Not yet started");
- }
- return this.startTime;
- }
-
- public long getEndTime() {
- return this.endTime;
- }
-
- public CompletableFuture<Sampler> getFuture() {
- return this.future;
- }
-
- @Override
- public void run() {
- try {
- if (this.endTime != -1 && this.endTime <= System.currentTimeMillis()) {
- this.future.complete(this);
- cancel();
- return;
- }
-
- ThreadInfo[] threadDumps = this.threadDumper.dumpThreads(this.threadBean);
- for (ThreadInfo threadInfo : threadDumps) {
- String threadName = threadInfo.getThreadName();
- StackTraceElement[] stack = threadInfo.getStackTrace();
-
- if (threadName == null || stack == null) {
- continue;
- }
-
- this.dataAggregator.insertData(threadName, stack);
- }
- } catch (Throwable t) {
- this.future.completeExceptionally(t);
- cancel();
- }
- }
-
- private void writeOutput(JsonWriter writer) throws IOException {
- writer.beginObject();
-
- writer.name("threads").beginArray();
-
- List<Map.Entry<String, StackNode>> data = new ArrayList<>(this.dataAggregator.getData().entrySet());
- data.sort(Map.Entry.comparingByKey());
-
- for (Map.Entry<String, StackNode> entry : data) {
- writer.beginObject();
- writer.name("threadName").value(entry.getKey());
- writer.name("totalTime").value(entry.getValue().getTotalTime());
- writer.name("rootNode");
- entry.getValue().serializeTo(writer);
- writer.endObject();
- }
-
- writer.endArray();
- writer.endObject();
- }
-
- public byte[] formCompressedDataPayload() {
- ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
- try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(byteOut), StandardCharsets.UTF_8)) {
- try (JsonWriter jsonWriter = new JsonWriter(writer)) {
- writeOutput(jsonWriter);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return byteOut.toByteArray();
- }
-
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java b/common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java
deleted file mode 100644
index 7db0515..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/SamplerBuilder.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package me.lucko.spark.profiler;
-
-import java.util.Timer;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Builds {@link Sampler} instances.
- */
-public class SamplerBuilder {
-
- private int samplingInterval = 4;
- private long timeout = -1;
- private ThreadDumper threadDumper = ThreadDumper.ALL;
- private ThreadGrouper threadGrouper = ThreadGrouper.BY_NAME;
-
- private int ticksOver = -1;
- private TickCounter tickCounter = null;
-
- public SamplerBuilder() {
- }
-
- public SamplerBuilder samplingInterval(int samplingInterval) {
- this.samplingInterval = samplingInterval;
- return this;
- }
-
- public SamplerBuilder completeAfter(long timeout, TimeUnit unit) {
- if (timeout <= 0) {
- throw new IllegalArgumentException("timeout > 0");
- }
- this.timeout = System.currentTimeMillis() + unit.toMillis(timeout);
- return this;
- }
-
- public SamplerBuilder threadDumper(ThreadDumper threadDumper) {
- this.threadDumper = threadDumper;
- return this;
- }
-
- public SamplerBuilder threadGrouper(ThreadGrouper threadGrouper) {
- this.threadGrouper = threadGrouper;
- return this;
- }
-
- public SamplerBuilder ticksOver(int ticksOver, TickCounter tickCounter) {
- this.ticksOver = ticksOver;
- this.tickCounter = tickCounter;
- return this;
- }
-
- public Sampler start(Timer samplingThread) {
- Sampler sampler;
- if (this.ticksOver != -1 && this.tickCounter != null) {
- sampler = new Sampler(this.samplingInterval, this.threadDumper, this.threadGrouper, this.timeout, this.tickCounter, this.ticksOver);
- } else {
- 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/StackNode.java b/common/src/main/java/me/lucko/spark/profiler/StackNode.java
deleted file mode 100644
index 575400a..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/StackNode.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * WarmRoast
- * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package me.lucko.spark.profiler;
-
-import com.google.gson.stream.JsonWriter;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.LongAdder;
-
-/**
- * Represents a node in the overall sampling stack.
- *
- * <p>The base implementation of this class is only used for the root of node structures. The
- * {@link StackTraceNode} class is used for representing method calls in the structure.</p>
- */
-public class StackNode implements Comparable<StackNode> {
-
- private static final int MAX_STACK_DEPTH = 300;
-
- /**
- * The name of this node
- */
- private final String name;
-
- /**
- * A map of this nodes children
- */
- private final Map<String, StackNode> children = new ConcurrentHashMap<>();
-
- /**
- * The accumulated sample time for this node
- */
- private final LongAdder totalTime = new LongAdder();
-
- public StackNode(String name) {
- this.name = name;
- }
-
- public String getName() {
- return this.name;
- }
-
- public Collection<StackNode> getChildren() {
- if (this.children.isEmpty()) {
- return Collections.emptyList();
- }
-
- List<StackNode> list = new ArrayList<>(this.children.values());
- list.sort(null);
- return list;
- }
-
- private StackNode resolveChild(String name) {
- return this.children.computeIfAbsent(name, StackNode::new);
- }
-
- private StackNode resolveChild(String className, String methodName) {
- return this.children.computeIfAbsent(StackTraceNode.formName(className, methodName), name -> new StackTraceNode(className, methodName));
- }
-
- public long getTotalTime() {
- return this.totalTime.longValue();
- }
-
- public void accumulateTime(long time) {
- this.totalTime.add(time);
- }
-
- private void log(StackTraceElement[] elements, int skip, long time) {
- accumulateTime(time);
-
- if (skip >= MAX_STACK_DEPTH) {
- return;
- }
-
- if (elements.length - skip == 0) {
- return;
- }
-
- StackTraceElement bottom = elements[elements.length - (skip + 1)];
- resolveChild(bottom.getClassName(), bottom.getMethodName()).log(elements, skip + 1, time);
- }
-
- public void log(StackTraceElement[] elements, long time) {
- log(elements, 0, time);
- }
-
- @Override
- public int compareTo(StackNode o) {
- return getName().compareTo(o.getName());
- }
-
- public void serializeTo(JsonWriter writer) throws IOException {
- writer.beginObject();
-
- // append metadata about this node
- appendMetadata(writer);
-
- // include the total time recorded for this node
- writer.name("totalTime").value(getTotalTime());
-
- // append child nodes, if any are present
- Collection<StackNode> childNodes = getChildren();
- if (!childNodes.isEmpty()) {
- writer.name("children").beginArray();
- for (StackNode child : childNodes) {
- child.serializeTo(writer);
- }
- writer.endArray();
- }
-
- writer.endObject();
- }
-
- protected void appendMetadata(JsonWriter writer) throws IOException {
- writer.name("name").value(getName());
- }
-
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/StackTraceNode.java b/common/src/main/java/me/lucko/spark/profiler/StackTraceNode.java
deleted file mode 100644
index d46a547..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/StackTraceNode.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * WarmRoast
- * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package me.lucko.spark.profiler;
-
-import com.google.gson.stream.JsonWriter;
-
-import java.io.IOException;
-
-/**
- * Represents a {@link StackNode node} for a method call.
- */
-public class StackTraceNode extends StackNode {
-
- /**
- * Forms the {@link StackNode#getName()} for a {@link StackTraceNode}.
- *
- * @param className the name of the class
- * @param methodName the name of the method
- * @return the name
- */
- static String formName(String className, String methodName) {
- return className + "." + methodName + "()";
- }
-
- /** The name of the class */
- private final String className;
- /** The name of the method */
- private final String methodName;
-
- public StackTraceNode(String className, String methodName) {
- super(formName(className, methodName));
- this.className = className;
- this.methodName = methodName;
- }
-
- public String getClassName() {
- return this.className;
- }
-
- public String getMethodName() {
- return this.methodName;
- }
-
- @Override
- protected void appendMetadata(JsonWriter writer) throws IOException {
- writer.name("className").value(this.className);
- writer.name("methodName").value(this.methodName);
- }
-
- @Override
- public int compareTo(StackNode that) {
- return Long.compare(that.getTotalTime(), this.getTotalTime());
- }
-
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java b/common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java
deleted file mode 100644
index 68d7dc9..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/ThreadDumper.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * WarmRoast
- * Copyright (C) 2013 Albert Pham <http://www.sk89q.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package me.lucko.spark.profiler;
-
-import java.lang.management.ThreadInfo;
-import java.lang.management.ThreadMXBean;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Uses the {@link ThreadMXBean} to generate {@link ThreadInfo} instances for the threads being
- * sampled.
- */
-@FunctionalInterface
-public interface ThreadDumper {
-
- /**
- * Generates {@link ThreadInfo} data for the sampled threads.
- *
- * @param threadBean the thread bean instance to obtain the data from
- * @return an array of generated thread info instances
- */
- ThreadInfo[] dumpThreads(ThreadMXBean threadBean);
-
- /**
- * 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) {
- return threadBean.dumpAllThreads(false, false);
- }
- }
-
- /**
- * Implementation of {@link ThreadDumper} that generates data for a specific set of threads.
- */
- final class Specific implements ThreadDumper {
- private final long[] ids;
-
- public Specific(long[] ids) {
- this.ids = ids;
- }
-
- public Specific(Set<String> names) {
- Set<String> threadNamesLower = names.stream().map(String::toLowerCase).collect(Collectors.toSet());
- this.ids = Thread.getAllStackTraces().keySet().stream()
- .filter(t -> threadNamesLower.contains(t.getName().toLowerCase()))
- .mapToLong(Thread::getId)
- .toArray();
- }
-
- @Override
- public ThreadInfo[] dumpThreads(ThreadMXBean threadBean) {
- return threadBean.getThreadInfo(this.ids, Integer.MAX_VALUE);
- }
- }
-
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java b/common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java
deleted file mode 100644
index 56a6cc4..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/ThreadGrouper.java
+++ /dev/null
@@ -1,52 +0,0 @@
-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)";
- }
- }
-
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/TickCounter.java b/common/src/main/java/me/lucko/spark/profiler/TickCounter.java
deleted file mode 100644
index 53a9c27..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/TickCounter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package me.lucko.spark.profiler;
-
-/**
- * A hook with the game's "tick loop".
- */
-public interface TickCounter {
-
- /**
- * Starts the counter
- */
- void start();
-
- /**
- * Stops the counter
- */
- void close();
-
- /**
- * Gets the current tick number
- *
- * @return the current tick
- */
- long getCurrentTick();
-
- /**
- * Adds a task to be called each time the tick increments
- *
- * @param runnable the task
- */
- void addTickTask(Runnable runnable);
-
- /**
- * Removes a tick task
- *
- * @param runnable the task
- */
- void removeTickTask(Runnable runnable);
-
-}
diff --git a/common/src/main/java/me/lucko/spark/profiler/TickedDataAggregator.java b/common/src/main/java/me/lucko/spark/profiler/TickedDataAggregator.java
deleted file mode 100644
index abca4b3..0000000
--- a/common/src/main/java/me/lucko/spark/profiler/TickedDataAggregator.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package me.lucko.spark.profiler;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Implementation of {@link DataAggregator} which supports only including sampling data from "ticks"
- * which exceed a certain threshold in duration.
- */
-public class TickedDataAggregator implements DataAggregator {
-
- /** A map of root stack nodes for each thread with sampling data */
- private final Map<String, StackNode> threadData = new ConcurrentHashMap<>();
-
- /** The worker pool for inserting stack nodes */
- private final ExecutorService workerPool;
-
- /** Used to monitor the current "tick" of the server */
- private final TickCounter tickCounter;
-
- /** The instance used to group threads together */
- private final ThreadGrouper threadGrouper;
-
- /** The interval to wait between sampling, in milliseconds */
- private final int interval;
-
- /** Tick durations under this threshold will not be inserted */
- private final int tickLengthThreshold;
-
- /** The expected number of samples in each tick */
- private final int expectedSize;
-
- // state
- private long currentTick = -1;
- private TickList currentData = new TickList(0);
-
- public TickedDataAggregator(ExecutorService workerPool, TickCounter tickCounter, ThreadGrouper threadGrouper, int interval, int tickLengthThreshold) {
- this.workerPool = workerPool;
- this.tickCounter = tickCounter;
- this.threadGrouper = threadGrouper;
- this.interval = interval;
- this.tickLengthThreshold = tickLengthThreshold;
- // 50 millis in a tick, plus 10 so we have a bit of room to go over
- this.expectedSize = (50 / interval) + 10;
- }
-
- // this is effectively synchronized by the Timer instance in Sampler
- @Override
- public void insertData(String threadName, StackTraceElement[] stack) {
- long tick = this.tickCounter.getCurrentTick();
- if (this.currentTick != tick) {
- pushCurrentTick();
- this.currentTick = tick;
- this.currentData = new TickList(this.expectedSize);
- }
-
- // form the queued data
- QueuedThreadInfo queuedData = new QueuedThreadInfo(threadName, stack);
- // insert it
- this.currentData.addData(queuedData);
- }
-
- private void pushCurrentTick() {
- TickList currentData = this.currentData;
-
- // approximate how long the tick lasted
- int tickLengthMillis = currentData.getList().size() * this.interval;
-
- // don't push data below the threshold
- if (tickLengthMillis < this.tickLengthThreshold) {
- return;
- }
-
- this.workerPool.submit(currentData);
- }
-
- @Override
- public void start() {
- this.tickCounter.start();
- }
-
- @Override
- public Map<String, StackNode> getData() {
- // push the current tick
- pushCurrentTick();
-
- // close the tick counter
- this.tickCounter.close();
-
- // wait for all pending data to be inserted
- this.workerPool.shutdown();
- try {
- this.workerPool.awaitTermination(15, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- return this.threadData;
- }
-
- void insertData(List<QueuedThreadInfo> dataList) {
- for (QueuedThreadInfo data : dataList) {
- try {
- String group = this.threadGrouper.getGroup(data.threadName);
- StackNode node = this.threadData.computeIfAbsent(group, StackNode::new);
- node.log(data.stack, this.interval);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- private final class TickList implements Runnable {
- private final List<QueuedThreadInfo> list;
-
- TickList(int expectedSize) {
- this.list = new ArrayList<>(expectedSize);
- }
-
- @Override
- public void run() {
- insertData(this.list);
- }
-
- public List<QueuedThreadInfo> getList() {
- return this.list;
- }
-
- public void addData(QueuedThreadInfo data) {
- this.list.add(data);
- }
- }
-
- private static final class QueuedThreadInfo {
- private final String threadName;
- private final StackTraceElement[] stack;
-
- QueuedThreadInfo(String threadName, StackTraceElement[] stack) {
- this.threadName = threadName;
- this.stack = stack;
- }
- }
-}