aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuck <git@lucko.me>2019-02-21 13:06:10 +0000
committerLuck <git@lucko.me>2019-02-21 13:06:10 +0000
commit161d3bdfbfe331a1ea3c6da1d096e86fd7a5c525 (patch)
tree96be6a24e9bd45198e4d5620eff57bba1e0a94cb
parent77c93aeeea763c68a4fd7f5b59afcfc2f6336379 (diff)
downloadspark-161d3bdfbfe331a1ea3c6da1d096e86fd7a5c525.tar.gz
spark-161d3bdfbfe331a1ea3c6da1d096e86fd7a5c525.tar.bz2
spark-161d3bdfbfe331a1ea3c6da1d096e86fd7a5c525.zip
Allow sampling at fractions of a millisecond intervals
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/Arguments.java12
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java2
-rw-r--r--spark-common/src/main/java/me/lucko/spark/sampler/Sampler.java5
-rw-r--r--spark-common/src/main/java/me/lucko/spark/sampler/SamplerBuilder.java10
-rw-r--r--spark-common/src/main/java/me/lucko/spark/sampler/aggregator/SimpleDataAggregator.java2
-rw-r--r--spark-common/src/main/java/me/lucko/spark/sampler/aggregator/TickedDataAggregator.java15
-rw-r--r--spark-common/src/main/java/me/lucko/spark/sampler/node/AbstractNode.java16
7 files changed, 44 insertions, 18 deletions
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/Arguments.java b/spark-common/src/main/java/me/lucko/spark/common/command/Arguments.java
index d240554..2b202af 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/Arguments.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/Arguments.java
@@ -89,6 +89,18 @@ public class Arguments {
return -1; // undefined
}
+ public double doubleFlag(String key) {
+ Iterator<String> it = this.parsedArgs.get(key).iterator();
+ if (it.hasNext()) {
+ try {
+ return Math.abs(Double.parseDouble(it.next()));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid input for '" + key + "' argument. Please specify a number!");
+ }
+ }
+ return -1; // undefined
+ }
+
public Set<String> stringFlag(String key) {
return this.parsedArgs.get(key);
}
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java
index 6ebbee1..9d00a96 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java
@@ -73,7 +73,7 @@ public class SamplerModule<S> implements CommandModule<S> {
platform.sendPrefixedMessage(sender, "&7The accuracy of the output will significantly improve when sampling is able to run for longer periods. Consider setting a timeout value over 30 seconds.");
}
- int intervalMillis = arguments.intFlag("interval");
+ double intervalMillis = arguments.doubleFlag("interval");
if (intervalMillis <= 0) {
intervalMillis = 4;
}
diff --git a/spark-common/src/main/java/me/lucko/spark/sampler/Sampler.java b/spark-common/src/main/java/me/lucko/spark/sampler/Sampler.java
index 3a9a271..2e8ac65 100644
--- a/spark-common/src/main/java/me/lucko/spark/sampler/Sampler.java
+++ b/spark-common/src/main/java/me/lucko/spark/sampler/Sampler.java
@@ -23,6 +23,7 @@ package me.lucko.spark.sampler;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.stream.JsonWriter;
+
import me.lucko.spark.sampler.aggregator.DataAggregator;
import me.lucko.spark.sampler.aggregator.SimpleDataAggregator;
import me.lucko.spark.sampler.aggregator.TickedDataAggregator;
@@ -71,7 +72,7 @@ public class Sampler implements Runnable {
/** 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 */
+ /** The interval to wait between sampling, in microseconds */
private final int interval;
/** The time when sampling first began */
private long startTime = -1;
@@ -98,7 +99,7 @@ public class Sampler implements Runnable {
public void start() {
this.startTime = System.currentTimeMillis();
this.dataAggregator.start();
- this.task = this.workerPool.scheduleAtFixedRate(this, 0, this.interval, TimeUnit.MILLISECONDS);
+ this.task = this.workerPool.scheduleAtFixedRate(this, 0, this.interval, TimeUnit.MICROSECONDS);
}
public long getStartTime() {
diff --git a/spark-common/src/main/java/me/lucko/spark/sampler/SamplerBuilder.java b/spark-common/src/main/java/me/lucko/spark/sampler/SamplerBuilder.java
index 07449ec..bf9dc04 100644
--- a/spark-common/src/main/java/me/lucko/spark/sampler/SamplerBuilder.java
+++ b/spark-common/src/main/java/me/lucko/spark/sampler/SamplerBuilder.java
@@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit;
*/
public class SamplerBuilder {
- private int samplingInterval = 4;
+ private double samplingInterval = 4; // milliseconds
private boolean includeLineNumbers = false;
private long timeout = -1;
private ThreadDumper threadDumper = ThreadDumper.ALL;
@@ -39,7 +39,7 @@ public class SamplerBuilder {
public SamplerBuilder() {
}
- public SamplerBuilder samplingInterval(int samplingInterval) {
+ public SamplerBuilder samplingInterval(double samplingInterval) {
this.samplingInterval = samplingInterval;
return this;
}
@@ -75,10 +75,12 @@ public class SamplerBuilder {
public Sampler start() {
Sampler sampler;
+
+ int intervalMicros = (int) (this.samplingInterval * 1000d);
if (this.ticksOver != -1 && this.tickCounter != null) {
- sampler = new Sampler(this.samplingInterval, this.threadDumper, this.threadGrouper, this.timeout, this.includeLineNumbers, this.tickCounter, this.ticksOver);
+ sampler = new Sampler(intervalMicros, this.threadDumper, this.threadGrouper, this.timeout, this.includeLineNumbers, this.tickCounter, this.ticksOver);
} else {
- sampler = new Sampler(this.samplingInterval, this.threadDumper, this.threadGrouper, this.timeout, this.includeLineNumbers);
+ sampler = new Sampler(intervalMicros, this.threadDumper, this.threadGrouper, this.timeout, this.includeLineNumbers);
}
sampler.start();
diff --git a/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/SimpleDataAggregator.java b/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/SimpleDataAggregator.java
index 25e2071..a72b47f 100644
--- a/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/SimpleDataAggregator.java
+++ b/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/SimpleDataAggregator.java
@@ -43,7 +43,7 @@ public class SimpleDataAggregator implements DataAggregator {
/** The instance used to group threads together */
private final ThreadGrouper threadGrouper;
- /** The interval to wait between sampling, in milliseconds */
+ /** The interval to wait between sampling, in microseconds */
private final int interval;
/** If line numbers should be included in the output */
diff --git a/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/TickedDataAggregator.java b/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/TickedDataAggregator.java
index 2c68b02..ef568c8 100644
--- a/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/TickedDataAggregator.java
+++ b/spark-common/src/main/java/me/lucko/spark/sampler/aggregator/TickedDataAggregator.java
@@ -50,14 +50,14 @@ public class TickedDataAggregator implements DataAggregator {
/** The instance used to group threads together */
private final ThreadGrouper threadGrouper;
- /** The interval to wait between sampling, in milliseconds */
+ /** The interval to wait between sampling, in microseconds */
private final int interval;
/** If line numbers should be included in the output */
private final boolean includeLineNumbers;
- /** Tick durations under this threshold will not be inserted */
- private final int tickLengthThreshold;
+ /** Tick durations under this threshold will not be inserted, measured in microseconds */
+ private final long tickLengthThreshold;
/** The expected number of samples in each tick */
private final int expectedSize;
@@ -74,9 +74,10 @@ public class TickedDataAggregator implements DataAggregator {
this.threadGrouper = threadGrouper;
this.interval = interval;
this.includeLineNumbers = includeLineNumbers;
- this.tickLengthThreshold = tickLengthThreshold;
+ this.tickLengthThreshold = TimeUnit.MILLISECONDS.toMicros(tickLengthThreshold);
// 50 millis in a tick, plus 10 so we have a bit of room to go over
- this.expectedSize = (50 / interval) + 10;
+ double intervalMilliseconds = interval / 1000d;
+ this.expectedSize = (int) ((50 / intervalMilliseconds) + 10);
}
@Override
@@ -101,10 +102,10 @@ public class TickedDataAggregator implements DataAggregator {
TickList currentData = this.currentData;
// approximate how long the tick lasted
- int tickLengthMillis = currentData.getList().size() * this.interval;
+ int tickLengthMicros = currentData.getList().size() * this.interval;
// don't push data below the threshold
- if (tickLengthMillis < this.tickLengthThreshold) {
+ if (tickLengthMicros < this.tickLengthThreshold) {
return;
}
diff --git a/spark-common/src/main/java/me/lucko/spark/sampler/node/AbstractNode.java b/spark-common/src/main/java/me/lucko/spark/sampler/node/AbstractNode.java
index 75632c4..859014f 100644
--- a/spark-common/src/main/java/me/lucko/spark/sampler/node/AbstractNode.java
+++ b/spark-common/src/main/java/me/lucko/spark/sampler/node/AbstractNode.java
@@ -30,6 +30,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
/**
@@ -45,12 +46,21 @@ public abstract class AbstractNode {
private final Map<String, StackTraceNode> children = new ConcurrentHashMap<>();
/**
- * The accumulated sample time for this node
+ * The accumulated sample time for this node, measured in microseconds
*/
private final LongAdder totalTime = new LongAdder();
-
+
+ /**
+ * Returns the total sample time for this node in milliseconds.
+ *
+ * @return the total time
+ */
public long getTotalTime() {
- return this.totalTime.longValue();
+ long millis = TimeUnit.MICROSECONDS.toMillis(this.totalTime.longValue());
+ if (millis == 0) {
+ return 1;
+ }
+ return millis;
}
private AbstractNode resolveChild(String className, String methodName, int lineNumber) {