diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java index 3f65ee241..3dfd8a78c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java @@ -15,6 +15,7 @@ import org.bukkit.entity.Player; import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand; import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector; +import io.github.thebusybiscuit.slimefun4.core.services.profiler.SummaryOrderType; import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.ConsolePerformanceInspector; import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.PlayerPerformanceInspector; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; @@ -22,7 +23,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; class TimingsCommand extends SubCommand { private static final String FLAG_PREFIX = "--"; - private final Set flags = new HashSet<>(Arrays.asList("verbose")); + private final Set flags = new HashSet<>(Arrays.asList("verbose", "avg", "low")); @ParametersAreNonnullByDefault TimingsCommand(Slimefun plugin, SlimefunCommand cmd) { @@ -30,31 +31,40 @@ class TimingsCommand extends SubCommand { } @Override - protected String getDescription() { + protected @Nonnull String getDescription() { return "commands.timings.description"; } @Override - public void onExecute(CommandSender sender, String[] args) { - if (sender.hasPermission("slimefun.command.timings") || sender instanceof ConsoleCommandSender) { - if (hasInvalidFlags(sender, args)) { - return; - } - - boolean verbose = hasFlag(args, "verbose"); - - if (verbose && sender instanceof Player) { - Slimefun.getLocalization().sendMessage(sender, "commands.timings.verbose-player", true); - return; - } - - Slimefun.getLocalization().sendMessage(sender, "commands.timings.please-wait", true); - - PerformanceInspector inspector = inspectorOf(sender, verbose); - Slimefun.getProfiler().requestSummary(inspector); - } else { + public void onExecute(CommandSender sender, @Nonnull String[] args) { + if (!sender.hasPermission("slimefun.command.timings") && !(sender instanceof ConsoleCommandSender)) { Slimefun.getLocalization().sendMessage(sender, "messages.no-permission", true); + return; } + + if (hasInvalidFlags(sender, args)) { + return; + } + + boolean verbose = hasFlag(args, "verbose"); + + if (verbose && sender instanceof Player) { + Slimefun.getLocalization().sendMessage(sender, "commands.timings.verbose-player", true); + return; + } + + SummaryOrderType orderType = SummaryOrderType.HIGHEST; + + if (hasFlag(args, "avg")) { + orderType = SummaryOrderType.AVERAGE; + } else if (hasFlag(args, "low")) { + orderType = SummaryOrderType.LOWEST; + } + + Slimefun.getLocalization().sendMessage(sender, "commands.timings.please-wait", true); + + PerformanceInspector inspector = inspectorOf(sender, verbose, orderType); + Slimefun.getProfiler().requestSummary(inspector); } @ParametersAreNonnullByDefault @@ -87,12 +97,12 @@ class TimingsCommand extends SubCommand { } @Nonnull - private PerformanceInspector inspectorOf(@Nonnull CommandSender sender, boolean verbose) { + @ParametersAreNonnullByDefault + private PerformanceInspector inspectorOf(CommandSender sender, boolean verbose, SummaryOrderType orderType) { if (sender instanceof Player player) { - return new PlayerPerformanceInspector(player); + return new PlayerPerformanceInspector(player, orderType); } else { - return new ConsolePerformanceInspector(sender, verbose); + return new ConsolePerformanceInspector(sender, verbose, orderType); } } - } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceInspector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceInspector.java index 6a8fd5900..984b207cf 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceInspector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceInspector.java @@ -38,4 +38,10 @@ public interface PerformanceInspector { */ boolean isVerbose(); + /** + * The order type for the summary of timings. + * + * @return The order type for the summary of timings. + */ + @Nonnull SummaryOrderType getOrderType(); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceSummary.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceSummary.java index 5883ef445..e41300b6a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceSummary.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceSummary.java @@ -1,12 +1,10 @@ package io.github.thebusybiscuit.slimefun4.core.services.profiler; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; @@ -64,13 +62,18 @@ class PerformanceSummary { summarizeTimings(totalTickedBlocks, "block", sender, items, entry -> { int count = profiler.getBlocksOfId(entry.getKey()); String time = NumberUtils.getAsMillis(entry.getValue()); + String message = entry.getKey() + " - " + count + "x (%s)"; - if (count > 1) { - String average = NumberUtils.getAsMillis(entry.getValue() / count); + if (count <= 1) { + return String.format(message, time); + } - return entry.getKey() + " - " + count + "x (" + time + " | avg: " + average + ')'; + String average = NumberUtils.getAsMillis(entry.getValue() / count); + + if (sender.getOrderType() == SummaryOrderType.AVERAGE) { + return String.format(message, average + " | total: " + time); } else { - return entry.getKey() + " - " + count + "x (" + time + ')'; + return String.format(message, time + " | avg: " + average); } }); @@ -91,8 +94,8 @@ class PerformanceSummary { @ParametersAreNonnullByDefault private void summarizeTimings(int count, String name, PerformanceInspector inspector, Map map, Function, String> formatter) { - Stream> stream = map.entrySet().stream(); - List> results = stream.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList()); + Set> entrySet = map.entrySet(); + List> results = inspector.getOrderType().sort(profiler, entrySet); String prefix = count + " " + name + (count != 1 ? 's' : ""); if (inspector instanceof PlayerPerformanceInspector playerPerformanceInspector) { @@ -181,22 +184,15 @@ class PerformanceSummary { rest--; } - builder.append(ChatColor.DARK_GRAY); - - for (int i = 0; i < rest; i++) { - builder.append(':'); - } - - builder.append(" - "); - - builder.append(rating.getColor() + ChatUtils.humanize(rating.name())); - - builder.append(ChatColor.GRAY); - builder.append(" ("); - builder.append(NumberUtils.roundDecimalNumber(percentage)); - builder.append("%)"); + builder.append(ChatColor.DARK_GRAY) + .append(":".repeat(Math.max(0, rest))) + .append(" - ") + .append(rating.getColor()).append(ChatUtils.humanize(rating.name())) + .append(ChatColor.GRAY) + .append(" (") + .append(NumberUtils.roundDecimalNumber(percentage)) + .append("%)"); return builder.toString(); } - } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SummaryOrderType.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SummaryOrderType.java new file mode 100644 index 000000000..2f1e2ef19 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SummaryOrderType.java @@ -0,0 +1,55 @@ +package io.github.thebusybiscuit.slimefun4.core.services.profiler; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Holds the different types of ordering for summaries. + * + * @author Walshy + */ +public enum SummaryOrderType { + + /** + * Sort by highest to the lowest total timings + */ + HIGHEST, + /** + * Sort by lowest to the highest total timings + */ + LOWEST, + /** + * Sort by average timings (highest to lowest) + */ + AVERAGE; + + @ParametersAreNonnullByDefault + List> sort(SlimefunProfiler profiler, Set> entrySet) { + switch(this) { + case HIGHEST: + return entrySet.stream() + .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) + .collect(Collectors.toList()); + case LOWEST: + return entrySet.stream() + .sorted(Comparator.comparingLong(Map.Entry::getValue)) + .collect(Collectors.toList()); + default: + final Map map = new HashMap<>(); + for (Map.Entry entry : entrySet) { + int count = profiler.getBlocksOfId(entry.getKey()); + long avg = count > 0 ? entry.getValue() / count : entry.getValue(); + + map.put(entry.getKey(), avg); + } + return map.entrySet().stream() + .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) + .collect(Collectors.toList()); + } + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/ConsolePerformanceInspector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/ConsolePerformanceInspector.java index 4520e0ec1..f4249a3cf 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/ConsolePerformanceInspector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/ConsolePerformanceInspector.java @@ -1,7 +1,9 @@ package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; +import io.github.thebusybiscuit.slimefun4.core.services.profiler.SummaryOrderType; import org.apache.commons.lang.Validate; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; @@ -28,35 +30,61 @@ public class ConsolePerformanceInspector implements PerformanceInspector { */ private final boolean verbose; + /** + * The order type of the timings. + */ + private final SummaryOrderType orderType; + /** * This creates a new {@link ConsolePerformanceInspector} for the given {@link CommandSender}. * * @param console - * The {@link CommandSender}, preferabbly a {@link ConsoleCommandSender} + * The {@link CommandSender}, preferably a {@link ConsoleCommandSender} * @param verbose * Whether the summary will be verbose or not + * @param orderType + * The {@link SummaryOrderType} of the timings */ - public ConsolePerformanceInspector(@Nonnull CommandSender console, boolean verbose) { + @ParametersAreNonnullByDefault + public ConsolePerformanceInspector(CommandSender console, boolean verbose, SummaryOrderType orderType) { Validate.notNull(console, "CommandSender cannot be null"); + Validate.notNull(orderType, "SummaryOrderType cannot be null"); this.console = console; this.verbose = verbose; + this.orderType = orderType; } + /** + * {@inheritDoc} + */ @Override public boolean isValid() { // The console is always "online". return true; } + /** + * {@inheritDoc} + */ @Override public boolean isVerbose() { return verbose; } + /** + * {@inheritDoc} + */ + @Override + public @Nonnull SummaryOrderType getOrderType() { + return orderType; + } + + /** + * {@inheritDoc} + */ @Override public void sendMessage(@Nonnull String msg) { console.sendMessage(msg); } - } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/PlayerPerformanceInspector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/PlayerPerformanceInspector.java index 51a44ab6c..8ce7811e3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/PlayerPerformanceInspector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/inspectors/PlayerPerformanceInspector.java @@ -5,6 +5,7 @@ import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import io.github.thebusybiscuit.slimefun4.core.services.profiler.SummaryOrderType; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -27,34 +28,62 @@ public class PlayerPerformanceInspector implements PerformanceInspector { */ private final UUID uuid; + /** + * The order type of the timings. + */ + private final SummaryOrderType orderType; + /** * This creates a new {@link PlayerPerformanceInspector} for the given {@link Player}. * * @param player * The {@link Player} + * @param orderType + * The {@link SummaryOrderType} of the timings */ - public PlayerPerformanceInspector(@Nonnull Player player) { + public PlayerPerformanceInspector(@Nonnull Player player, @Nonnull SummaryOrderType orderType) { Validate.notNull(player, "Player cannot be null"); + Validate.notNull(orderType, "SummaryOrderType cannot be null"); this.uuid = player.getUniqueId(); + this.orderType = orderType; } - @Nullable - private Player getPlayer() { + /** + * {@inheritDoc} + */ + private @Nullable Player getPlayer() { return Bukkit.getPlayer(uuid); } + /** + * {@inheritDoc} + */ @Override public boolean isValid() { Player player = getPlayer(); return player != null && player.isOnline(); } + /** + * {@inheritDoc} + */ @Override public boolean isVerbose() { return false; } + /** + * {@inheritDoc} + */ + @Override + public @Nonnull SummaryOrderType getOrderType() { + return orderType; + } + + /** + * {@inheritDoc} + */ @Override public void sendMessage(@Nonnull String msg) { Player player = getPlayer();