From bfbbcb3e68e019da4657ef0da22b889de656ae3f Mon Sep 17 00:00:00 2001 From: Luck Date: Tue, 28 Dec 2021 18:12:33 +0000 Subject: Include platform and system statistics in profiler viewer payload --- .../me/lucko/spark/common/util/Compression.java | 100 +++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/Compression.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/Compression.java b/spark-common/src/main/java/me/lucko/spark/common/util/Compression.java new file mode 100644 index 0000000..9295c25 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/Compression.java @@ -0,0 +1,100 @@ +/* + * 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; + +import org.tukaani.xz.LZMA2Options; +import org.tukaani.xz.LZMAOutputStream; +import org.tukaani.xz.XZOutputStream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.LongConsumer; +import java.util.zip.GZIPOutputStream; + +public enum Compression { + GZIP { + @Override + public Path compress(Path file, LongConsumer progressHandler) throws IOException { + Path compressedFile = file.getParent().resolve(file.getFileName().toString() + ".gz"); + try (InputStream in = Files.newInputStream(file)) { + try (OutputStream out = Files.newOutputStream(compressedFile)) { + try (GZIPOutputStream compressionOut = new GZIPOutputStream(out, 1024 * 64)) { + copy(in, compressionOut, progressHandler); + } + } + } + return compressedFile; + } + }, + XZ { + @Override + public Path compress(Path file, LongConsumer progressHandler) throws IOException { + Path compressedFile = file.getParent().resolve(file.getFileName().toString() + ".xz"); + try (InputStream in = Files.newInputStream(file)) { + try (OutputStream out = Files.newOutputStream(compressedFile)) { + try (XZOutputStream compressionOut = new XZOutputStream(out, new LZMA2Options())) { + copy(in, compressionOut, progressHandler); + } + } + } + return compressedFile; + } + }, + LZMA { + @Override + public Path compress(Path file, LongConsumer progressHandler) throws IOException { + Path compressedFile = file.getParent().resolve(file.getFileName().toString() + ".lzma"); + try (InputStream in = Files.newInputStream(file)) { + try (OutputStream out = Files.newOutputStream(compressedFile)) { + try (LZMAOutputStream compressionOut = new LZMAOutputStream(out, new LZMA2Options(), true)) { + copy(in, compressionOut, progressHandler); + } + } + } + return compressedFile; + } + }; + + public abstract Path compress(Path file, LongConsumer progressHandler) throws IOException; + + private static long copy(InputStream from, OutputStream to, LongConsumer progress) throws IOException { + byte[] buf = new byte[1024 * 64]; + long total = 0; + long iterations = 0; + while (true) { + int r = from.read(buf); + if (r == -1) { + break; + } + to.write(buf, 0, r); + total += r; + + // report progress every 5MB + if (iterations++ % ((1024 / 64) * 5) == 0) { + progress.accept(total); + } + } + return total; + } +} -- cgit From 1dd973f7317734d47dcb9879070daee76ca4b6b7 Mon Sep 17 00:00:00 2001 From: Luck Date: Tue, 28 Dec 2021 22:31:49 +0000 Subject: Add timeout thread to detect stuck commands --- .../spark/common/util/SparkThreadFactory.java | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.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/SparkThreadFactory.java b/spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.java new file mode 100644 index 0000000..9c7309d --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.java @@ -0,0 +1,42 @@ +/* + * 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; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +public class SparkThreadFactory implements ThreadFactory { + private static final AtomicInteger poolNumber = new AtomicInteger(1); + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + public SparkThreadFactory() { + this.namePrefix = "spark-worker-pool-" + + poolNumber.getAndIncrement() + + "-thread-"; + } + + public Thread newThread(Runnable r) { + Thread t = new Thread(r, this.namePrefix + this.threadNumber.getAndIncrement()); + t.setDaemon(true); + return t; + } +} -- cgit From d2716da1dc7f61aa45c0058e9a8fd65aa858f3c8 Mon Sep 17 00:00:00 2001 From: Luck Date: Thu, 20 Jan 2022 20:22:02 +0000 Subject: Add ping statistics and command --- .../me/lucko/spark/common/util/RollingAverage.java | 6 + .../spark/common/util/StatisticFormatter.java | 187 +++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/StatisticFormatter.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/RollingAverage.java b/spark-common/src/main/java/me/lucko/spark/common/util/RollingAverage.java index 87c41a4..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 @@ -39,6 +39,12 @@ public class RollingAverage implements DoubleAverageInfo { this.samples = new ArrayDeque<>(this.windowSize + 1); } + public int getSamples() { + synchronized (this) { + return this.samples.size(); + } + } + public void add(BigDecimal num) { synchronized (this) { this.total = this.total.add(num); 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 new file mode 100644 index 0000000..9a2850e --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/StatisticFormatter.java @@ -0,0 +1,187 @@ +/* + * 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; + +import com.google.common.base.Strings; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.TextColor; + +import java.lang.management.MemoryUsage; + +import static net.kyori.adventure.text.Component.text; +import static net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY; +import static net.kyori.adventure.text.format.NamedTextColor.GRAY; +import static net.kyori.adventure.text.format.NamedTextColor.GREEN; +import static net.kyori.adventure.text.format.NamedTextColor.RED; +import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; + +public enum StatisticFormatter { + ; + + private static final String BAR_CHARACTER = "|"; + + public static TextComponent formatTps(double tps) { + TextColor color; + if (tps > 18.0) { + color = GREEN; + } else if (tps > 16.0) { + color = YELLOW; + } else { + color = RED; + } + + return text((tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color); + } + + public static TextComponent formatTickDurations(RollingAverage average) { + return text() + .append(formatTickDuration(average.min())) + .append(text('/', GRAY)) + .append(formatTickDuration(average.median())) + .append(text('/', GRAY)) + .append(formatTickDuration(average.percentile95th())) + .append(text('/', GRAY)) + .append(formatTickDuration(average.max())) + .build(); + } + + public static TextComponent formatTickDuration(double duration) { + TextColor color; + if (duration >= 50d) { + color = RED; + } else if (duration >= 40d) { + color = YELLOW; + } else { + color = GREEN; + } + + return text(String.format("%.1f", duration), color); + } + + public static TextComponent formatCpuUsage(double usage) { + TextColor color; + if (usage > 0.9) { + color = RED; + } else if (usage > 0.65) { + color = YELLOW; + } else { + color = GREEN; + } + + return text(FormatUtil.percent(usage, 1d), color); + } + + public static TextComponent formatPingRtts(double min, double median, double percentile95th, double max) { + return text() + .append(formatPingRtt(min)) + .append(text('/', GRAY)) + .append(formatPingRtt(median)) + .append(text('/', GRAY)) + .append(formatPingRtt(percentile95th)) + .append(text('/', GRAY)) + .append(formatPingRtt(max)) + .build(); + } + + public static TextComponent formatPingRtt(double ping) { + TextColor color; + if (ping >= 200) { + color = RED; + } else if (ping >= 100) { + color = YELLOW; + } else { + color = GREEN; + } + + return text((int) Math.ceil(ping), color); + } + + public static TextComponent generateMemoryUsageDiagram(MemoryUsage usage, int length) { + double used = usage.getUsed(); + double committed = usage.getCommitted(); + double max = usage.getMax(); + + int usedChars = (int) ((used * length) / max); + int committedChars = (int) ((committed * length) / max); + + TextComponent.Builder line = text().content(Strings.repeat(BAR_CHARACTER, usedChars)).color(YELLOW); + if (committedChars > usedChars) { + line.append(text(Strings.repeat(BAR_CHARACTER, (committedChars - usedChars) - 1), GRAY)); + line.append(Component.text(BAR_CHARACTER, RED)); + } + if (length > committedChars) { + line.append(text(Strings.repeat(BAR_CHARACTER, (length - committedChars)), GRAY)); + } + + return text() + .append(text("[", DARK_GRAY)) + .append(line.build()) + .append(text("]", DARK_GRAY)) + .build(); + } + + public static TextComponent generateMemoryPoolDiagram(MemoryUsage usage, MemoryUsage collectionUsage, int length) { + double used = usage.getUsed(); + double collectionUsed = used; + if (collectionUsage != null) { + collectionUsed = collectionUsage.getUsed(); + } + double committed = usage.getCommitted(); + double max = usage.getMax(); + + int usedChars = (int) ((used * length) / max); + int collectionUsedChars = (int) ((collectionUsed * length) / max); + int committedChars = (int) ((committed * length) / max); + + TextComponent.Builder line = text().content(Strings.repeat(BAR_CHARACTER, collectionUsedChars)).color(YELLOW); + + if (usedChars > collectionUsedChars) { + line.append(Component.text(BAR_CHARACTER, RED)); + line.append(text(Strings.repeat(BAR_CHARACTER, (usedChars - collectionUsedChars) - 1), YELLOW)); + } + if (committedChars > usedChars) { + line.append(text(Strings.repeat(BAR_CHARACTER, (committedChars - usedChars) - 1), GRAY)); + line.append(Component.text(BAR_CHARACTER, YELLOW)); + } + if (length > committedChars) { + line.append(text(Strings.repeat(BAR_CHARACTER, (length - committedChars)), GRAY)); + } + + return text() + .append(text("[", DARK_GRAY)) + .append(line.build()) + .append(text("]", DARK_GRAY)) + .build(); + } + + public static TextComponent generateDiskUsageDiagram(double used, double max, int length) { + int usedChars = (int) ((used * length) / max); + int freeChars = length - usedChars; + return text() + .append(text("[", DARK_GRAY)) + .append(text(Strings.repeat(BAR_CHARACTER, usedChars), YELLOW)) + .append(text(Strings.repeat(BAR_CHARACTER, freeChars), GRAY)) + .append(text("]", DARK_GRAY)) + .build(); + } +} -- cgit From ef490d2c00af0c8d549c111654619ee57b1b9d87 Mon Sep 17 00:00:00 2001 From: Luck Date: Fri, 28 Jan 2022 18:23:43 +0000 Subject: Change textual diagram characters --- .../spark/common/util/StatisticFormatter.java | 27 +++++++++++----------- 1 file changed, 14 insertions(+), 13 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/StatisticFormatter.java b/spark-common/src/main/java/me/lucko/spark/common/util/StatisticFormatter.java index 9a2850e..24e49fa 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 @@ -38,7 +38,8 @@ import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; public enum StatisticFormatter { ; - private static final String BAR_CHARACTER = "|"; + private static final String BAR_TRUE_CHARACTER = "┃"; + private static final String BAR_FALSE_CHARACTER = "╻"; public static TextComponent formatTps(double tps) { TextColor color; @@ -124,13 +125,13 @@ public enum StatisticFormatter { int usedChars = (int) ((used * length) / max); int committedChars = (int) ((committed * length) / max); - TextComponent.Builder line = text().content(Strings.repeat(BAR_CHARACTER, usedChars)).color(YELLOW); + TextComponent.Builder line = text().content(Strings.repeat(BAR_TRUE_CHARACTER, usedChars)).color(YELLOW); if (committedChars > usedChars) { - line.append(text(Strings.repeat(BAR_CHARACTER, (committedChars - usedChars) - 1), GRAY)); - line.append(Component.text(BAR_CHARACTER, RED)); + line.append(text(Strings.repeat(BAR_FALSE_CHARACTER, (committedChars - usedChars) - 1), GRAY)); + line.append(Component.text(BAR_FALSE_CHARACTER, RED)); } if (length > committedChars) { - line.append(text(Strings.repeat(BAR_CHARACTER, (length - committedChars)), GRAY)); + line.append(text(Strings.repeat(BAR_FALSE_CHARACTER, (length - committedChars)), GRAY)); } return text() @@ -153,18 +154,18 @@ public enum StatisticFormatter { int collectionUsedChars = (int) ((collectionUsed * length) / max); int committedChars = (int) ((committed * length) / max); - TextComponent.Builder line = text().content(Strings.repeat(BAR_CHARACTER, collectionUsedChars)).color(YELLOW); + TextComponent.Builder line = text().content(Strings.repeat(BAR_TRUE_CHARACTER, collectionUsedChars)).color(YELLOW); if (usedChars > collectionUsedChars) { - line.append(Component.text(BAR_CHARACTER, RED)); - line.append(text(Strings.repeat(BAR_CHARACTER, (usedChars - collectionUsedChars) - 1), YELLOW)); + line.append(Component.text(BAR_TRUE_CHARACTER, RED)); + line.append(text(Strings.repeat(BAR_TRUE_CHARACTER, (usedChars - collectionUsedChars) - 1), YELLOW)); } if (committedChars > usedChars) { - line.append(text(Strings.repeat(BAR_CHARACTER, (committedChars - usedChars) - 1), GRAY)); - line.append(Component.text(BAR_CHARACTER, YELLOW)); + line.append(text(Strings.repeat(BAR_FALSE_CHARACTER, (committedChars - usedChars) - 1), GRAY)); + line.append(Component.text(BAR_FALSE_CHARACTER, YELLOW)); } if (length > committedChars) { - line.append(text(Strings.repeat(BAR_CHARACTER, (length - committedChars)), GRAY)); + line.append(text(Strings.repeat(BAR_FALSE_CHARACTER, (length - committedChars)), GRAY)); } return text() @@ -179,8 +180,8 @@ public enum StatisticFormatter { int freeChars = length - usedChars; return text() .append(text("[", DARK_GRAY)) - .append(text(Strings.repeat(BAR_CHARACTER, usedChars), YELLOW)) - .append(text(Strings.repeat(BAR_CHARACTER, freeChars), GRAY)) + .append(text(Strings.repeat(BAR_TRUE_CHARACTER, usedChars), YELLOW)) + .append(text(Strings.repeat(BAR_FALSE_CHARACTER, freeChars), GRAY)) .append(text("]", DARK_GRAY)) .build(); } -- cgit From 25f46b649363d99f51b1b5262b5f7c0ce0c3251b Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 6 Feb 2022 20:25:07 +0000 Subject: Improve build tooling - add version to output file name - check license headers automatically --- .../me/lucko/spark/common/util/BytebinClient.java | 27 +++++++++------------- 1 file changed, 11 insertions(+), 16 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 29ee5bb..c2ca1b1 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 @@ -1,26 +1,21 @@ /* - * This file is part of bytebin, licensed under the MIT License. + * This file is part of spark. * * Copyright (c) lucko (Luck) * Copyright (c) contributors * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * 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. * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * 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. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * 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; -- cgit From f54a31e9d4756c12836d5e42c31d3d100546533d Mon Sep 17 00:00:00 2001 From: Luck Date: Sat, 12 Feb 2022 00:14:02 +0000 Subject: Add class source lookups for Sponge8 --- .../lucko/spark/common/util/ClassSourceLookup.java | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 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/ClassSourceLookup.java b/spark-common/src/main/java/me/lucko/spark/common/util/ClassSourceLookup.java index 42a04f7..bd9ec37 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/ClassSourceLookup.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/ClassSourceLookup.java @@ -26,6 +26,7 @@ import me.lucko.spark.common.sampler.node.ThreadNode; import org.checkerframework.checker.nullness.qual.Nullable; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; @@ -87,8 +88,22 @@ public interface ClassSourceLookup { */ interface ByUrl extends ClassSourceLookup { - default String identifyUrl(URL url) throws URISyntaxException { - return url.getProtocol().equals("file") ? identifyFile(Paths.get(url.toURI())) : null; + default String identifyUrl(URL url) throws URISyntaxException, MalformedURLException { + Path path = null; + + String protocol = url.getProtocol(); + if (protocol.equals("file")) { + path = Paths.get(url.toURI()); + } else if (protocol.equals("jar")) { + URL innerUrl = new URL(url.getPath()); + path = Paths.get(innerUrl.getPath().split("!")[0]); + } + + if (path != null) { + return identifyFile(path.toAbsolutePath().normalize()); + } + + return null; } default String identifyFile(Path path) { @@ -123,7 +138,7 @@ public interface ClassSourceLookup { */ class ByCodeSource implements ClassSourceLookup, ByUrl { @Override - public @Nullable String identify(Class clazz) throws URISyntaxException { + public @Nullable String identify(Class clazz) throws URISyntaxException, MalformedURLException { ProtectionDomain protectionDomain = clazz.getProtectionDomain(); if (protectionDomain == null) { return null; @@ -148,12 +163,12 @@ public interface ClassSourceLookup { static Visitor createVisitor(ClassSourceLookup lookup) { if (lookup == ClassSourceLookup.NO_OP) { - return NoOpVistitor.INSTANCE; // don't bother! + return NoOpVisitor.INSTANCE; // don't bother! } return new VisitorImpl(lookup); } - enum NoOpVistitor implements Visitor { + enum NoOpVisitor implements Visitor { INSTANCE; @Override -- cgit From 2c219289bd4815a1c3987f4a0bc68c453f3f3efa Mon Sep 17 00:00:00 2001 From: Luck Date: Wed, 16 Mar 2022 20:29:37 +0000 Subject: Show 'available' physical memory instead of 'free' --- .../java/me/lucko/spark/common/util/LinuxProc.java | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 spark-common/src/main/java/me/lucko/spark/common/util/LinuxProc.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/LinuxProc.java b/spark-common/src/main/java/me/lucko/spark/common/util/LinuxProc.java new file mode 100644 index 0000000..0926ae7 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/LinuxProc.java @@ -0,0 +1,79 @@ +/* + * 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; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; + +/** + * Utility for reading from /proc/ on Linux systems. + */ +public enum LinuxProc { + + /** + * Information about the system CPU. + */ + CPUINFO("/proc/cpuinfo"), + + /** + * Information about the system memory. + */ + MEMINFO("/proc/meminfo"); + + private final Path path; + + LinuxProc(String path) { + this.path = resolvePath(path); + } + + private static @Nullable Path resolvePath(String path) { + try { + Path p = Paths.get(path); + if (Files.isReadable(p)) { + return p; + } + } catch (Exception e) { + // ignore + } + return null; + } + + public @NonNull List read() { + if (this.path != null) { + try { + return Files.readAllLines(this.path, StandardCharsets.UTF_8); + } catch (IOException e) { + // ignore + } + } + + return Collections.emptyList(); + } + +} -- cgit From 45edd6197aa777d0c746f37a813d6be4ca916694 Mon Sep 17 00:00:00 2001 From: Luck Date: Mon, 18 Apr 2022 11:54:40 +0100 Subject: Include network interface statistics in '/spark health' command --- .../me/lucko/spark/common/util/FormatUtil.java | 23 ++++++++++++++++++++++ .../java/me/lucko/spark/common/util/LinuxProc.java | 7 ++++++- .../me/lucko/spark/common/util/RollingAverage.java | 11 +++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) (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/FormatUtil.java b/spark-common/src/main/java/me/lucko/spark/common/util/FormatUtil.java index 492d4ea..cbc496d 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/FormatUtil.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/FormatUtil.java @@ -20,6 +20,9 @@ package me.lucko.spark.common.util; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; + public enum FormatUtil { ; @@ -37,4 +40,24 @@ public enum FormatUtil { int sizeIndex = (int) (Math.log(bytes) / Math.log(1024)); return String.format("%.1f", bytes / Math.pow(1024, sizeIndex)) + " " + SIZE_UNITS[sizeIndex]; } + + public static Component formatBytes(long bytes, TextColor color, String suffix) { + String value; + String unit; + + if (bytes == 0) { + value = "0"; + unit = "KB" + suffix; + } else { + int sizeIndex = (int) (Math.log(bytes) / Math.log(1024)); + value = String.format("%.1f", bytes / Math.pow(1024, sizeIndex)); + unit = SIZE_UNITS[sizeIndex] + suffix; + } + + return Component.text() + .append(Component.text(value, color)) + .append(Component.space()) + .append(Component.text(unit)) + .build(); + } } diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/LinuxProc.java b/spark-common/src/main/java/me/lucko/spark/common/util/LinuxProc.java index 0926ae7..7d688d7 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/LinuxProc.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/LinuxProc.java @@ -44,7 +44,12 @@ public enum LinuxProc { /** * Information about the system memory. */ - MEMINFO("/proc/meminfo"); + MEMINFO("/proc/meminfo"), + + /** + * Information about the system network usage. + */ + NET_DEV("/proc/net/dev"); private final Path path; 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 57dfdff..65753bc 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,6 +21,7 @@ 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; @@ -111,4 +112,14 @@ 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(); + } + } -- cgit From 86a312842662ba57faa8fd5e8471672dfac13089 Mon Sep 17 00:00:00 2001 From: Luck Date: Tue, 19 Apr 2022 12:45:46 +0100 Subject: Fix /proc/net output parsing and number formatting (#195) --- .../src/main/java/me/lucko/spark/common/util/FormatUtil.java | 10 ++++++---- .../java/me/lucko/spark/common/util/StatisticFormatter.java | 3 ++- 2 files changed, 8 insertions(+), 5 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/FormatUtil.java b/spark-common/src/main/java/me/lucko/spark/common/util/FormatUtil.java index cbc496d..c4a3d66 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/util/FormatUtil.java +++ b/spark-common/src/main/java/me/lucko/spark/common/util/FormatUtil.java @@ -23,6 +23,8 @@ package me.lucko.spark.common.util; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; +import java.util.Locale; + public enum FormatUtil { ; @@ -34,23 +36,23 @@ public enum FormatUtil { } public static String formatBytes(long bytes) { - if (bytes == 0) { + if (bytes <= 0) { return "0 bytes"; } int sizeIndex = (int) (Math.log(bytes) / Math.log(1024)); - return String.format("%.1f", bytes / Math.pow(1024, sizeIndex)) + " " + SIZE_UNITS[sizeIndex]; + return String.format(Locale.ENGLISH, "%.1f", bytes / Math.pow(1024, sizeIndex)) + " " + SIZE_UNITS[sizeIndex]; } public static Component formatBytes(long bytes, TextColor color, String suffix) { String value; String unit; - if (bytes == 0) { + if (bytes <= 0) { value = "0"; unit = "KB" + suffix; } else { int sizeIndex = (int) (Math.log(bytes) / Math.log(1024)); - value = String.format("%.1f", bytes / Math.pow(1024, sizeIndex)); + value = String.format(Locale.ENGLISH, "%.1f", bytes / Math.pow(1024, sizeIndex)); unit = SIZE_UNITS[sizeIndex] + suffix; } 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 24e49fa..22ee9bb 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 @@ -27,6 +27,7 @@ import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.TextColor; import java.lang.management.MemoryUsage; +import java.util.Locale; import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY; @@ -76,7 +77,7 @@ public enum StatisticFormatter { color = GREEN; } - return text(String.format("%.1f", duration), color); + return text(String.format(Locale.ENGLISH, "%.1f", duration), color); } public static TextComponent formatCpuUsage(double usage) { -- cgit From b077100667c1dee6e73da399e3484f92bbf67cb8 Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 24 Apr 2022 17:25:47 +0100 Subject: Fix NPE caused by initialisation order on Forge/Fabric --- .../main/java/me/lucko/spark/common/util/SparkThreadFactory.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (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/SparkThreadFactory.java b/spark-common/src/main/java/me/lucko/spark/common/util/SparkThreadFactory.java index 9c7309d..156fa0d 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,7 @@ package me.lucko.spark.common.util; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; -public class SparkThreadFactory implements ThreadFactory { +public class SparkThreadFactory implements ThreadFactory, Thread.UncaughtExceptionHandler { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; @@ -36,7 +36,14 @@ public class SparkThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { Thread t = new Thread(r, this.namePrefix + this.threadNumber.getAndIncrement()); + t.setUncaughtExceptionHandler(this); 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