aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0359-Add-tick-times-API-and-mspt-command.patch
blob: 80ac508d517a211a1b7d3f20c3bf7666c3cad23f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sun, 5 Apr 2020 22:23:14 -0500
Subject: [PATCH] Add tick times API and /mspt command


diff --git a/src/main/java/io/papermc/paper/command/MSPTCommand.java b/src/main/java/io/papermc/paper/command/MSPTCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b5293b0c696ef21d0101493ffa41b60bf0bc86b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java
@@ -0,0 +1,102 @@
+package io.papermc.paper.command;
+
+import net.kyori.adventure.text.Component;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.Location;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.NamedTextColor.GOLD;
+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;
+
+@DefaultQualifier(NonNull.class)
+public final class MSPTCommand extends Command {
+    private static final DecimalFormat DF = new DecimalFormat("########0.0");
+    private static final Component SLASH = text("/");
+
+    public MSPTCommand(final String name) {
+        super(name);
+        this.description = "View server tick times";
+        this.usageMessage = "/mspt";
+        this.setPermission("bukkit.command.mspt");
+    }
+
+    @Override
+    public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean execute(CommandSender sender, String commandLabel, String[] args) {
+        if (!testPermission(sender)) return true;
+
+        MinecraftServer server = MinecraftServer.getServer();
+
+        List<Component> times = new ArrayList<>();
+        times.addAll(eval(server.tickTimes5s.getTimes()));
+        times.addAll(eval(server.tickTimes10s.getTimes()));
+        times.addAll(eval(server.tickTimes60s.getTimes()));
+
+        sender.sendMessage(text().content("Server tick times ").color(GOLD)
+            .append(text().color(YELLOW)
+                .append(
+                    text("("),
+                    text("avg", GRAY),
+                    text("/"),
+                    text("min", GRAY),
+                    text("/"),
+                    text("max", GRAY),
+                    text(")")
+                )
+            ).append(
+                text(" from last 5s"),
+                text(",", GRAY),
+                text(" 10s"),
+                text(",", GRAY),
+                text(" 1m"),
+                text(":", YELLOW)
+            )
+        );
+        sender.sendMessage(text().content("◴ ").color(GOLD)
+            .append(text().color(GRAY)
+                .append(
+                    times.get(0), SLASH, times.get(1), SLASH, times.get(2), text(", ", YELLOW),
+                    times.get(3), SLASH, times.get(4), SLASH, times.get(5), text(", ", YELLOW),
+                    times.get(6), SLASH, times.get(7), SLASH, times.get(8)
+                )
+            )
+        );
+        return true;
+    }
+
+    private static List<Component> eval(long[] times) {
+        long min = Integer.MAX_VALUE;
+        long max = 0L;
+        long total = 0L;
+        for (long value : times) {
+            if (value > 0L && value < min) min = value;
+            if (value > max) max = value;
+            total += value;
+        }
+        double avgD = ((double) total / (double) times.length) * 1.0E-6D;
+        double minD = ((double) min) * 1.0E-6D;
+        double maxD = ((double) max) * 1.0E-6D;
+        return Arrays.asList(getColor(avgD), getColor(minD), getColor(maxD));
+    }
+
+    private static Component getColor(double avg) {
+        return text(DF.format(avg), avg >= 50 ? RED : avg >= 40 ? YELLOW : GREEN);
+    }
+}
diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java
index d44d0074446c1c54e87dc8078dff7fef1d92f343..bbb8b1933ef33a3b91f69545f69dd3cfb84b27f5 100644
--- a/src/main/java/io/papermc/paper/command/PaperCommands.java
+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java
@@ -17,6 +17,7 @@ public final class PaperCommands {
     private static final Map<String, Command> COMMANDS = new HashMap<>();
     static {
         COMMANDS.put("paper", new PaperCommand("paper"));
+        COMMANDS.put("mspt", new MSPTCommand("mspt"));
     }
 
     public static void registerCommands(final MinecraftServer server) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index cd57953e31c1f0f51553be113d84760f24b061b0..36112a1ab7306deb3cc38b103f22f7c1b8f89206 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -251,6 +251,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
     private net.kyori.adventure.text.Component motd; // Paper - Adventure
     private int playerIdleTimeout;
     public final long[] tickTimes;
+    // Paper start
+    public final TickTimes tickTimes5s = new TickTimes(100);
+    public final TickTimes tickTimes10s = new TickTimes(200);
+    public final TickTimes tickTimes60s = new TickTimes(1200);
+    // Paper end
     @Nullable
     private KeyPair keyPair;
     @Nullable
@@ -1341,6 +1346,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
         this.averageTickTime = this.averageTickTime * 0.8F + (float) j / 1000000.0F * 0.19999999F;
         long k = Util.getNanos();
 
+        // Paper start
+        tickTimes5s.add(this.tickCount, j);
+        tickTimes10s.add(this.tickCount, j);
+        tickTimes60s.add(this.tickCount, j);
+        // Paper end
         this.frameTimer.logFrameDuration(k - i);
         this.profiler.pop();
         org.spigotmc.WatchdogThread.tick(); // Spigot
@@ -2571,4 +2581,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
     public static record ServerResourcePackInfo(String url, String hash, boolean isRequired, @Nullable Component prompt) {
 
     }
+
+    // Paper start
+    public static class TickTimes {
+        private final long[] times;
+
+        public TickTimes(int length) {
+            times = new long[length];
+        }
+
+        void add(int index, long time) {
+            times[index % times.length] = time;
+        }
+
+        public long[] getTimes() {
+            return times.clone();
+        }
+
+        public double getAverage() {
+            long total = 0L;
+            for (long value : times) {
+                total += value;
+            }
+            return ((double) total / (double) times.length) * 1.0E-6D;
+        }
+    }
+    // Paper end
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index f7d2193f7e182e64cd51d3f909e4f0505a388f48..6e1618f32f1b5a896fa647d857eed4356115dcdd 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2535,6 +2535,16 @@ public final class CraftServer implements Server {
                 net.minecraft.server.MinecraftServer.getServer().tps15.getAverage()
         };
     }
+
+    @Override
+    public long[] getTickTimes() {
+        return getServer().tickTimes5s.getTimes();
+    }
+
+    @Override
+    public double getAverageTickTime() {
+        return getServer().tickTimes5s.getAverage();
+    }
     // Paper end
 
     // Spigot start