From 06b794dcea806150770fb88d43e366a3496a9d0f Mon Sep 17 00:00:00 2001 From: lucko Date: Sat, 28 Jan 2023 11:07:45 +0000 Subject: Stream live data to the viewer using WebSockets (#294) --- .../me/lucko/spark/common/util/BytebinClient.java | 14 ++- .../me/lucko/spark/common/util/Configuration.java | 27 +++++ .../me/lucko/spark/common/util/MediaTypes.java | 29 +++++ .../spark/common/util/ws/BytesocksClient.java | 118 +++++++++++++++++++++ .../spark/common/util/ws/BytesocksClientImpl.java | 40 +++++++ 5 files changed, 224 insertions(+), 4 deletions(-) create mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/MediaTypes.java create mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java create mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java (limited to 'spark-common/src/main/java/me/lucko/spark/common/util') diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java b/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java index e69b94e..8f11edc 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java @@ -32,6 +32,8 @@ import java.util.zip.GZIPOutputStream; /** * Utility for posting content to bytebin. + * + * @see https://github.com/lucko/bytebin */ public class BytebinClient { @@ -45,7 +47,7 @@ public class BytebinClient { this.userAgent = userAgent; } - private Content postContent(String contentType, Consumer consumer) throws IOException { + private Content postContent(String contentType, Consumer consumer, String userAgent) throws IOException { URL url = new URL(this.url + "post"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); try { @@ -55,7 +57,7 @@ public class BytebinClient { connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", contentType); - connection.setRequestProperty("User-Agent", this.userAgent); + connection.setRequestProperty("User-Agent", userAgent); connection.setRequestProperty("Content-Encoding", "gzip"); connection.connect(); @@ -74,14 +76,18 @@ public class BytebinClient { } } - public Content postContent(AbstractMessageLite proto, String contentType) throws IOException { + public Content postContent(AbstractMessageLite proto, String contentType, String userAgentExtra) throws IOException { return postContent(contentType, outputStream -> { try (OutputStream out = new GZIPOutputStream(outputStream)) { proto.writeTo(out); } catch (IOException e) { throw new RuntimeException(e); } - }); + }, this.userAgent + "/" + userAgentExtra); + } + + public Content postContent(AbstractMessageLite proto, String contentType) throws IOException { + return postContent(proto, contentType, this.userAgent); } public static final class Content { diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/Configuration.java b/spark-common/src/main/java/me/lucko/spark/common/util/Configuration.java index 32f3bc6..d19ba64 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/Configuration.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/Configuration.java @@ -22,6 +22,7 @@ package me.lucko.spark.common.util; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; @@ -32,6 +33,9 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public final class Configuration { private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); @@ -103,6 +107,21 @@ public final class Configuration { return val.isBoolean() ? val.getAsInt() : def; } + public List getStringList(String path) { + JsonElement el = this.root.get(path); + if (el == null || !el.isJsonArray()) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(); + for (JsonElement child : el.getAsJsonArray()) { + if (child.isJsonPrimitive()) { + list.add(child.getAsJsonPrimitive().getAsString()); + } + } + return list; + } + public void setString(String path, String value) { this.root.add(path, new JsonPrimitive(value)); } @@ -115,6 +134,14 @@ public final class Configuration { this.root.add(path, new JsonPrimitive(value)); } + public void setStringList(String path, List value) { + JsonArray array = new JsonArray(); + for (String str : value) { + array.add(str); + } + this.root.add(path, array); + } + public boolean contains(String path) { return this.root.has(path); } diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/MediaTypes.java b/spark-common/src/main/java/me/lucko/spark/common/util/MediaTypes.java new file mode 100644 index 0000000..2c49540 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/MediaTypes.java @@ -0,0 +1,29 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) + * 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 . + */ + +package me.lucko.spark.common.util; + +public enum MediaTypes { + ; + + public static final String SPARK_SAMPLER_MEDIA_TYPE = "application/x-spark-sampler"; + public static final String SPARK_HEAP_MEDIA_TYPE = "application/x-spark-heap"; + +} diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java b/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java new file mode 100644 index 0000000..1db7a67 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java @@ -0,0 +1,118 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) + * 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 . + */ + +package me.lucko.spark.common.util.ws; + +import java.util.concurrent.CompletableFuture; + +/** + * A client that can interact with bytesocks. + * + * @see https://github.com/lucko/bytesocks + */ +public interface BytesocksClient { + + /** + * Creates a new {@link BytesocksClient}. + * + *

Returns {@code null} on Java versions before 11.

+ * + * @param host the host + * @param userAgent the user agent + * @return the client + */ + static BytesocksClient create(String host, String userAgent) { + try { + return new BytesocksClientImpl(host, userAgent); + } catch (UnsupportedOperationException e) { + return null; + } + } + + /** + * Creates a new bytesocks channel and returns a socket connected to it. + * + * @param listener the listener + * @return the socket + * @throws Exception if something goes wrong + */ + Socket createAndConnect(Listener listener) throws Exception; + + /** + * Connects to an existing bytesocks channel. + * + * @param channelId the channel id + * @param listener the listener + * @return the socket + * @throws Exception if something goes wrong + */ + Socket connect(String channelId, Listener listener) throws Exception; + + /** + * A socket connected to a bytesocks channel. + */ + interface Socket { + + /** + * Gets the id of the connected channel. + * + * @return the id of the channel + */ + String getChannelId(); + + /** + * Gets if the socket is open. + * + * @return true if the socket is open + */ + boolean isOpen(); + + /** + * Sends a message to the channel using the socket. + * + * @param msg the message to send + * @return a future to encapsulate the progress of sending the message + */ + CompletableFuture send(CharSequence msg); + + /** + * Closes the socket. + * + * @param statusCode the status code + * @param reason the reason + */ + void close(int statusCode, String reason); + } + + /** + * Socket listener + */ + interface Listener { + + default void onOpen() {} + + default void onError(Throwable error) {} + + default void onText(CharSequence data) {} + + default void onClose(int statusCode, String reason) {} + } + +} diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java b/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java new file mode 100644 index 0000000..cf1489c --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java @@ -0,0 +1,40 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) + * 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 . + */ + +package me.lucko.spark.common.util.ws; + +// Overridden by java 11 source set + +class BytesocksClientImpl implements BytesocksClient { + + BytesocksClientImpl(String host, String userAgent) { + throw new UnsupportedOperationException(); + } + + @Override + public Socket createAndConnect(Listener listener) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public Socket connect(String channelId, Listener listener) throws Exception { + throw new UnsupportedOperationException(); + } +} -- cgit From f5fd47e225b5e887ea7fbccf5bfa5a927be35619 Mon Sep 17 00:00:00 2001 From: Luck Date: Sat, 28 Jan 2023 17:21:42 +0000 Subject: Fix bytebin user agent --- .../main/java/me/lucko/spark/common/util/BytebinClient.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'spark-common/src/main/java/me/lucko/spark/common/util') diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java b/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java index 8f11edc..b8a2053 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/BytebinClient.java @@ -47,7 +47,11 @@ public class BytebinClient { this.userAgent = userAgent; } - private Content postContent(String contentType, Consumer consumer, String userAgent) throws IOException { + private Content postContent(String contentType, Consumer consumer, String userAgentExtra) throws IOException { + String userAgent = userAgentExtra != null + ? this.userAgent + "/" + userAgentExtra + : this.userAgent; + URL url = new URL(this.url + "post"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); try { @@ -83,11 +87,11 @@ public class BytebinClient { } catch (IOException e) { throw new RuntimeException(e); } - }, this.userAgent + "/" + userAgentExtra); + }, userAgentExtra); } public Content postContent(AbstractMessageLite proto, String contentType) throws IOException { - return postContent(proto, contentType, this.userAgent); + return postContent(proto, contentType, null); } public static final class Content { -- cgit From 6ed41df89e109ef1bb8eef655e5d07843aca22e0 Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 12 Feb 2023 13:02:08 +0000 Subject: Fix NPE in ClassFinder (#287) --- spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'spark-common/src/main/java/me/lucko/spark/common/util') diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java b/spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java index 4481786..f132613 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java @@ -44,6 +44,9 @@ public class ClassFinder { } catch (Exception e) { return; } + if (instrumentation == null) { + return; + } // obtain and cache loaded classes for (Class loadedClass : instrumentation.getAllLoadedClasses()) { -- cgit From 0f30d2983ec6ef487fd1966c1c22fa4a73e081f9 Mon Sep 17 00:00:00 2001 From: Luck Date: Tue, 7 Mar 2023 21:54:14 +0000 Subject: Don't use multi-release jar for websocket code --- build.gradle | 6 - spark-bukkit/build.gradle | 1 + spark-bungeecord/build.gradle | 1 + spark-common/build.gradle | 23 +--- .../java/me/lucko/spark/common/SparkPlatform.java | 5 +- .../common/command/modules/SamplerModule.java | 2 +- .../spark/common/util/ws/BytesocksClient.java | 118 ----------------- .../spark/common/util/ws/BytesocksClientImpl.java | 40 ------ .../me/lucko/spark/common/ws/ViewerSocket.java | 2 +- .../spark/common/ws/ViewerSocketConnection.java | 2 +- .../spark/common/util/ws/BytesocksClientImpl.java | 146 --------------------- spark-fabric/build.gradle | 1 + spark-forge/build.gradle | 1 + spark-minestom/build.gradle | 1 + spark-nukkit/build.gradle | 1 + spark-sponge7/build.gradle | 1 + spark-sponge8/build.gradle | 1 + spark-velocity/build.gradle | 1 + spark-velocity4/build.gradle | 1 + spark-waterdog/build.gradle | 1 + 20 files changed, 18 insertions(+), 337 deletions(-) delete mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java delete mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java delete mode 100644 spark-common/src/main/java11/me/lucko/spark/common/util/ws/BytesocksClientImpl.java (limited to 'spark-common/src/main/java/me/lucko/spark/common/util') diff --git a/build.gradle b/build.gradle index 8984ca1..f1a0a8e 100644 --- a/build.gradle +++ b/build.gradle @@ -29,12 +29,6 @@ subprojects { options.release = 8 } - jar { - manifest { - attributes('Multi-Release': 'true') - } - } - processResources { duplicatesStrategy = DuplicatesStrategy.INCLUDE } diff --git a/spark-bukkit/build.gradle b/spark-bukkit/build.gradle index 92b65cc..1646bf2 100644 --- a/spark-bukkit/build.gradle +++ b/spark-bukkit/build.gradle @@ -37,6 +37,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-bungeecord/build.gradle b/spark-bungeecord/build.gradle index 885de55..7e6b93f 100644 --- a/spark-bungeecord/build.gradle +++ b/spark-bungeecord/build.gradle @@ -27,6 +27,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-common/build.gradle b/spark-common/build.gradle index 742d943..1713168 100644 --- a/spark-common/build.gradle +++ b/spark-common/build.gradle @@ -4,24 +4,6 @@ plugins { id 'com.google.protobuf' version '0.9.1' } -sourceSets { - java11 { - java { - srcDirs = ['src/main/java11'] - } - } -} - -compileJava11Java { - options.release = 11 -} - -jar { - into('META-INF/versions/11') { - from sourceSets.java11.output - } -} - license { exclude '**/sampler/async/jfr/**' } @@ -37,9 +19,8 @@ dependencies { implementation 'com.github.jvm-profiling-tools:async-profiler:v2.8.3' implementation 'org.ow2.asm:asm:9.1' implementation 'net.bytebuddy:byte-buddy-agent:1.11.0' - implementation 'com.google.protobuf:protobuf-javalite:3.21.11' - java11Implementation 'com.google.protobuf:protobuf-javalite:3.21.11' + implementation 'me.lucko:bytesocks-java-client:1.0-SNAPSHOT' api('net.kyori:adventure-api:4.12.0') { exclude(module: 'adventure-bom') @@ -61,8 +42,6 @@ dependencies { compileOnly 'com.google.code.gson:gson:2.7' compileOnly 'com.google.guava:guava:19.0' compileOnly 'org.checkerframework:checker-qual:3.8.0' - - java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compileJava } } protobuf { 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 61c6062..f609719 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 @@ -23,6 +23,8 @@ package me.lucko.spark.common; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import me.lucko.bytesocks.client.BytesocksClient; +import me.lucko.bytesocks.client.BytesocksClientFactory; import me.lucko.spark.common.activitylog.ActivityLog; import me.lucko.spark.common.api.SparkApi; import me.lucko.spark.common.command.Arguments; @@ -53,7 +55,6 @@ import me.lucko.spark.common.tick.TickReporter; import me.lucko.spark.common.util.BytebinClient; import me.lucko.spark.common.util.Configuration; import me.lucko.spark.common.util.TemporaryFiles; -import me.lucko.spark.common.util.ws.BytesocksClient; import me.lucko.spark.common.ws.TrustedKeyStore; import net.kyori.adventure.text.Component; @@ -126,7 +127,7 @@ public class SparkPlatform { String bytesocksHost = this.configuration.getString("bytesocksHost", "spark-usersockets.lucko.me"); this.bytebinClient = new BytebinClient(bytebinUrl, "spark-plugin"); - this.bytesocksClient = BytesocksClient.create(bytesocksHost, "spark-plugin"); + this.bytesocksClient = BytesocksClientFactory.newClient(bytesocksHost, "spark-plugin"); this.trustedKeyStore = new TrustedKeyStore(this.configuration); this.disableResponseBroadcast = this.configuration.getBoolean("disableResponseBroadcast", false); 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 049c817..27e790f 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 @@ -22,6 +22,7 @@ package me.lucko.spark.common.command.modules; import com.google.common.collect.Iterables; +import me.lucko.bytesocks.client.BytesocksClient; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.activitylog.Activity; import me.lucko.spark.common.command.Arguments; @@ -43,7 +44,6 @@ import me.lucko.spark.common.tick.TickHook; import me.lucko.spark.common.util.FormatUtil; import me.lucko.spark.common.util.MediaTypes; import me.lucko.spark.common.util.MethodDisambiguator; -import me.lucko.spark.common.util.ws.BytesocksClient; import me.lucko.spark.common.ws.ViewerSocket; import me.lucko.spark.proto.SparkSamplerProtos; diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java b/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java deleted file mode 100644 index 1db7a67..0000000 --- a/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClient.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This file is part of spark. - * - * Copyright (c) lucko (Luck) - * 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 . - */ - -package me.lucko.spark.common.util.ws; - -import java.util.concurrent.CompletableFuture; - -/** - * A client that can interact with bytesocks. - * - * @see https://github.com/lucko/bytesocks - */ -public interface BytesocksClient { - - /** - * Creates a new {@link BytesocksClient}. - * - *

Returns {@code null} on Java versions before 11.

- * - * @param host the host - * @param userAgent the user agent - * @return the client - */ - static BytesocksClient create(String host, String userAgent) { - try { - return new BytesocksClientImpl(host, userAgent); - } catch (UnsupportedOperationException e) { - return null; - } - } - - /** - * Creates a new bytesocks channel and returns a socket connected to it. - * - * @param listener the listener - * @return the socket - * @throws Exception if something goes wrong - */ - Socket createAndConnect(Listener listener) throws Exception; - - /** - * Connects to an existing bytesocks channel. - * - * @param channelId the channel id - * @param listener the listener - * @return the socket - * @throws Exception if something goes wrong - */ - Socket connect(String channelId, Listener listener) throws Exception; - - /** - * A socket connected to a bytesocks channel. - */ - interface Socket { - - /** - * Gets the id of the connected channel. - * - * @return the id of the channel - */ - String getChannelId(); - - /** - * Gets if the socket is open. - * - * @return true if the socket is open - */ - boolean isOpen(); - - /** - * Sends a message to the channel using the socket. - * - * @param msg the message to send - * @return a future to encapsulate the progress of sending the message - */ - CompletableFuture send(CharSequence msg); - - /** - * Closes the socket. - * - * @param statusCode the status code - * @param reason the reason - */ - void close(int statusCode, String reason); - } - - /** - * Socket listener - */ - interface Listener { - - default void onOpen() {} - - default void onError(Throwable error) {} - - default void onText(CharSequence data) {} - - default void onClose(int statusCode, String reason) {} - } - -} diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java b/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java deleted file mode 100644 index cf1489c..0000000 --- a/spark-common/src/main/java/me/lucko/spark/common/util/ws/BytesocksClientImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of spark. - * - * Copyright (c) lucko (Luck) - * 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 . - */ - -package me.lucko.spark.common.util.ws; - -// Overridden by java 11 source set - -class BytesocksClientImpl implements BytesocksClient { - - BytesocksClientImpl(String host, String userAgent) { - throw new UnsupportedOperationException(); - } - - @Override - public Socket createAndConnect(Listener listener) throws Exception { - throw new UnsupportedOperationException(); - } - - @Override - public Socket connect(String channelId, Listener listener) throws Exception { - throw new UnsupportedOperationException(); - } -} diff --git a/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocket.java b/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocket.java index 5c7e08c..6a9c2b7 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocket.java +++ b/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocket.java @@ -22,12 +22,12 @@ package me.lucko.spark.common.ws; import com.google.protobuf.ByteString; +import me.lucko.bytesocks.client.BytesocksClient; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.sampler.AbstractSampler; import me.lucko.spark.common.sampler.Sampler; import me.lucko.spark.common.sampler.window.ProfilingWindowUtils; import me.lucko.spark.common.util.MediaTypes; -import me.lucko.spark.common.util.ws.BytesocksClient; import me.lucko.spark.proto.SparkProtos; import me.lucko.spark.proto.SparkSamplerProtos; import me.lucko.spark.proto.SparkWebSocketProtos.ClientConnect; diff --git a/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocketConnection.java b/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocketConnection.java index f870cb7..9079860 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocketConnection.java +++ b/spark-common/src/main/java/me/lucko/spark/common/ws/ViewerSocketConnection.java @@ -22,8 +22,8 @@ package me.lucko.spark.common.ws; import com.google.protobuf.ByteString; +import me.lucko.bytesocks.client.BytesocksClient; import me.lucko.spark.common.SparkPlatform; -import me.lucko.spark.common.util.ws.BytesocksClient; import me.lucko.spark.proto.SparkWebSocketProtos.PacketWrapper; import me.lucko.spark.proto.SparkWebSocketProtos.RawPacket; diff --git a/spark-common/src/main/java11/me/lucko/spark/common/util/ws/BytesocksClientImpl.java b/spark-common/src/main/java11/me/lucko/spark/common/util/ws/BytesocksClientImpl.java deleted file mode 100644 index 7adb809..0000000 --- a/spark-common/src/main/java11/me/lucko/spark/common/util/ws/BytesocksClientImpl.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * This file is part of spark. - * - * Copyright (c) lucko (Luck) - * 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 . - */ - -package me.lucko.spark.common.util.ws; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.net.http.WebSocket; -import java.time.Duration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; - -/** - * Java 11 implementation of {@link BytesocksClient}. - */ -class BytesocksClientImpl implements BytesocksClient { - - private final HttpClient client; - - /* The bytesocks urls */ - private final String httpUrl; - private final String wsUrl; - - /** The client user agent */ - private final String userAgent; - - BytesocksClientImpl(String host, String userAgent) { - this.client = HttpClient.newHttpClient(); - - this.httpUrl = "https://" + host + "/"; - this.wsUrl = "wss://" + host + "/"; - this.userAgent = userAgent; - } - - @Override - public Socket createAndConnect(Listener listener) throws Exception { - HttpRequest createRequest = HttpRequest.newBuilder() - .uri(URI.create(this.httpUrl + "create")) - .header("User-Agent", this.userAgent) - .build(); - - HttpResponse resp = this.client.send(createRequest, HttpResponse.BodyHandlers.discarding()); - if (resp.statusCode() != 201) { - throw new RuntimeException("Request failed: " + resp); - } - - String channelId = resp.headers().firstValue("Location").orElse(null); - if (channelId == null) { - throw new RuntimeException("Location header not returned: " + resp); - } - - return connect(channelId, listener); - } - - @Override - public Socket connect(String channelId, Listener listener) throws Exception { - WebSocket socket = this.client.newWebSocketBuilder() - .header("User-Agent", this.userAgent) - .connectTimeout(Duration.ofSeconds(5)) - .buildAsync(URI.create(this.wsUrl + channelId), new ListenerImpl(listener)) - .join(); - - return new SocketImpl(channelId, socket); - } - - private static final class SocketImpl implements Socket { - private final String id; - private final WebSocket ws; - - private SocketImpl(String id, WebSocket ws) { - this.id = id; - this.ws = ws; - } - - @Override - public String getChannelId() { - return this.id; - } - - @Override - public boolean isOpen() { - return !this.ws.isOutputClosed() && !this.ws.isInputClosed(); - } - - @Override - public CompletableFuture send(CharSequence msg) { - return this.ws.sendText(msg, true); - } - - @Override - public void close(int statusCode, String reason) { - this.ws.sendClose(statusCode, reason); - } - } - - private static final class ListenerImpl implements WebSocket.Listener { - private final Listener listener; - - private ListenerImpl(Listener listener) { - this.listener = listener; - } - - @Override - public void onOpen(WebSocket webSocket) { - this.listener.onOpen(); - webSocket.request(1); - } - - @Override - public CompletionStage onClose(WebSocket webSocket, int statusCode, String reason) { - return CompletableFuture.runAsync(() -> this.listener.onClose(statusCode, reason)); - } - - @Override - public void onError(WebSocket webSocket, Throwable error) { - this.listener.onError(error); - } - - @Override - public CompletionStage onText(WebSocket webSocket, CharSequence data, boolean last) { - webSocket.request(1); - return CompletableFuture.runAsync(() -> this.listener.onText(data)); - } - } - - -} diff --git a/spark-fabric/build.gradle b/spark-fabric/build.gradle index 0421f68..b59ee1d 100644 --- a/spark-fabric/build.gradle +++ b/spark-fabric/build.gradle @@ -80,6 +80,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' // relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-forge/build.gradle b/spark-forge/build.gradle index 47c4c22..733a0f7 100644 --- a/spark-forge/build.gradle +++ b/spark-forge/build.gradle @@ -58,6 +58,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-minestom/build.gradle b/spark-minestom/build.gradle index a673106..788201b 100644 --- a/spark-minestom/build.gradle +++ b/spark-minestom/build.gradle @@ -35,6 +35,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-nukkit/build.gradle b/spark-nukkit/build.gradle index fbdf2b8..d2e4833 100644 --- a/spark-nukkit/build.gradle +++ b/spark-nukkit/build.gradle @@ -31,6 +31,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-sponge7/build.gradle b/spark-sponge7/build.gradle index b06d3bd..0610a9a 100644 --- a/spark-sponge7/build.gradle +++ b/spark-sponge7/build.gradle @@ -28,6 +28,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-sponge8/build.gradle b/spark-sponge8/build.gradle index 202c308..cbd922f 100644 --- a/spark-sponge8/build.gradle +++ b/spark-sponge8/build.gradle @@ -33,6 +33,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-velocity/build.gradle b/spark-velocity/build.gradle index 275d3df..5aa15a5 100644 --- a/spark-velocity/build.gradle +++ b/spark-velocity/build.gradle @@ -31,6 +31,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-velocity4/build.gradle b/spark-velocity4/build.gradle index 1f8e8ee..d30f28b 100644 --- a/spark-velocity4/build.gradle +++ b/spark-velocity4/build.gradle @@ -36,6 +36,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' diff --git a/spark-waterdog/build.gradle b/spark-waterdog/build.gradle index b8f5331..c4bd382 100644 --- a/spark-waterdog/build.gradle +++ b/spark-waterdog/build.gradle @@ -37,6 +37,7 @@ shadowJar { relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf' relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm' relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler' + relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks' exclude 'module-info.class' exclude 'META-INF/maven/**' -- cgit From 6cdd78a0c57d751d3a44b319703c20b034f8d675 Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 19 Mar 2023 13:24:13 +0000 Subject: Tidy up thread factories and async sampler regex thread filter --- .../spark/common/monitor/MonitoringExecutor.java | 5 +- .../lucko/spark/common/sampler/SamplerBuilder.java | 1 - .../lucko/spark/common/sampler/ThreadDumper.java | 71 +++++++++++++--------- .../common/sampler/async/AsyncProfilerJob.java | 16 +---- .../spark/common/sampler/async/AsyncSampler.java | 6 +- .../spark/common/sampler/java/JavaSampler.java | 6 +- .../spark/common/util/SparkThreadFactory.java | 15 ++--- 7 files changed, 67 insertions(+), 53 deletions(-) (limited to 'spark-common/src/main/java/me/lucko/spark/common/util') diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/MonitoringExecutor.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/MonitoringExecutor.java index 635ae20..cbacebf 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/monitor/MonitoringExecutor.java +++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/MonitoringExecutor.java @@ -20,6 +20,8 @@ package me.lucko.spark.common.monitor; +import me.lucko.spark.common.util.SparkThreadFactory; + import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -29,7 +31,8 @@ public enum MonitoringExecutor { /** The executor used to monitor & calculate rolling averages. */ public static final ScheduledExecutorService INSTANCE = Executors.newSingleThreadScheduledExecutor(r -> { Thread thread = Executors.defaultThreadFactory().newThread(r); - thread.setName("spark-monitor"); + thread.setName("spark-monitoring-thread"); + thread.setUncaughtExceptionHandler(SparkThreadFactory.EXCEPTION_HANDLER); thread.setDaemon(true); return thread; }); diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/SamplerBuilder.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/SamplerBuilder.java index 7891a98..b6895ce 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/SamplerBuilder.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/SamplerBuilder.java @@ -120,7 +120,6 @@ public class SamplerBuilder { boolean canUseAsyncProfiler = this.useAsyncProfiler && !onlyTicksOverMode && !(this.ignoreSleeping || this.ignoreNative) && - !(this.threadDumper instanceof ThreadDumper.Regex) && AsyncProfilerAccess.getInstance(platform).checkSupported(platform); if (this.mode == SamplerMode.ALLOCATION && (!canUseAsyncProfiler || !AsyncProfilerAccess.getInstance(platform).checkAllocationProfilingSupported(platform))) { diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/ThreadDumper.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/ThreadDumper.java index 62e2dda..c68384b 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/ThreadDumper.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/ThreadDumper.java @@ -32,7 +32,6 @@ import java.util.Objects; import java.util.Set; import java.util.function.Supplier; import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; /** @@ -49,6 +48,15 @@ public interface ThreadDumper { */ ThreadInfo[] dumpThreads(ThreadMXBean threadBean); + /** + * Gets if the given thread should be included in the output. + * + * @param threadId the thread id + * @param threadName the thread name + * @return if the thread should be included + */ + boolean isThreadIncluded(long threadId, String threadName); + /** * Gets metadata about the thread dumper instance. */ @@ -81,6 +89,11 @@ public interface ThreadDumper { return threadBean.dumpAllThreads(false, false); } + @Override + public boolean isThreadIncluded(long threadId, String threadName) { + return true; + } + @Override public SamplerMetadata.ThreadDumper getMetadata() { return SamplerMetadata.ThreadDumper.newBuilder() @@ -116,7 +129,7 @@ public interface ThreadDumper { } public void setThread(Thread thread) { - this.dumper = new Specific(new long[]{thread.getId()}); + this.dumper = new Specific(thread); } } @@ -132,10 +145,6 @@ public interface ThreadDumper { this.ids = new long[]{thread.getId()}; } - public Specific(long[] ids) { - this.ids = ids; - } - public Specific(Set names) { this.threadNamesLowerCase = names.stream().map(String::toLowerCase).collect(Collectors.toSet()); this.ids = new ThreadFinder().getThreads() @@ -163,6 +172,14 @@ public interface ThreadDumper { return this.threadNamesLowerCase; } + @Override + public boolean isThreadIncluded(long threadId, String threadName) { + if (Arrays.binarySearch(this.ids, threadId) >= 0) { + return true; + } + return getThreadNames().contains(threadName.toLowerCase()); + } + @Override public ThreadInfo[] dumpThreads(ThreadMXBean threadBean) { return threadBean.getThreadInfo(this.ids, Integer.MAX_VALUE); @@ -187,35 +204,31 @@ public interface ThreadDumper { public Regex(Set namePatterns) { this.namePatterns = namePatterns.stream() - .map(regex -> { - try { - return Pattern.compile(regex, Pattern.CASE_INSENSITIVE); - } catch (PatternSyntaxException e) { - return null; - } - }) - .filter(Objects::nonNull) + .map(regex -> Pattern.compile(regex, Pattern.CASE_INSENSITIVE)) .collect(Collectors.toSet()); } + @Override + public boolean isThreadIncluded(long threadId, String threadName) { + Boolean result = this.cache.get(threadId); + if (result != null) { + return result; + } + + for (Pattern pattern : this.namePatterns) { + if (pattern.matcher(threadName).matches()) { + this.cache.put(threadId, true); + return true; + } + } + this.cache.put(threadId, false); + return false; + } + @Override public ThreadInfo[] dumpThreads(ThreadMXBean threadBean) { return this.threadFinder.getThreads() - .filter(thread -> { - Boolean result = this.cache.get(thread.getId()); - if (result != null) { - return result; - } - - for (Pattern pattern : this.namePatterns) { - if (pattern.matcher(thread.getName()).matches()) { - this.cache.put(thread.getId(), true); - return true; - } - } - this.cache.put(thread.getId(), false); - return false; - }) + .filter(thread -> isThreadIncluded(thread.getId(), thread.getName())) .map(thread -> threadBean.getThreadInfo(thread.getId(), Integer.MAX_VALUE)) .filter(Objects::nonNull) .toArray(ThreadInfo[]::new); diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerJob.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerJob.java index 039d4ba..2fd304c 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerJob.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerJob.java @@ -34,7 +34,6 @@ import java.nio.file.Path; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; /** * Represents a profiling job within async-profiler. @@ -203,18 +202,9 @@ public class AsyncProfilerJob { * Aggregates the collected data. */ public void aggregate(AsyncDataAggregator dataAggregator) { - - Predicate threadFilter; - if (this.threadDumper instanceof ThreadDumper.Specific) { - ThreadDumper.Specific specificDumper = (ThreadDumper.Specific) this.threadDumper; - threadFilter = n -> specificDumper.getThreadNames().contains(n.toLowerCase()); - } else { - threadFilter = n -> true; - } - // read the jfr file produced by async-profiler try (JfrReader reader = new JfrReader(this.outputFile)) { - readSegments(reader, this.sampleCollector, threadFilter, dataAggregator); + readSegments(reader, this.sampleCollector, dataAggregator); } catch (Exception e) { boolean fileExists; try { @@ -241,7 +231,7 @@ public class AsyncProfilerJob { } } - private void readSegments(JfrReader reader, SampleCollector collector, Predicate threadFilter, AsyncDataAggregator dataAggregator) throws IOException { + private void readSegments(JfrReader reader, SampleCollector collector, AsyncDataAggregator dataAggregator) throws IOException { List samples = reader.readAllEvents(collector.eventClass()); for (E sample : samples) { String threadName = reader.threads.get((long) sample.tid); @@ -249,7 +239,7 @@ public class AsyncProfilerJob { continue; } - if (!threadFilter.test(threadName)) { + if (!this.threadDumper.isThreadIncluded(sample.tid, threadName)) { continue; } diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java index ec88677..961c3e9 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java @@ -28,6 +28,7 @@ import me.lucko.spark.common.sampler.SamplerMode; import me.lucko.spark.common.sampler.SamplerSettings; import me.lucko.spark.common.sampler.window.ProfilingWindowUtils; import me.lucko.spark.common.tick.TickHook; +import me.lucko.spark.common.util.SparkThreadFactory; import me.lucko.spark.common.ws.ViewerSocket; import me.lucko.spark.proto.SparkSamplerProtos.SamplerData; @@ -69,7 +70,10 @@ public class AsyncSampler extends AbstractSampler { this.profilerAccess = AsyncProfilerAccess.getInstance(platform); this.dataAggregator = new AsyncDataAggregator(settings.threadGrouper()); this.scheduler = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder().setNameFormat("spark-asyncsampler-worker-thread").build() + new ThreadFactoryBuilder() + .setNameFormat("spark-async-sampler-worker-thread") + .setUncaughtExceptionHandler(SparkThreadFactory.EXCEPTION_HANDLER) + .build() ); } diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java index 2e40406..e29619b 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java @@ -29,6 +29,7 @@ import me.lucko.spark.common.sampler.SamplerSettings; import me.lucko.spark.common.sampler.window.ProfilingWindowUtils; import me.lucko.spark.common.sampler.window.WindowStatisticsCollector; import me.lucko.spark.common.tick.TickHook; +import me.lucko.spark.common.util.SparkThreadFactory; import me.lucko.spark.common.ws.ViewerSocket; import me.lucko.spark.proto.SparkSamplerProtos.SamplerData; @@ -50,7 +51,10 @@ public class JavaSampler extends AbstractSampler implements Runnable { /** The worker pool for inserting stack nodes */ private final ScheduledExecutorService workerPool = Executors.newScheduledThreadPool( - 6, new ThreadFactoryBuilder().setNameFormat("spark-worker-" + THREAD_ID.getAndIncrement() + "-%d").build() + 6, new ThreadFactoryBuilder() + .setNameFormat("spark-java-sampler-" + THREAD_ID.getAndIncrement() + "-%d") + .setUncaughtExceptionHandler(SparkThreadFactory.EXCEPTION_HANDLER) + .build() ); /** The main sampling task */ diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.java b/spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.java index 156fa0d..42dca12 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.java @@ -23,7 +23,13 @@ package me.lucko.spark.common.util; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; -public class SparkThreadFactory implements ThreadFactory, Thread.UncaughtExceptionHandler { +public class SparkThreadFactory implements ThreadFactory { + + public static final Thread.UncaughtExceptionHandler EXCEPTION_HANDLER = (t, e) -> { + System.err.println("Uncaught exception thrown by thread " + t.getName()); + e.printStackTrace(); + }; + private static final AtomicInteger poolNumber = new AtomicInteger(1); private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; @@ -36,14 +42,9 @@ public class SparkThreadFactory implements ThreadFactory, Thread.UncaughtExcepti public Thread newThread(Runnable r) { Thread t = new Thread(r, this.namePrefix + this.threadNumber.getAndIncrement()); - t.setUncaughtExceptionHandler(this); + t.setUncaughtExceptionHandler(EXCEPTION_HANDLER); t.setDaemon(true); return t; } - @Override - public void uncaughtException(Thread t, Throwable e) { - System.err.println("Uncaught exception thrown by thread " + t.getName()); - e.printStackTrace(); - } } -- cgit From a70ccb394839c63f13b3e6ff5539c0a042925d2f Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 19 Mar 2023 19:35:29 +0000 Subject: Allow platforms to provide their own TPS/MSPT calculations --- .../lucko/spark/api/statistic/StatisticWindow.java | 3 +- .../java/me/lucko/spark/common/SparkPlatform.java | 15 +- .../java/me/lucko/spark/common/SparkPlugin.java | 13 ++ .../java/me/lucko/spark/common/api/SparkApi.java | 2 + .../common/monitor/tick/SparkTickStatistics.java | 197 +++++++++++++++++++++ .../spark/common/monitor/tick/TickStatistics.java | 169 ++---------------- .../platform/PlatformStatisticsProvider.java | 26 ++- .../sampler/window/WindowStatisticsCollector.java | 4 +- .../me/lucko/spark/common/util/RollingAverage.java | 11 -- .../spark/common/util/StatisticFormatter.java | 4 +- 10 files changed, 260 insertions(+), 184 deletions(-) create mode 100644 spark-common/src/main/java/me/lucko/spark/common/monitor/tick/SparkTickStatistics.java (limited to 'spark-common/src/main/java/me/lucko/spark/common/util') diff --git a/spark-api/src/main/java/me/lucko/spark/api/statistic/StatisticWindow.java b/spark-api/src/main/java/me/lucko/spark/api/statistic/StatisticWindow.java index cdf4d01..cdaa2b8 100644 --- a/spark-api/src/main/java/me/lucko/spark/api/statistic/StatisticWindow.java +++ b/spark-api/src/main/java/me/lucko/spark/api/statistic/StatisticWindow.java @@ -92,7 +92,8 @@ public interface StatisticWindow { enum MillisPerTick implements StatisticWindow { SECONDS_10(Duration.ofSeconds(10)), - MINUTES_1(Duration.ofMinutes(1)); + MINUTES_1(Duration.ofMinutes(1)), + MINUTES_5(Duration.ofMinutes(5)); private final Duration value; 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 f609719..84f435a 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 @@ -45,6 +45,7 @@ import me.lucko.spark.common.monitor.memory.GarbageCollectorStatistics; import me.lucko.spark.common.monitor.net.NetworkMonitor; import me.lucko.spark.common.monitor.ping.PingStatistics; import me.lucko.spark.common.monitor.ping.PlayerPingProvider; +import me.lucko.spark.common.monitor.tick.SparkTickStatistics; import me.lucko.spark.common.monitor.tick.TickStatistics; import me.lucko.spark.common.platform.PlatformStatisticsProvider; import me.lucko.spark.common.sampler.BackgroundSamplerManager; @@ -153,9 +154,13 @@ public class SparkPlatform { this.samplerContainer = new SamplerContainer(); this.backgroundSamplerManager = new BackgroundSamplerManager(this, this.configuration); + TickStatistics tickStatistics = plugin.createTickStatistics(); this.tickHook = plugin.createTickHook(); this.tickReporter = plugin.createTickReporter(); - this.tickStatistics = this.tickHook != null || this.tickReporter != null ? new TickStatistics() : null; + if (tickStatistics == null && (this.tickHook != null || this.tickReporter != null)) { + tickStatistics = new SparkTickStatistics(); + } + this.tickStatistics = tickStatistics; PlayerPingProvider pingProvider = plugin.createPlayerPingProvider(); this.pingStatistics = pingProvider != null ? new PingStatistics(pingProvider) : null; @@ -168,12 +173,12 @@ public class SparkPlatform { throw new RuntimeException("Platform has already been enabled!"); } - if (this.tickHook != null) { - this.tickHook.addCallback(this.tickStatistics); + if (this.tickHook != null && this.tickStatistics instanceof SparkTickStatistics) { + this.tickHook.addCallback((TickHook.Callback) this.tickStatistics); this.tickHook.start(); } - if (this.tickReporter != null) { - this.tickReporter.addCallback(this.tickStatistics); + if (this.tickReporter != null&& this.tickStatistics instanceof SparkTickStatistics) { + this.tickReporter.addCallback((TickReporter.Callback) this.tickStatistics); this.tickReporter.start(); } if (this.pingStatistics != null) { diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java index b7aef2a..a3bdceb 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java +++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java @@ -23,6 +23,7 @@ package me.lucko.spark.common; import me.lucko.spark.api.Spark; import me.lucko.spark.common.command.sender.CommandSender; import me.lucko.spark.common.monitor.ping.PlayerPingProvider; +import me.lucko.spark.common.monitor.tick.TickStatistics; import me.lucko.spark.common.platform.MetadataProvider; import me.lucko.spark.common.platform.PlatformInfo; import me.lucko.spark.common.platform.serverconfig.ServerConfigProvider; @@ -127,6 +128,18 @@ public interface SparkPlugin { return null; } + /** + * Creates tick statistics for the platform, if supported. + * + *

Spark is able to provide a default implementation for platforms that + * provide a {@link TickHook} and {@link TickReporter}.

+ * + * @return a new tick statistics instance + */ + default TickStatistics createTickStatistics() { + return null; + } + /** * Creates a class source lookup function. * diff --git a/spark-common/src/main/java/me/lucko/spark/common/api/SparkApi.java b/spark-common/src/main/java/me/lucko/spark/common/api/SparkApi.java index 5b1ec2b..9e4eee4 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/api/SparkApi.java +++ b/spark-common/src/main/java/me/lucko/spark/common/api/SparkApi.java @@ -151,6 +151,8 @@ public class SparkApi implements Spark { return stats.duration10Sec(); case MINUTES_1: return stats.duration1Min(); + case MINUTES_5: + return stats.duration5Min(); default: throw new AssertionError(window); } diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/SparkTickStatistics.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/SparkTickStatistics.java new file mode 100644 index 0000000..5877cbe --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/SparkTickStatistics.java @@ -0,0 +1,197 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) + * 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 . + */ + +package me.lucko.spark.common.monitor.tick; + +import me.lucko.spark.api.statistic.misc.DoubleAverageInfo; +import me.lucko.spark.common.tick.TickHook; +import me.lucko.spark.common.tick.TickReporter; +import me.lucko.spark.common.util.RollingAverage; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.concurrent.TimeUnit; + +/** + * Calculates the servers TPS (ticks per second) rate. + * + *

The code use to calculate the TPS is the same as the code used by the Minecraft server itself. + * This means that this class will output values the same as the /tps command.

+ * + *

We calculate our own values instead of pulling them from the server for two reasons. Firstly, + * it's easier - pulling from the server requires reflection code on each of the platforms, we'd + * rather avoid that. Secondly, it allows us to generate rolling averages over a shorter period of + * time.

+ */ +public class SparkTickStatistics implements TickHook.Callback, TickReporter.Callback, TickStatistics { + + private static final long SEC_IN_NANO = TimeUnit.SECONDS.toNanos(1); + private static final int TPS = 20; + private static final int TPS_SAMPLE_INTERVAL = 20; + private static final BigDecimal TPS_BASE = new BigDecimal(SEC_IN_NANO).multiply(new BigDecimal(TPS_SAMPLE_INTERVAL)); + + private final TpsRollingAverage tps5Sec = new TpsRollingAverage(5); + private final TpsRollingAverage tps10Sec = new TpsRollingAverage(10); + private final TpsRollingAverage tps1Min = new TpsRollingAverage(60); + private final TpsRollingAverage tps5Min = new TpsRollingAverage(60 * 5); + private final TpsRollingAverage tps15Min = new TpsRollingAverage(60 * 15); + private final TpsRollingAverage[] tpsAverages = {this.tps5Sec, this.tps10Sec, this.tps1Min, this.tps5Min, this.tps15Min}; + + private boolean durationSupported = false; + private final RollingAverage tickDuration10Sec = new RollingAverage(TPS * 10); + private final RollingAverage tickDuration1Min = new RollingAverage(TPS * 60); + private final RollingAverage tickDuration5Min = new RollingAverage(TPS * 60 * 5); + private final RollingAverage[] tickDurationAverages = {this.tickDuration10Sec, this.tickDuration1Min, this.tickDuration5Min}; + + private long last = 0; + + @Override + public boolean isDurationSupported() { + return this.durationSupported; + } + + @Override + public void onTick(int currentTick) { + if (currentTick % TPS_SAMPLE_INTERVAL != 0) { + return; + } + + long now = System.nanoTime(); + + if (this.last == 0) { + this.last = now; + return; + } + + long diff = now - this.last; + BigDecimal currentTps = TPS_BASE.divide(new BigDecimal(diff), 30, RoundingMode.HALF_UP); + BigDecimal total = currentTps.multiply(new BigDecimal(diff)); + + for (TpsRollingAverage rollingAverage : this.tpsAverages) { + rollingAverage.add(currentTps, diff, total); + } + + this.last = now; + } + + @Override + public void onTick(double duration) { + this.durationSupported = true; + BigDecimal decimal = new BigDecimal(duration); + for (RollingAverage rollingAverage : this.tickDurationAverages) { + rollingAverage.add(decimal); + } + } + + @Override + public double tps5Sec() { + return this.tps5Sec.getAverage(); + } + + @Override + public double tps10Sec() { + return this.tps10Sec.getAverage(); + } + + @Override + public double tps1Min() { + return this.tps1Min.getAverage(); + } + + @Override + public double tps5Min() { + return this.tps5Min.getAverage(); + } + + @Override + public double tps15Min() { + return this.tps15Min.getAverage(); + } + + @Override + public DoubleAverageInfo duration10Sec() { + if (!this.durationSupported) { + return null; + } + return this.tickDuration10Sec; + } + + @Override + public DoubleAverageInfo duration1Min() { + if (!this.durationSupported) { + return null; + } + return this.tickDuration1Min; + } + + @Override + public DoubleAverageInfo duration5Min() { + if (!this.durationSupported) { + return null; + } + return this.tickDuration5Min; + } + + + /** + * Rolling average calculator. + * + *

This code is taken from PaperMC/Paper, licensed under MIT.

+ * + * @author aikar (PaperMC) https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0021-Further-improve-server-tick-loop.patch + */ + public static final class TpsRollingAverage { + private final int size; + private long time; + private BigDecimal total; + private int index = 0; + private final BigDecimal[] samples; + private final long[] times; + + TpsRollingAverage(int size) { + this.size = size; + this.time = size * SEC_IN_NANO; + this.total = new BigDecimal(TPS).multiply(new BigDecimal(SEC_IN_NANO)).multiply(new BigDecimal(size)); + this.samples = new BigDecimal[size]; + this.times = new long[size]; + for (int i = 0; i < size; i++) { + this.samples[i] = new BigDecimal(TPS); + this.times[i] = SEC_IN_NANO; + } + } + + public void add(BigDecimal x, long t, BigDecimal total) { + this.time -= this.times[this.index]; + this.total = this.total.subtract(this.samples[this.index].multiply(new BigDecimal(this.times[this.index]))); + this.samples[this.index] = x; + this.times[this.index] = t; + this.time += t; + this.total = this.total.add(total); + if (++this.index == this.size) { + this.index = 0; + } + } + + public double getAverage() { + return this.total.divide(new BigDecimal(this.time), 30, RoundingMode.HALF_UP).doubleValue(); + } + } + +} diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickStatistics.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickStatistics.java index bd2b834..a48b178 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickStatistics.java +++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickStatistics.java @@ -20,168 +20,23 @@ package me.lucko.spark.common.monitor.tick; -import me.lucko.spark.common.tick.TickHook; -import me.lucko.spark.common.tick.TickReporter; -import me.lucko.spark.common.util.RollingAverage; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.concurrent.TimeUnit; +import me.lucko.spark.api.statistic.misc.DoubleAverageInfo; /** - * Calculates the servers TPS (ticks per second) rate. - * - *

The code use to calculate the TPS is the same as the code used by the Minecraft server itself. - * This means that this class will output values the same as the /tps command.

- * - *

We calculate our own values instead of pulling them from the server for two reasons. Firstly, - * it's easier - pulling from the server requires reflection code on each of the platforms, we'd - * rather avoid that. Secondly, it allows us to generate rolling averages over a shorter period of - * time.

+ * Provides the server TPS (ticks per second) and MSPT (milliseconds per tick) rates. */ -public class TickStatistics implements TickHook.Callback, TickReporter.Callback { - - private static final long SEC_IN_NANO = TimeUnit.SECONDS.toNanos(1); - private static final int TPS = 20; - private static final int TPS_SAMPLE_INTERVAL = 20; - private static final BigDecimal TPS_BASE = new BigDecimal(SEC_IN_NANO).multiply(new BigDecimal(TPS_SAMPLE_INTERVAL)); - - private final TpsRollingAverage tps5Sec = new TpsRollingAverage(5); - private final TpsRollingAverage tps10Sec = new TpsRollingAverage(10); - private final TpsRollingAverage tps1Min = new TpsRollingAverage(60); - private final TpsRollingAverage tps5Min = new TpsRollingAverage(60 * 5); - private final TpsRollingAverage tps15Min = new TpsRollingAverage(60 * 15); - private final TpsRollingAverage[] tpsAverages = {this.tps5Sec, this.tps10Sec, this.tps1Min, this.tps5Min, this.tps15Min}; - - private boolean durationSupported = false; - private final RollingAverage tickDuration10Sec = new RollingAverage(TPS * 10); - private final RollingAverage tickDuration1Min = new RollingAverage(TPS * 60); - private final RollingAverage tickDuration5Min = new RollingAverage(TPS * 60 * 5); - private final RollingAverage[] tickDurationAverages = {this.tickDuration10Sec, this.tickDuration1Min, this.tickDuration5Min}; - - private long last = 0; - - public boolean isDurationSupported() { - return this.durationSupported; - } - - @Override - public void onTick(int currentTick) { - if (currentTick % TPS_SAMPLE_INTERVAL != 0) { - return; - } - - long now = System.nanoTime(); - - if (this.last == 0) { - this.last = now; - return; - } - - long diff = now - this.last; - BigDecimal currentTps = TPS_BASE.divide(new BigDecimal(diff), 30, RoundingMode.HALF_UP); - BigDecimal total = currentTps.multiply(new BigDecimal(diff)); - - for (TpsRollingAverage rollingAverage : this.tpsAverages) { - rollingAverage.add(currentTps, diff, total); - } - - this.last = now; - } - - @Override - public void onTick(double duration) { - this.durationSupported = true; - BigDecimal decimal = new BigDecimal(duration); - for (RollingAverage rollingAverage : this.tickDurationAverages) { - rollingAverage.add(decimal); - } - } - - public double tps5Sec() { - return this.tps5Sec.getAverage(); - } - - public double tps10Sec() { - return this.tps10Sec.getAverage(); - } - - public double tps1Min() { - return this.tps1Min.getAverage(); - } - - public double tps5Min() { - return this.tps5Min.getAverage(); - } - - public double tps15Min() { - return this.tps15Min.getAverage(); - } - - public RollingAverage duration10Sec() { - if (!this.durationSupported) { - return null; - } - return this.tickDuration10Sec; - } - - public RollingAverage duration1Min() { - if (!this.durationSupported) { - return null; - } - return this.tickDuration1Min; - } - - public RollingAverage duration5Min() { - if (!this.durationSupported) { - return null; - } - return this.tickDuration5Min; - } - - - /** - * Rolling average calculator. - * - *

This code is taken from PaperMC/Paper, licensed under MIT.

- * - * @author aikar (PaperMC) https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0021-Further-improve-server-tick-loop.patch - */ - public static final class TpsRollingAverage { - private final int size; - private long time; - private BigDecimal total; - private int index = 0; - private final BigDecimal[] samples; - private final long[] times; +public interface TickStatistics { - TpsRollingAverage(int size) { - this.size = size; - this.time = size * SEC_IN_NANO; - this.total = new BigDecimal(TPS).multiply(new BigDecimal(SEC_IN_NANO)).multiply(new BigDecimal(size)); - this.samples = new BigDecimal[size]; - this.times = new long[size]; - for (int i = 0; i < size; i++) { - this.samples[i] = new BigDecimal(TPS); - this.times[i] = SEC_IN_NANO; - } - } + double tps5Sec(); + double tps10Sec(); + double tps1Min(); + double tps5Min(); + double tps15Min(); - public void add(BigDecimal x, long t, BigDecimal total) { - this.time -= this.times[this.index]; - this.total = this.total.subtract(this.samples[this.index].multiply(new BigDecimal(this.times[this.index]))); - this.samples[this.index] = x; - this.times[this.index] = t; - this.time += t; - this.total = this.total.add(total); - if (++this.index == this.size) { - this.index = 0; - } - } + boolean isDurationSupported(); - public double getAverage() { - return this.total.divide(new BigDecimal(this.time), 30, RoundingMode.HALF_UP).doubleValue(); - } - } + DoubleAverageInfo duration10Sec(); + DoubleAverageInfo duration1Min(); + DoubleAverageInfo duration5Min(); } diff --git a/spark-common/src/main/java/me/lucko/spark/common/platform/PlatformStatisticsProvider.java b/spark-common/src/main/java/me/lucko/spark/common/platform/PlatformStatisticsProvider.java index 059590d..b0987c9 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/platform/PlatformStatisticsProvider.java +++ b/spark-common/src/main/java/me/lucko/spark/common/platform/PlatformStatisticsProvider.java @@ -20,6 +20,7 @@ package me.lucko.spark.common.platform; +import me.lucko.spark.api.statistic.misc.DoubleAverageInfo; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.monitor.cpu.CpuInfo; import me.lucko.spark.common.monitor.cpu.CpuMonitor; @@ -33,6 +34,7 @@ import me.lucko.spark.common.monitor.ping.PingStatistics; import me.lucko.spark.common.monitor.tick.TickStatistics; import me.lucko.spark.common.platform.world.AsyncWorldInfoProvider; import me.lucko.spark.common.platform.world.WorldStatisticsProvider; +import me.lucko.spark.proto.SparkProtos; import me.lucko.spark.proto.SparkProtos.PlatformStatistics; import me.lucko.spark.proto.SparkProtos.SystemStatistics; import me.lucko.spark.proto.SparkProtos.WorldStatistics; @@ -118,10 +120,10 @@ public class PlatformStatisticsProvider { networkInterfaceStats.forEach((name, statistics) -> builder.putNet( name, SystemStatistics.NetInterface.newBuilder() - .setRxBytesPerSecond(statistics.rxBytesPerSecond().toProto()) - .setRxPacketsPerSecond(statistics.rxPacketsPerSecond().toProto()) - .setTxBytesPerSecond(statistics.txBytesPerSecond().toProto()) - .setTxPacketsPerSecond(statistics.txPacketsPerSecond().toProto()) + .setRxBytesPerSecond(rollingAvgProto(statistics.rxBytesPerSecond())) + .setRxPacketsPerSecond(rollingAvgProto(statistics.rxPacketsPerSecond())) + .setTxBytesPerSecond(rollingAvgProto(statistics.txBytesPerSecond())) + .setTxPacketsPerSecond(rollingAvgProto(statistics.txPacketsPerSecond())) .build() )); @@ -166,8 +168,8 @@ public class PlatformStatisticsProvider { ); if (tickStatistics.isDurationSupported()) { builder.setMspt(PlatformStatistics.Mspt.newBuilder() - .setLast1M(tickStatistics.duration1Min().toProto()) - .setLast5M(tickStatistics.duration5Min().toProto()) + .setLast1M(rollingAvgProto(tickStatistics.duration1Min())) + .setLast5M(rollingAvgProto(tickStatistics.duration5Min())) .build() ); } @@ -176,7 +178,7 @@ public class PlatformStatisticsProvider { PingStatistics pingStatistics = this.platform.getPingStatistics(); if (pingStatistics != null && pingStatistics.getPingAverage().getSamples() != 0) { builder.setPing(PlatformStatistics.Ping.newBuilder() - .setLast15M(pingStatistics.getPingAverage().toProto()) + .setLast15M(rollingAvgProto(pingStatistics.getPingAverage())) .build() ); } @@ -204,4 +206,14 @@ public class PlatformStatisticsProvider { return builder.build(); } + public static SparkProtos.RollingAverageValues rollingAvgProto(DoubleAverageInfo info) { + return SparkProtos.RollingAverageValues.newBuilder() + .setMean(info.mean()) + .setMax(info.max()) + .setMin(info.min()) + .setMedian(info.median()) + .setPercentile95(info.percentile95th()) + .build(); + } + } diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/window/WindowStatisticsCollector.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/window/WindowStatisticsCollector.java index 7acbd6b..86c0b20 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/window/WindowStatisticsCollector.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/window/WindowStatisticsCollector.java @@ -20,13 +20,13 @@ package me.lucko.spark.common.sampler.window; +import me.lucko.spark.api.statistic.misc.DoubleAverageInfo; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.monitor.cpu.CpuMonitor; import me.lucko.spark.common.monitor.tick.TickStatistics; import me.lucko.spark.common.platform.world.AsyncWorldInfoProvider; import me.lucko.spark.common.platform.world.WorldInfoProvider; import me.lucko.spark.common.tick.TickHook; -import me.lucko.spark.common.util.RollingAverage; import me.lucko.spark.proto.SparkProtos; import java.util.HashMap; @@ -165,7 +165,7 @@ public class WindowStatisticsCollector { if (tickStatistics != null) { builder.setTps(tickStatistics.tps1Min()); - RollingAverage mspt = tickStatistics.duration1Min(); + DoubleAverageInfo mspt = tickStatistics.duration1Min(); if (mspt != null) { builder.setMsptMedian(mspt.median()); builder.setMsptMax(mspt.max()); 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 index 65753bc..57dfdff 100644 --- 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 @@ -21,7 +21,6 @@ package me.lucko.spark.common.util; import me.lucko.spark.api.statistic.misc.DoubleAverageInfo; -import me.lucko.spark.proto.SparkProtos; import java.math.BigDecimal; import java.math.RoundingMode; @@ -112,14 +111,4 @@ public class RollingAverage implements DoubleAverageInfo { return sortedSamples[rank].doubleValue(); } - public SparkProtos.RollingAverageValues toProto() { - return SparkProtos.RollingAverageValues.newBuilder() - .setMean(mean()) - .setMax(max()) - .setMin(min()) - .setMedian(median()) - .setPercentile95(percentile95th()) - .build(); - } - } diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/StatisticFormatter.java b/spark-common/src/main/java/me/lucko/spark/common/util/StatisticFormatter.java index 22ee9bb..b488f50 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/StatisticFormatter.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/StatisticFormatter.java @@ -22,6 +22,8 @@ package me.lucko.spark.common.util; import com.google.common.base.Strings; +import me.lucko.spark.api.statistic.misc.DoubleAverageInfo; + import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.TextColor; @@ -55,7 +57,7 @@ public enum StatisticFormatter { return text((tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color); } - public static TextComponent formatTickDurations(RollingAverage average) { + public static TextComponent formatTickDurations(DoubleAverageInfo average) { return text() .append(formatTickDuration(average.min())) .append(text('/', GRAY)) -- cgit