aboutsummaryrefslogtreecommitdiff
path: root/spark-common/src/main/java/me/lucko
diff options
context:
space:
mode:
Diffstat (limited to 'spark-common/src/main/java/me/lucko')
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java2
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java5
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java130
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java4
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java7
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/monitor/cpu/CpuMonitor.java102
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java63
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/util/RollingAverage.java53
8 files changed, 264 insertions, 102 deletions
diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
index dd55157..e99cb05 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
@@ -32,6 +32,7 @@ import me.lucko.spark.common.command.modules.SamplerModule;
import me.lucko.spark.common.command.modules.TickMonitoringModule;
import me.lucko.spark.common.command.tabcomplete.CompletionSupplier;
import me.lucko.spark.common.command.tabcomplete.TabCompleter;
+import me.lucko.spark.common.monitor.cpu.CpuMonitor;
import me.lucko.spark.common.monitor.tick.TpsCalculator;
import me.lucko.spark.common.sampler.TickCounter;
import me.lucko.spark.common.util.BytebinClient;
@@ -95,6 +96,7 @@ public class SparkPlatform {
this.tickCounter.addTickTask(this.tpsCalculator);
this.tickCounter.start();
}
+ CpuMonitor.ensureMonitoring();
}
public void disable() {
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java
index c51fe2c..edb8537 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java
@@ -68,10 +68,7 @@ public class ActivityLogModule implements CommandModule {
.build()
);
- TextComponent.Builder valueComponent = TextComponent.builder(activity.getDataValue())
- .color(TextColor.WHITE)
- .decoration(TextDecoration.UNDERLINED, true);
-
+ TextComponent.Builder valueComponent = TextComponent.builder(activity.getDataValue(), TextColor.WHITE);
if (activity.getDataType().equals("url")) {
valueComponent.clickEvent(ClickEvent.openUrl(activity.getDataValue()));
}
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java
index f2ae6fc..9c139eb 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java
@@ -54,7 +54,14 @@ public class HealthModule implements CommandModule {
TpsCalculator tpsCalculator = platform.getTpsCalculator();
if (tpsCalculator != null) {
resp.replyPrefixed(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:"));
- resp.replyPrefixed(TextComponent.builder(" ").append(tpsCalculator.toFormattedComponent()).build());
+ resp.replyPrefixed(TextComponent.builder(" ")
+ .append(formatTps(tpsCalculator.avg5Sec())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg10Sec())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg1Min())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg5Min())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg15Min()))
+ .build()
+ );
} else {
resp.replyPrefixed(TextComponent.of("Not supported!"));
}
@@ -64,6 +71,29 @@ public class HealthModule implements CommandModule {
);
consumer.accept(Command.builder()
+ .aliases("cpu")
+ .executor((platform, sender, resp, arguments) -> {
+ resp.replyPrefixed(TextComponent.of("CPU usage from last 10s, 1m, 15m:"));
+ resp.replyPrefixed(TextComponent.builder(" ")
+ .append(formatCpuUsage(CpuMonitor.systemLoad10SecAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.systemLoad1MinAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.systemLoad15MinAvg()))
+ .append(TextComponent.of(" (system)", TextColor.DARK_GRAY))
+ .build()
+ );
+ resp.replyPrefixed(TextComponent.builder(" ")
+ .append(formatCpuUsage(CpuMonitor.processLoad10SecAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.processLoad1MinAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.processLoad15MinAvg()))
+ .append(TextComponent.of(" (process)", TextColor.DARK_GRAY))
+ .build()
+ );
+ })
+ .tabCompleter(Command.TabCompleter.empty())
+ .build()
+ );
+
+ consumer.accept(Command.builder()
.aliases("healthreport", "health", "ht")
.argumentUsage("memory", null)
.executor((platform, sender, resp, arguments) -> {
@@ -80,10 +110,39 @@ public class HealthModule implements CommandModule {
.append(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:", TextColor.GOLD))
.build()
);
- report.add(TextComponent.builder(" ").append(tpsCalculator.toFormattedComponent()).build());
+ report.add(TextComponent.builder(" ")
+ .append(formatTps(tpsCalculator.avg5Sec())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg10Sec())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg1Min())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg5Min())).append(TextComponent.of(", "))
+ .append(formatTps(tpsCalculator.avg15Min()))
+ .build()
+ );
report.add(TextComponent.empty());
}
+ report.add(TextComponent.builder("")
+ .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
+ .append(TextComponent.space())
+ .append(TextComponent.of("CPU usage from last 10s, 1m, 15m:", TextColor.GOLD))
+ .build()
+ );
+ report.add(TextComponent.builder(" ")
+ .append(formatCpuUsage(CpuMonitor.systemLoad10SecAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.systemLoad1MinAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.systemLoad15MinAvg()))
+ .append(TextComponent.of(" (system)", TextColor.DARK_GRAY))
+ .build()
+ );
+ report.add(TextComponent.builder(" ")
+ .append(formatCpuUsage(CpuMonitor.processLoad10SecAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.processLoad1MinAvg())).append(TextComponent.of(", "))
+ .append(formatCpuUsage(CpuMonitor.processLoad15MinAvg()))
+ .append(TextComponent.of(" (process)", TextColor.DARK_GRAY))
+ .build()
+ );
+ report.add(TextComponent.empty());
+
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();
report.add(TextComponent.builder("")
@@ -168,37 +227,6 @@ public class HealthModule implements CommandModule {
}
}
- double systemCpuLoad = CpuMonitor.getSystemCpuLoad();
- double processCpuLoad = CpuMonitor.getProcessCpuLoad();
-
- if (systemCpuLoad >= 0 || processCpuLoad >= 0) {
- report.add(TextComponent.builder("")
- .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
- .append(TextComponent.space())
- .append(TextComponent.of("CPU usage:", TextColor.GOLD))
- .build()
- );
-
- if (systemCpuLoad >= 0) {
- report.add(TextComponent.builder(" ")
- .append(TextComponent.of("System: ", TextColor.GRAY))
- .append(TextComponent.of(percent(systemCpuLoad, 1.0d), TextColor.GREEN))
- .build()
- );
- report.add(TextComponent.builder(" ").append(generateCpuUsageDiagram(systemCpuLoad, 40)).build());
- report.add(TextComponent.empty());
- }
- if (processCpuLoad >= 0) {
- report.add(TextComponent.builder(" ")
- .append(TextComponent.of("Process: ", TextColor.GRAY))
- .append(TextComponent.of(percent(processCpuLoad, 1.0d), TextColor.GREEN))
- .build()
- );
- report.add(TextComponent.builder(" ").append(generateCpuUsageDiagram(processCpuLoad, 40)).build());
- report.add(TextComponent.empty());
- }
- }
-
try {
FileStore fileStore = Files.getFileStore(Paths.get("."));
long totalSpace = fileStore.getTotalSpace();
@@ -242,6 +270,32 @@ public class HealthModule implements CommandModule {
return (int) percent + "%";
}
+ private static TextComponent formatTps(double tps) {
+ TextColor color;
+ if (tps > 18.0) {
+ color = TextColor.GREEN;
+ } else if (tps > 16.0) {
+ color = TextColor.YELLOW;
+ } else {
+ color = TextColor.RED;
+ }
+
+ return TextComponent.of( (tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color);
+ }
+
+ private static TextComponent formatCpuUsage(double usage) {
+ TextColor color;
+ if (usage > 0.9) {
+ color = TextColor.RED;
+ } else if (usage > 0.65) {
+ color = TextColor.YELLOW;
+ } else {
+ color = TextColor.GREEN;
+ }
+
+ return TextComponent.of(percent(usage, 1d), color);
+ }
+
private static TextComponent generateMemoryUsageDiagram(MemoryUsage usage, int length) {
double used = usage.getUsed();
double committed = usage.getCommitted();
@@ -300,16 +354,6 @@ public class HealthModule implements CommandModule {
.build();
}
- private static TextComponent generateCpuUsageDiagram(double usage, int length) {
- int usedChars = (int) ((usage * length));
- String line = Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars);
- return TextComponent.builder("")
- .append(TextComponent.of("[", TextColor.DARK_GRAY))
- .append(TextComponent.of(line, TextColor.GRAY))
- .append(TextComponent.of("]", TextColor.DARK_GRAY))
- .build();
- }
-
private static TextComponent generateDiskUsageDiagram(double used, double max, int length) {
int usedChars = (int) ((used * length) / max);
String line = Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars);
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java
index 42c03d0..f5854f0 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java
@@ -65,7 +65,7 @@ public class MemoryModule implements CommandModule {
return;
}
- byte[] output = heapDump.formCompressedDataPayload();
+ byte[] output = heapDump.formCompressedDataPayload(sender);
try {
String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key();
String url = SparkPlatform.VIEWER_URL + key;
@@ -120,7 +120,7 @@ public class MemoryModule implements CommandModule {
}
resp.broadcastPrefixed(TextComponent.builder("Heap dump written to: ", TextColor.GOLD)
- .append(TextComponent.of(file.toString(), TextColor.DARK_GRAY))
+ .append(TextComponent.of(file.toString(), TextColor.GRAY))
.build()
);
platform.getActivityLog().addToLog(Activity.fileActivity(sender, System.currentTimeMillis(), "Heap dump", file.toString()));
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 4ea6144..4b7baae 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
@@ -228,8 +228,9 @@ public class SamplerModule implements CommandModule {
return Collections.emptyList();
}
- List<String> opts = new ArrayList<>(Arrays.asList("--timeout", "--regex", "--combine-all",
- "--not-combined", "--interval", "--only-ticks-over", "--include-line-numbers"));
+ List<String> opts = new ArrayList<>(Arrays.asList("--info", "--stop", "--cancel",
+ "--timeout", "--regex", "--combine-all", "--not-combined", "--interval",
+ "--only-ticks-over", "--include-line-numbers"));
opts.removeAll(arguments);
opts.add("--thread"); // allowed multiple times
@@ -243,7 +244,7 @@ public class SamplerModule implements CommandModule {
private void handleUpload(SparkPlatform platform, CommandResponseHandler resp, Sampler sampler) {
platform.getPlugin().runAsync(() -> {
- byte[] output = sampler.formCompressedDataPayload();
+ byte[] output = sampler.formCompressedDataPayload(resp.sender());
try {
String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key();
String url = SparkPlatform.VIEWER_URL + key;
diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/cpu/CpuMonitor.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/cpu/CpuMonitor.java
index 20d71ef..f4190e5 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/monitor/cpu/CpuMonitor.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/cpu/CpuMonitor.java
@@ -20,25 +20,60 @@
package me.lucko.spark.common.monitor.cpu;
+import me.lucko.spark.common.util.RollingAverage;
+
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
+import java.math.BigDecimal;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+/**
+ * Exposes and monitors the system/process CPU usage.
+ */
public final class CpuMonitor {
private CpuMonitor() {}
/** The object name of the com.sun.management.OperatingSystemMXBean */
private static final String OPERATING_SYSTEM_BEAN = "java.lang:type=OperatingSystem";
+ /** The OperatingSystemMXBean instance */
+ private static final OperatingSystemMXBean BEAN;
+ /** The executor used to monitor & calculate rolling averages. */
+ private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor(r -> {
+ Thread thread = Executors.defaultThreadFactory().newThread(r);
+ thread.setName("spark-cpu-monitor");
+ return thread;
+ });
- private static OperatingSystemMXBean getBean() {
+ // Rolling averages for system/process data
+ private static final RollingAverage SYSTEM_AVERAGE_10_SEC = new RollingAverage(10);
+ private static final RollingAverage SYSTEM_AVERAGE_1_MIN = new RollingAverage(60);
+ private static final RollingAverage SYSTEM_AVERAGE_15_MIN = new RollingAverage(60 * 15);
+ private static final RollingAverage PROCESS_AVERAGE_10_SEC = new RollingAverage(10);
+ private static final RollingAverage PROCESS_AVERAGE_1_MIN = new RollingAverage(60);
+ private static final RollingAverage PROCESS_AVERAGE_15_MIN = new RollingAverage(60 * 15);
+
+ static {
try {
MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName diagnosticBeanName = ObjectName.getInstance(OPERATING_SYSTEM_BEAN);
- return JMX.newMXBeanProxy(beanServer, diagnosticBeanName, OperatingSystemMXBean.class);
+ BEAN = JMX.newMXBeanProxy(beanServer, diagnosticBeanName, OperatingSystemMXBean.class);
} catch (Exception e) {
- throw new RuntimeException(e);
+ throw new UnsupportedOperationException("OperatingSystemMXBean is not supported by the system", e);
}
+
+ // schedule rolling average calculations.
+ EXECUTOR.scheduleAtFixedRate(new RollingAverageCollectionTask(), 1, 1, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Ensures that the static initializer has been called.
+ */
+ public static void ensureMonitoring() {
+ // intentionally empty
}
/**
@@ -54,8 +89,20 @@ public final class CpuMonitor {
* @return the "recent cpu usage" for the whole system; a negative
* value if not available.
*/
- public static double getSystemCpuLoad() {
- return getBean().getSystemCpuLoad();
+ public static double systemLoad() {
+ return BEAN.getSystemCpuLoad();
+ }
+
+ public static double systemLoad10SecAvg() {
+ return SYSTEM_AVERAGE_10_SEC.getAverage();
+ }
+
+ public static double systemLoad1MinAvg() {
+ return SYSTEM_AVERAGE_1_MIN.getAverage();
+ }
+
+ public static double systemLoad15MinAvg() {
+ return SYSTEM_AVERAGE_15_MIN.getAverage();
}
/**
@@ -73,8 +120,49 @@ public final class CpuMonitor {
* @return the "recent cpu usage" for the Java Virtual Machine process;
* a negative value if not available.
*/
- public static double getProcessCpuLoad() {
- return getBean().getProcessCpuLoad();
+ public static double processLoad() {
+ return BEAN.getProcessCpuLoad();
+ }
+
+ public static double processLoad10SecAvg() {
+ return PROCESS_AVERAGE_10_SEC.getAverage();
+ }
+
+ public static double processLoad1MinAvg() {
+ return PROCESS_AVERAGE_1_MIN.getAverage();
+ }
+
+ public static double processLoad15MinAvg() {
+ return PROCESS_AVERAGE_15_MIN.getAverage();
+ }
+
+ /**
+ * Task to poll CPU loads and add to the rolling averages in the enclosing class.
+ */
+ private static final class RollingAverageCollectionTask implements Runnable {
+ private final RollingAverage[] systemAverages = new RollingAverage[]{
+ SYSTEM_AVERAGE_10_SEC,
+ SYSTEM_AVERAGE_1_MIN,
+ SYSTEM_AVERAGE_15_MIN
+ };
+ private final RollingAverage[] processAverages = new RollingAverage[]{
+ PROCESS_AVERAGE_10_SEC,
+ PROCESS_AVERAGE_1_MIN,
+ PROCESS_AVERAGE_15_MIN
+ };
+
+ @Override
+ public void run() {
+ BigDecimal systemCpuLoad = new BigDecimal(systemLoad());
+ BigDecimal processCpuLoad = new BigDecimal(processLoad());
+
+ for (RollingAverage average : this.systemAverages) {
+ average.add(systemCpuLoad);
+ }
+ for (RollingAverage average : this.processAverages) {
+ average.add(processCpuLoad);
+ }
+ }
}
public interface OperatingSystemMXBean {
diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java
index 2278e0c..3000523 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java
@@ -21,8 +21,6 @@
package me.lucko.spark.common.monitor.tick;
import me.lucko.spark.common.sampler.TickCounter;
-import net.kyori.text.TextComponent;
-import net.kyori.text.format.TextColor;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -46,14 +44,14 @@ public class TpsCalculator implements TickCounter.TickTask {
private static final int SAMPLE_INTERVAL = 20;
private static final BigDecimal TPS_BASE = new BigDecimal(SEC_IN_NANO).multiply(new BigDecimal((long) SAMPLE_INTERVAL));
- private final RollingAverage tps5S = new RollingAverage(5);
- private final RollingAverage tps10S = new RollingAverage(10);
- private final RollingAverage tps1M = new RollingAverage(60);
- private final RollingAverage tps5M = new RollingAverage(60 * 5);
- private final RollingAverage tps15M = new RollingAverage(60 * 15);
+ private final TpsRollingAverage avg5Sec = new TpsRollingAverage(5);
+ private final TpsRollingAverage avg10Sec = new TpsRollingAverage(10);
+ private final TpsRollingAverage avg1Min = new TpsRollingAverage(60);
+ private final TpsRollingAverage avg5Min = new TpsRollingAverage(60 * 5);
+ private final TpsRollingAverage avg15Min = new TpsRollingAverage(60 * 15);
- private final RollingAverage[] averages = new RollingAverage[]{
- this.tps5S, this.tps10S, this.tps1M, this.tps5M, this.tps15M
+ private final TpsRollingAverage[] averages = new TpsRollingAverage[]{
+ this.avg5Sec, this.avg10Sec, this.avg1Min, this.avg5Min, this.avg15Min
};
private long last = 0;
@@ -75,55 +73,34 @@ public class TpsCalculator implements TickCounter.TickTask {
long diff = now - this.last;
BigDecimal currentTps = TPS_BASE.divide(new BigDecimal(diff), 30, RoundingMode.HALF_UP);
- for (RollingAverage rollingAverage : this.averages) {
+ for (TpsRollingAverage rollingAverage : this.averages) {
rollingAverage.add(currentTps, diff);
}
this.last = now;
}
- public RollingAverage avg5Sec() {
- return this.tps5S;
+ public double avg5Sec() {
+ return this.avg5Sec.getAverage();
}
- public RollingAverage avg10Sec() {
- return this.tps10S;
+ public double avg10Sec() {
+ return this.avg10Sec.getAverage();
}
- public RollingAverage avg1Min() {
- return this.tps1M;
+ public double avg1Min() {
+ return this.avg1Min.getAverage();
}
- public RollingAverage avg5Min() {
- return this.tps5M;
+ public double avg5Min() {
+ return this.avg5Min.getAverage();
}
- public RollingAverage avg15Min() {
- return this.tps15M;
+ public double avg15Min() {
+ return this.avg15Min.getAverage();
}
- public TextComponent toFormattedComponent() {
- return TextComponent.builder("")
- .append(format(this.tps5S.getAverage())).append(TextComponent.of(", "))
- .append(format(this.tps10S.getAverage())).append(TextComponent.of(", "))
- .append(format(this.tps1M.getAverage())).append(TextComponent.of(", "))
- .append(format(this.tps5M.getAverage())).append(TextComponent.of(", "))
- .append(format(this.tps15M.getAverage()))
- .build();
- }
-
- private static TextComponent format(double tps) {
- TextColor color;
- if (tps > 18.0) {
- color = TextColor.GREEN;
- } else if (tps > 16.0) {
- color = TextColor.YELLOW;
- } else {
- color = TextColor.RED;
- }
- return TextComponent.of( (tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color);
- }
/**
* Rolling average calculator taken.
@@ -132,7 +109,7 @@ public class TpsCalculator implements TickCounter.TickTask {
*
* @author aikar (PaperMC) https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0021-Further-improve-server-tick-loop.patch
*/
- public static final class RollingAverage {
+ public static final class TpsRollingAverage {
private final int size;
private long time;
private BigDecimal total;
@@ -140,7 +117,7 @@ public class TpsCalculator implements TickCounter.TickTask {
private final BigDecimal[] samples;
private final long[] times;
- RollingAverage(int size) {
+ TpsRollingAverage(int size) {
this.size = size;
this.time = size * SEC_IN_NANO;
this.total = new BigDecimal((long) TPS).multiply(new BigDecimal(SEC_IN_NANO)).multiply(new BigDecimal((long) size));
diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/RollingAverage.java b/spark-common/src/main/java/me/lucko/spark/common/util/RollingAverage.java
new file mode 100644
index 0000000..5b1fd21
--- /dev/null
+++ b/spark-common/src/main/java/me/lucko/spark/common/util/RollingAverage.java
@@ -0,0 +1,53 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * 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.common.util;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+public class RollingAverage {
+
+ private final Queue<BigDecimal> samples = new ArrayDeque<>();
+ private final int size;
+ private BigDecimal total = BigDecimal.ZERO;
+
+ public RollingAverage(int size) {
+ this.size = size;
+ }
+
+ public void add(BigDecimal num) {
+ this.total = this.total.add(num);
+ this.samples.add(num);
+ if (this.samples.size() > this.size) {
+ this.total = this.total.subtract(this.samples.remove());
+ }
+ }
+
+ public double getAverage() {
+ if (this.samples.isEmpty()) {
+ return 0;
+ }
+ return this.total.divide(BigDecimal.valueOf(this.samples.size()), 30, RoundingMode.HALF_UP).doubleValue();
+ }
+
+}