Paper/Spigot-Server-Patches/0009-Timings-v2.patch
Aikar b2d81e21c5
Improve Chunk Prioritization and Internal Scheduler
In previous MC versions, we had a rather simple internal scheduler
for delayed tasks that would just keep pushing task back until desired
tick was reached.

The method it called to schedule the task changed behavior in 1.14, and now
this scheduler is not working nowhere near what it was supposed to be doing.

This was causing long delayed task to eat up CPU (In Oversleep for example)

Rewrite this to just use the CraftScheduler for scheduling delayed tasks.

Once this was fixed, it became quite clear the code that delayed ticket
additions for chunks based on distance was clearly not right, as it was
tested on the previous broken logic.

So the ticket delay process has been vastly revamped to be even smarter.
Chunks behind the player can load slower than the chunks in front of the player.
We also can delay ticket adding until one of its neighbors has loaded, as
this lets us get a smoother spiral out for the chunks (minus frustum intent).

Additionally on frustum previous commit inadvertently broke frustum trying to
fix an issue when the real fix lied elsewhere, so restore chunk priority so
it works again.
2020-06-09 03:17:25 -04:00

2291 lines
105 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 04:00:11 -0600
Subject: [PATCH] Timings v2
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
new file mode 100644
index 0000000000000000000000000000000000000000..a58ef60d9976b3afc50e94364cf474bd2e5fdfd6
--- /dev/null
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
@@ -0,0 +1,149 @@
+package co.aikar.timings;
+
+import com.google.common.collect.MapMaker;
+import net.minecraft.server.*;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.scheduler.BukkitTask;
+
+import org.bukkit.craftbukkit.scheduler.CraftTask;
+
+import java.util.Map;
+
+// TODO: Re-implement missing timers
+public final class MinecraftTimings {
+
+ public static final Timing serverOversleep = Timings.ofSafe("Server Oversleep");
+ public static final Timing playerListTimer = Timings.ofSafe("Player List");
+ public static final Timing commandFunctionsTimer = Timings.ofSafe("Command Functions");
+ public static final Timing connectionTimer = Timings.ofSafe("Connection Handler");
+ public static final Timing tickablesTimer = Timings.ofSafe("Tickables");
+ public static final Timing minecraftSchedulerTimer = Timings.ofSafe("Minecraft Scheduler");
+ public static final Timing bukkitSchedulerTimer = Timings.ofSafe("Bukkit Scheduler");
+ public static final Timing bukkitSchedulerPendingTimer = Timings.ofSafe("Bukkit Scheduler - Pending");
+ public static final Timing bukkitSchedulerFinishTimer = Timings.ofSafe("Bukkit Scheduler - Finishing");
+ public static final Timing chunkIOTickTimer = Timings.ofSafe("ChunkIOTick");
+ public static final Timing timeUpdateTimer = Timings.ofSafe("Time Update");
+ public static final Timing serverCommandTimer = Timings.ofSafe("Server Command");
+ public static final Timing savePlayers = Timings.ofSafe("Save Players");
+
+ public static final Timing tickEntityTimer = Timings.ofSafe("## tickEntity");
+ public static final Timing tickTileEntityTimer = Timings.ofSafe("## tickTileEntity");
+ public static final Timing packetProcessTimer = Timings.ofSafe("## Packet Processing");
+ public static final Timing scheduledBlocksTimer = Timings.ofSafe("## Scheduled Blocks");
+ public static final Timing structureGenerationTimer = Timings.ofSafe("Structure Generation");
+
+ public static final Timing processQueueTimer = Timings.ofSafe("processQueue");
+ public static final Timing processTasksTimer = Timings.ofSafe("processTasks");
+
+ public static final Timing playerCommandTimer = Timings.ofSafe("playerCommand");
+
+ public static final Timing entityActivationCheckTimer = Timings.ofSafe("entityActivationCheck");
+
+ public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update");
+ public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate");
+
+ private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
+
+ private MinecraftTimings() {}
+
+ public static Timing getInternalTaskName(String taskName) {
+ return Timings.ofSafe(taskName);
+ }
+
+ /**
+ * Gets a timer associated with a plugins tasks.
+ * @param bukkitTask
+ * @param period
+ * @return
+ */
+ public static Timing getPluginTaskTimings(BukkitTask bukkitTask, long period) {
+ if (!bukkitTask.isSync()) {
+ return NullTimingHandler.NULL;
+ }
+ Plugin plugin;
+
+ CraftTask craftTask = (CraftTask) bukkitTask;
+
+ final Class<?> taskClass = craftTask.getTaskClass();
+ if (bukkitTask.getOwner() != null) {
+ plugin = bukkitTask.getOwner();
+ } else {
+ plugin = TimingsManager.getPluginByClassloader(taskClass);
+ }
+
+ final String taskname = taskNameCache.computeIfAbsent(taskClass, clazz -> {
+ try {
+ String clsName = !clazz.isMemberClass()
+ ? clazz.getName()
+ : clazz.getCanonicalName();
+ if (clsName != null && clsName.contains("$Lambda$")) {
+ clsName = clsName.replaceAll("(Lambda\\$.*?)/.*", "$1");
+ }
+ return clsName != null ? clsName : "UnknownTask";
+ } catch (Throwable ex) {
+ new Exception("Error occurred detecting class name", ex).printStackTrace();
+ return "MangledClassFile";
+ }
+ });
+
+ StringBuilder name = new StringBuilder(64);
+ name.append("Task: ").append(taskname);
+ if (period > 0) {
+ name.append(" (interval:").append(period).append(")");
+ } else {
+ name.append(" (Single)");
+ }
+
+ if (plugin == null) {
+ return Timings.ofSafe(null, name.toString());
+ }
+
+ return Timings.ofSafe(plugin, name.toString());
+ }
+
+ /**
+ * Get a named timer for the specified entity type to track type specific timings.
+ * @param entity
+ * @return
+ */
+ public static Timing getEntityTimings(Entity entity) {
+ String entityType = entity.getClass().getName();
+ return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType, tickEntityTimer);
+ }
+
+ /**
+ * Get a named timer for the specified tile entity type to track type specific timings.
+ * @param entity
+ * @return
+ */
+ public static Timing getTileEntityTimings(TileEntity entity) {
+ String entityType = entity.getClass().getName();
+ return Timings.ofSafe("Minecraft", "## tickTileEntity - " + entityType, tickTileEntityTimer);
+ }
+ public static Timing getCancelTasksTimer() {
+ return Timings.ofSafe("Cancel Tasks");
+ }
+ public static Timing getCancelTasksTimer(Plugin plugin) {
+ return Timings.ofSafe(plugin, "Cancel Tasks");
+ }
+
+ public static void stopServer() {
+ TimingsManager.stopServer();
+ }
+
+ public static Timing getBlockTiming(Block block) {
+ return Timings.ofSafe("## Scheduled Block: " + block.toString(), scheduledBlocksTimer);
+ }
+/*
+ public static Timing getStructureTiming(StructureGenerator structureGenerator) {
+ return Timings.ofSafe("Structure Generator - " + structureGenerator.getName(), structureGenerationTimer);
+ }*/
+
+ public static Timing getPacketTiming(Packet packet) {
+ return Timings.ofSafe("## Packet - " + packet.getClass().getName(), packetProcessTimer);
+ }
+
+ public static Timing getCommandFunctionTiming(CustomFunction function) {
+ return Timings.ofSafe("Command Function - " + function.getMinecraftKey().toString());
+ }
+}
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4ebcf8f66197299256bd6b65710a1488c90ea41
--- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -0,0 +1,377 @@
+/*
+ * This file is licensed under the MIT License (MIT).
+ *
+ * Copyright (c) 2014 Daniel Ennis <http://aikar.co>
+ *
+ * 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:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+package co.aikar.timings;
+
+import com.google.common.collect.Sets;
+import net.minecraft.server.MinecraftServer;
+import org.apache.commons.lang.StringUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.MemorySection;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+import org.bukkit.entity.EntityType;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.zip.GZIPOutputStream;
+
+import static co.aikar.timings.TimingsManager.HISTORY;
+import static co.aikar.util.JSONUtil.appendObjectData;
+import static co.aikar.util.JSONUtil.createObject;
+import static co.aikar.util.JSONUtil.pair;
+import static co.aikar.util.JSONUtil.toArray;
+import static co.aikar.util.JSONUtil.toArrayMapper;
+import static co.aikar.util.JSONUtil.toObjectMapper;
+
+@SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
+public class TimingsExport extends Thread {
+
+ private final TimingsReportListener listeners;
+ private final Map out;
+ private final TimingHistory[] history;
+ private static long lastReport = 0;
+
+ private TimingsExport(TimingsReportListener listeners, Map out, TimingHistory[] history) {
+ super("Timings paste thread");
+ this.listeners = listeners;
+ this.out = out;
+ this.history = history;
+ }
+
+ /**
+ * Checks if any pending reports are being requested, and builds one if needed.
+ */
+ public static void reportTimings() {
+ if (Timings.requestingReport.isEmpty()) {
+ return;
+ }
+ TimingsReportListener listeners = new TimingsReportListener(Timings.requestingReport);
+ listeners.addConsoleIfNeeded();
+
+ Timings.requestingReport.clear();
+ long now = System.currentTimeMillis();
+ final long lastReportDiff = now - lastReport;
+ if (lastReportDiff < 60000) {
+ listeners.sendMessage(ChatColor.RED + "Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)");
+ listeners.done();
+ return;
+ }
+ final long lastStartDiff = now - TimingsManager.timingStart;
+ if (lastStartDiff < 180000) {
+ listeners.sendMessage(ChatColor.RED + "Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)");
+ listeners.done();
+ return;
+ }
+ listeners.sendMessage(ChatColor.GREEN + "Preparing Timings Report...");
+ lastReport = now;
+ Map parent = createObject(
+ // Get some basic system details about the server
+ pair("version", Bukkit.getVersion()),
+ pair("maxplayers", Bukkit.getMaxPlayers()),
+ pair("start", TimingsManager.timingStart / 1000),
+ pair("end", System.currentTimeMillis() / 1000),
+ pair("online-mode", Bukkit.getServer().getOnlineMode()),
+ pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000),
+ pair("datapacks", toArrayMapper(MinecraftServer.getServer().getResourcePackRepository().d(), pack -> {
+ // Don't feel like obf helper'ing these, non fatal if its temp missed.
+ return ChatColor.stripColor(CraftChatMessage.fromComponent(pack.a(true)));
+ }))
+ );
+ if (!TimingsManager.privacy) {
+ appendObjectData(parent,
+ pair("server", Bukkit.getUnsafe().getTimingsServerName()),
+ pair("motd", Bukkit.getServer().getMotd()),
+ pair("icon", Bukkit.getServer().getServerIcon().getData())
+ );
+ }
+
+ final Runtime runtime = Runtime.getRuntime();
+ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
+
+ OperatingSystemMXBean osInfo = ManagementFactory.getOperatingSystemMXBean();
+
+ parent.put("system", createObject(
+ pair("timingcost", getCost()),
+ pair("loadavg", osInfo.getSystemLoadAverage()),
+ pair("name", System.getProperty("os.name")),
+ pair("version", System.getProperty("os.version")),
+ pair("jvmversion", System.getProperty("java.version")),
+ pair("arch", System.getProperty("os.arch")),
+ pair("maxmem", runtime.maxMemory()),
+ pair("memory", createObject(
+ pair("heap", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().toString()),
+ pair("nonheap", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().toString()),
+ pair("finalizing", ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount())
+ )),
+ pair("cpu", runtime.availableProcessors()),
+ pair("runtime", runtimeBean.getUptime()),
+ pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")),
+ pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), input -> pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime()))))
+ )
+ );
+
+ parent.put("worlds", toObjectMapper(MinecraftServer.getServer().getWorlds(), world -> {
+ if (world.getWorldData().getName().equals("worldeditregentempworld")) return null;
+ return pair(world.getWorldData().getName(), createObject(
+ pair("gamerules", toObjectMapper(world.getWorld().getGameRules(), rule -> {
+ return pair(rule, world.getWorld().getGameRuleValue(rule));
+ })),
+ pair("ticking-distance", world.getChunkProvider().playerChunkMap.getEffectiveViewDistance())
+ ));
+ }));
+
+ Set<Material> tileEntityTypeSet = Sets.newHashSet();
+ Set<EntityType> entityTypeSet = Sets.newHashSet();
+
+ int size = HISTORY.size();
+ TimingHistory[] history = new TimingHistory[size + 1];
+ int i = 0;
+ for (TimingHistory timingHistory : HISTORY) {
+ tileEntityTypeSet.addAll(timingHistory.tileEntityTypeSet);
+ entityTypeSet.addAll(timingHistory.entityTypeSet);
+ history[i++] = timingHistory;
+ }
+
+ history[i] = new TimingHistory(); // Current snapshot
+ tileEntityTypeSet.addAll(history[i].tileEntityTypeSet);
+ entityTypeSet.addAll(history[i].entityTypeSet);
+
+
+ Map handlers = createObject();
+ Map groupData;
+ synchronized (TimingIdentifier.GROUP_MAP) {
+ for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) {
+ synchronized (group.handlers) {
+ for (TimingHandler id : group.handlers) {
+
+ if (!id.isTimed() && !id.isSpecial()) {
+ continue;
+ }
+
+ String name = id.identifier.name;
+ if (name.startsWith("##")) {
+ name = name.substring(3);
+ }
+ handlers.put(id.id, toArray(
+ group.id,
+ name
+ ));
+ }
+ }
+ }
+
+ groupData = toObjectMapper(
+ TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name));
+ }
+
+ parent.put("idmap", createObject(
+ pair("groups", groupData),
+ pair("handlers", handlers),
+ pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))),
+ pair("tileentity",
+ toObjectMapper(tileEntityTypeSet, input -> pair(input.ordinal(), input.name()))),
+ pair("entity",
+ toObjectMapper(entityTypeSet, input -> pair(input.ordinal(), input.name())))
+ ));
+
+ // Information about loaded plugins
+
+ parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(),
+ plugin -> pair(plugin.getName(), createObject(
+ pair("version", plugin.getDescription().getVersion()),
+ pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()),
+ pair("website", plugin.getDescription().getWebsite()),
+ pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", "))
+ ))));
+
+
+
+ // Information on the users Config
+
+ parent.put("config", createObject(
+ pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
+ pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
+ ));
+
+ new TimingsExport(listeners, parent, history).start();
+ }
+
+ static long getCost() {
+ // Benchmark the users System.nanotime() for cost basis
+ int passes = 100;
+ TimingHandler SAMPLER1 = Timings.ofSafe("Timings Sampler 1");
+ TimingHandler SAMPLER2 = Timings.ofSafe("Timings Sampler 2");
+ TimingHandler SAMPLER3 = Timings.ofSafe("Timings Sampler 3");
+ TimingHandler SAMPLER4 = Timings.ofSafe("Timings Sampler 4");
+ TimingHandler SAMPLER5 = Timings.ofSafe("Timings Sampler 5");
+ TimingHandler SAMPLER6 = Timings.ofSafe("Timings Sampler 6");
+
+ long start = System.nanoTime();
+ for (int i = 0; i < passes; i++) {
+ SAMPLER1.startTiming();
+ SAMPLER2.startTiming();
+ SAMPLER3.startTiming();
+ SAMPLER3.stopTiming();
+ SAMPLER4.startTiming();
+ SAMPLER5.startTiming();
+ SAMPLER6.startTiming();
+ SAMPLER6.stopTiming();
+ SAMPLER5.stopTiming();
+ SAMPLER4.stopTiming();
+ SAMPLER2.stopTiming();
+ SAMPLER1.stopTiming();
+ }
+ long timingsCost = (System.nanoTime() - start) / passes / 6;
+ SAMPLER1.reset(true);
+ SAMPLER2.reset(true);
+ SAMPLER3.reset(true);
+ SAMPLER4.reset(true);
+ SAMPLER5.reset(true);
+ SAMPLER6.reset(true);
+ return timingsCost;
+ }
+
+ private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) {
+
+ JSONObject object = new JSONObject();
+ for (String key : config.getKeys(false)) {
+ String fullKey = (parentKey != null ? parentKey + "." + key : key);
+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) {
+ continue;
+ }
+ final Object val = config.get(key);
+
+ object.put(key, valAsJSON(val, fullKey));
+ }
+ return object;
+ }
+
+ private static Object valAsJSON(Object val, final String parentKey) {
+ if (!(val instanceof MemorySection)) {
+ if (val instanceof List) {
+ Iterable<Object> v = (Iterable<Object>) val;
+ return toArrayMapper(v, input -> valAsJSON(input, parentKey));
+ } else {
+ return String.valueOf(val);
+ }
+ } else {
+ return mapAsJSON((ConfigurationSection) val, parentKey);
+ }
+ }
+
+ @Override
+ public void run() {
+ out.put("data", toArrayMapper(history, TimingHistory::export));
+
+
+ String response = null;
+ String timingsURL = null;
+ try {
+ HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection();
+ con.setDoOutput(true);
+ String hostName = "BrokenHost";
+ try {
+ hostName = InetAddress.getLocalHost().getHostName();
+ } catch (Exception ignored) {}
+ con.setRequestProperty("User-Agent", "Paper/" + Bukkit.getUnsafe().getTimingsServerName() + "/" + hostName);
+ con.setRequestMethod("POST");
+ con.setInstanceFollowRedirects(false);
+
+ OutputStream request = new GZIPOutputStream(con.getOutputStream()) {{
+ this.def.setLevel(7);
+ }};
+
+ request.write(JSONValue.toJSONString(out).getBytes("UTF-8"));
+ request.close();
+
+ response = getResponse(con);
+
+ if (con.getResponseCode() != 302) {
+ listeners.sendMessage(
+ ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage());
+ listeners.sendMessage(ChatColor.RED + "Check your logs for more information");
+ if (response != null) {
+ Bukkit.getLogger().log(Level.SEVERE, response);
+ }
+ return;
+ }
+
+ timingsURL = con.getHeaderField("Location");
+ listeners.sendMessage(ChatColor.GREEN + "View Timings Report: " + timingsURL);
+
+ if (response != null && !response.isEmpty()) {
+ Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response);
+ }
+ } catch (IOException ex) {
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
+ if (response != null) {
+ Bukkit.getLogger().log(Level.SEVERE, response);
+ }
+ Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex);
+ } finally {
+ this.listeners.done(timingsURL);
+ }
+ }
+
+ private String getResponse(HttpURLConnection con) throws IOException {
+ InputStream is = null;
+ try {
+ is = con.getInputStream();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ byte[] b = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = is.read(b)) != -1) {
+ bos.write(b, 0, bytesRead);
+ }
+ return bos.toString();
+
+ } catch (IOException ex) {
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
+ Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex);
+ return null;
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+ }
+}
diff --git a/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/src/main/java/co/aikar/timings/WorldTimingsHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa1c920ea6092259149f9e7f9cd7cc1ed27bf338
--- /dev/null
+++ b/src/main/java/co/aikar/timings/WorldTimingsHandler.java
@@ -0,0 +1,118 @@
+package co.aikar.timings;
+
+import net.minecraft.server.World;
+import net.minecraft.server.WorldServer;
+
+/**
+ * Set of timers per world, to track world specific timings.
+ */
+// TODO: Re-implement missing timers
+public class WorldTimingsHandler {
+ public final Timing mobSpawn;
+ public final Timing doChunkUnload;
+ public final Timing doPortalForcer;
+ public final Timing scheduledBlocks;
+ public final Timing scheduledBlocksCleanup;
+ public final Timing scheduledBlocksTicking;
+ public final Timing chunkTicks;
+ public final Timing lightChunk;
+ public final Timing chunkTicksBlocks;
+ public final Timing doVillages;
+ public final Timing doChunkMap;
+ public final Timing doChunkMapUpdate;
+ public final Timing doChunkMapToUpdate;
+ public final Timing doChunkMapSortMissing;
+ public final Timing doChunkMapSortSendToPlayers;
+ public final Timing doChunkMapPlayersNeedingChunks;
+ public final Timing doChunkMapPendingSendToPlayers;
+ public final Timing doChunkMapUnloadChunks;
+ public final Timing doChunkGC;
+ public final Timing doSounds;
+ public final Timing entityRemoval;
+ public final Timing entityTick;
+ public final Timing tileEntityTick;
+ public final Timing tileEntityPending;
+ public final Timing tracker1;
+ public final Timing tracker2;
+ public final Timing doTick;
+ public final Timing tickEntities;
+ public final Timing chunks;
+ public final Timing newEntities;
+ public final Timing raids;
+ public final Timing chunkProviderTick;
+ public final Timing broadcastChunkUpdates;
+ public final Timing countNaturalMobs;
+
+ public final Timing chunkLoad;
+ public final Timing chunkLoadPopulate;
+ public final Timing syncChunkLoad;
+ public final Timing chunkLoadLevelTimer;
+ public final Timing chunkIO;
+ public final Timing chunkPostLoad;
+ public final Timing worldSave;
+ public final Timing worldSaveChunks;
+ public final Timing worldSaveLevel;
+ public final Timing chunkSaveData;
+
+
+ public final Timing miscMobSpawning;
+
+ public WorldTimingsHandler(World server) {
+ String name = server.worldData.getName() +" - ";
+
+ mobSpawn = Timings.ofSafe(name + "mobSpawn");
+ doChunkUnload = Timings.ofSafe(name + "doChunkUnload");
+ scheduledBlocks = Timings.ofSafe(name + "Scheduled Blocks");
+ scheduledBlocksCleanup = Timings.ofSafe(name + "Scheduled Blocks - Cleanup");
+ scheduledBlocksTicking = Timings.ofSafe(name + "Scheduled Blocks - Ticking");
+ chunkTicks = Timings.ofSafe(name + "Chunk Ticks");
+ lightChunk = Timings.ofSafe(name + "Light Chunk");
+ chunkTicksBlocks = Timings.ofSafe(name + "Chunk Ticks - Blocks");
+ doVillages = Timings.ofSafe(name + "doVillages");
+ doChunkMap = Timings.ofSafe(name + "doChunkMap");
+ doChunkMapUpdate = Timings.ofSafe(name + "doChunkMap - Update");
+ doChunkMapToUpdate = Timings.ofSafe(name + "doChunkMap - To Update");
+ doChunkMapSortMissing = Timings.ofSafe(name + "doChunkMap - Sort Missing");
+ doChunkMapSortSendToPlayers = Timings.ofSafe(name + "doChunkMap - Sort Send To Players");
+ doChunkMapPlayersNeedingChunks = Timings.ofSafe(name + "doChunkMap - Players Needing Chunks");
+ doChunkMapPendingSendToPlayers = Timings.ofSafe(name + "doChunkMap - Pending Send To Players");
+ doChunkMapUnloadChunks = Timings.ofSafe(name + "doChunkMap - Unload Chunks");
+ doSounds = Timings.ofSafe(name + "doSounds");
+ doChunkGC = Timings.ofSafe(name + "doChunkGC");
+ doPortalForcer = Timings.ofSafe(name + "doPortalForcer");
+ entityTick = Timings.ofSafe(name + "entityTick");
+ entityRemoval = Timings.ofSafe(name + "entityRemoval");
+ tileEntityTick = Timings.ofSafe(name + "tileEntityTick");
+ tileEntityPending = Timings.ofSafe(name + "tileEntityPending");
+
+ chunkLoad = Timings.ofSafe(name + "Chunk Load");
+ chunkLoadPopulate = Timings.ofSafe(name + "Chunk Load - Populate");
+ syncChunkLoad = Timings.ofSafe(name + "Sync Chunk Load");
+ chunkLoadLevelTimer = Timings.ofSafe(name + "Chunk Load - Load Level");
+ chunkIO = Timings.ofSafe(name + "Chunk Load - DiskIO");
+ chunkPostLoad = Timings.ofSafe(name + "Chunk Load - Post Load");
+ worldSave = Timings.ofSafe(name + "World Save");
+ worldSaveLevel = Timings.ofSafe(name + "World Save - Level");
+ worldSaveChunks = Timings.ofSafe(name + "World Save - Chunks");
+ chunkSaveData = Timings.ofSafe(name + "Chunk Save - Data");
+
+ tracker1 = Timings.ofSafe(name + "tracker stage 1");
+ tracker2 = Timings.ofSafe(name + "tracker stage 2");
+ doTick = Timings.ofSafe(name + "doTick");
+ tickEntities = Timings.ofSafe(name + "tickEntities");
+
+ chunks = Timings.ofSafe(name + "Chunks");
+ newEntities = Timings.ofSafe(name + "New entity registration");
+ raids = Timings.ofSafe(name + "Raids");
+ chunkProviderTick = Timings.ofSafe(name + "Chunk provider tick");
+ broadcastChunkUpdates = Timings.ofSafe(name + "Broadcast chunk updates");
+ countNaturalMobs = Timings.ofSafe(name + "Count natural mobs");
+
+
+ miscMobSpawning = Timings.ofSafe(name + "Mob spawning - Misc");
+ }
+
+ public static Timing getTickList(WorldServer worldserver, String timingsType) {
+ return Timings.ofSafe(worldserver.getWorldData().getName() + " - Scheduled " + timingsType);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index b6d470e594ce196f560ac6c94ced904b0081b205..f402a29b0904a0094ffe6e42dbdc6fbc0912d9d9 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -14,11 +14,14 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.regex.Pattern;
+import com.google.common.collect.Lists;
import net.minecraft.server.MinecraftServer;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
+import co.aikar.timings.Timings;
+import co.aikar.timings.TimingsManager;
public class PaperConfig {
@@ -187,4 +190,27 @@ public class PaperConfig {
config.addDefault(path, def);
return config.getString(path, config.getString(path));
}
+
+ public static String timingsServerName;
+ private static void timings() {
+ boolean timings = getBoolean("timings.enabled", true);
+ boolean verboseTimings = getBoolean("timings.verbose", true);
+ TimingsManager.privacy = getBoolean("timings.server-name-privacy", false);
+ TimingsManager.hiddenConfigs = getList("timings.hidden-config-entries", Lists.newArrayList("database", "settings.bungeecord-addresses"));
+ int timingHistoryInterval = getInt("timings.history-interval", 300);
+ int timingHistoryLength = getInt("timings.history-length", 3600);
+ timingsServerName = getString("timings.server-name", "Unknown Server");
+
+
+ Timings.setVerboseTimingsEnabled(verboseTimings);
+ Timings.setTimingsEnabled(timings);
+ Timings.setHistoryInterval(timingHistoryInterval * 20);
+ Timings.setHistoryLength(timingHistoryLength * 20);
+
+ log("Timings: " + timings +
+ " - Verbose: " + verboseTimings +
+ " - Interval: " + timeSummary(Timings.getHistoryInterval() / 20) +
+ " - Length: " + timeSummary(Timings.getHistoryLength() / 20) +
+ " - Server Name: " + timingsServerName);
+ }
}
diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java
index cd72a9c84569592f9c82708a17388e594648d19d..5de881371a485957fd8fadc7540a2b549b20dd65 100644
--- a/src/main/java/net/minecraft/server/Block.java
+++ b/src/main/java/net/minecraft/server/Block.java
@@ -31,6 +31,15 @@ public class Block implements IMaterial {
protected final boolean q;
protected final SoundEffectType stepSound;
protected final Material material;
+ // Paper start
+ public co.aikar.timings.Timing timing;
+ public co.aikar.timings.Timing getTiming() {
+ if (timing == null) {
+ timing = co.aikar.timings.MinecraftTimings.getBlockTiming(this);
+ }
+ return timing;
+ }
+ // Paper end
protected final MaterialMapColor t;
private final float frictionFactor;
private final float f;
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index f1b9b937e8ced0c718db463c94d716422113c396..43dc791191cdf2aa3e5cb2768c25e6be4b2cf6b1 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -692,6 +692,7 @@ public class Chunk implements IChunkAccess {
server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(this.bukkitChunk, this.needsDecoration));
if (this.needsDecoration) {
+ try (co.aikar.timings.Timing ignored = this.world.timings.chunkLoadPopulate.startTiming()) { // Paper
this.needsDecoration = false;
java.util.Random random = new java.util.Random();
random.setSeed(world.getSeed());
@@ -711,6 +712,7 @@ public class Chunk implements IChunkAccess {
}
}
server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk));
+ } // Paper
}
}
}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index ba2af2abe2dd09eb6801f431a0942bd93755c97e..875f353dc3a0f3418b01821abf30e0f1ca32bb4d 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -308,11 +308,13 @@ public class ChunkProviderServer extends IChunkProvider {
}
gameprofilerfiller.c("getChunkCacheMiss");
- world.timings.syncChunkLoadTimer.startTiming(); // Spigot
CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag);
+ if (!completablefuture.isDone()) { // Paper
+ this.world.timings.syncChunkLoad.startTiming(); // Paper
this.serverThreadQueue.awaitTasks(completablefuture::isDone);
- world.timings.syncChunkLoadTimer.stopTiming(); // Spigot
+ this.world.timings.syncChunkLoad.stopTiming(); // Paper
+ } // Paper
ichunkaccess = (IChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> {
return ichunkaccess1;
}, (playerchunk_failure) -> {
@@ -505,7 +507,9 @@ public class ChunkProviderServer extends IChunkProvider {
public void save(boolean flag) {
this.tickDistanceManager();
+ try (co.aikar.timings.Timing timed = world.timings.chunkSaveData.startTiming()) { // Paper - Timings
this.playerChunkMap.save(flag);
+ } // Paper - Timings
}
@Override
@@ -542,7 +546,9 @@ public class ChunkProviderServer extends IChunkProvider {
this.tickDistanceManager();
this.world.timings.doChunkMap.stopTiming(); // Spigot
this.world.getMethodProfiler().exitEnter("chunks");
+ this.world.timings.chunks.startTiming(); // Paper - timings
this.tickChunks();
+ this.world.timings.chunks.stopTiming(); // Paper - timings
this.world.timings.doChunkUnload.startTiming(); // Spigot
this.world.getMethodProfiler().exitEnter("unload");
this.playerChunkMap.unloadChunks(booleansupplier);
@@ -573,10 +579,12 @@ public class ChunkProviderServer extends IChunkProvider {
// CraftBukkit end
this.world.getMethodProfiler().enter("naturalSpawnCount");
+ this.world.timings.countNaturalMobs.startTiming(); // Paper - timings
int l = this.chunkMapDistance.b();
EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values();
Object2IntMap<EnumCreatureType> object2intmap = this.world.l();
+ this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings
this.world.getMethodProfiler().exit();
this.playerChunkMap.f().forEach((playerchunk) -> {
Optional<Chunk> optional = ((Either) playerchunk.b().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
@@ -585,11 +593,14 @@ public class ChunkProviderServer extends IChunkProvider {
Chunk chunk = (Chunk) optional.get();
this.world.getMethodProfiler().enter("broadcast");
+ this.world.timings.broadcastChunkUpdates.startTiming(); // Paper - timings
playerchunk.a(chunk);
+ this.world.timings.broadcastChunkUpdates.stopTiming(); // Paper - timings
this.world.getMethodProfiler().exit();
ChunkCoordIntPair chunkcoordintpair = playerchunk.i();
if (!this.playerChunkMap.isOutsideOfRange(chunkcoordintpair)) {
+ // Paper end
chunk.setInhabitedTime(chunk.getInhabitedTime() + j);
if (flag1 && (this.allowMonsters || this.allowAnimals) && this.world.getWorldBorder().isInBounds(chunk.getPos()) && !this.playerChunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot
this.world.getMethodProfiler().enter("spawner");
@@ -640,24 +651,24 @@ public class ChunkProviderServer extends IChunkProvider {
this.world.getMethodProfiler().exit();
}
- this.world.timings.doTickTiles.startTiming(); // Spigot
+ this.world.timings.chunkTicks.startTiming(); // Spigot // Paper
this.world.a(chunk, k);
- this.world.timings.doTickTiles.stopTiming(); // Spigot
+ this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper
}
}
});
this.world.getMethodProfiler().enter("customSpawners");
if (flag1) {
+ try (co.aikar.timings.Timing ignored = this.world.timings.miscMobSpawning.startTiming()) { // Paper - timings
this.chunkGenerator.doMobSpawning(this.world, this.allowMonsters, this.allowAnimals);
+ } // Paper - timings
}
this.world.getMethodProfiler().exit();
this.world.getMethodProfiler().exit();
}
- this.world.timings.tracker.startTiming(); // Spigot
this.playerChunkMap.g();
- this.world.timings.tracker.stopTiming(); // Spigot
}
@Override
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index e16d30f2cafcbc5edbcd58d97703686aaf1537d5..13d99de2cd08de02215031a1f699110c13ef35ff 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -1,5 +1,6 @@
package net.minecraft.server;
+import co.aikar.timings.Timings;
import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
@@ -388,7 +389,6 @@ public class ChunkRegionLoader {
private static void loadEntities(NBTTagCompound nbttagcompound, Chunk chunk) {
NBTTagList nbttaglist = nbttagcompound.getList("Entities", 10);
World world = chunk.getWorld();
- world.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot
for (int i = 0; i < nbttaglist.size(); ++i) {
NBTTagCompound nbttagcompound1 = nbttaglist.getCompound(i);
@@ -400,8 +400,6 @@ public class ChunkRegionLoader {
chunk.d(true);
}
- world.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot
- world.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot
NBTTagList nbttaglist1 = nbttagcompound.getList("TileEntities", 10);
for (int j = 0; j < nbttaglist1.size(); ++j) {
@@ -418,8 +416,6 @@ public class ChunkRegionLoader {
}
}
}
- world.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot
-
}
private static NBTTagCompound a(ChunkCoordIntPair chunkcoordintpair, Map<String, StructureStart> map, Map<String, LongSet> map1) {
diff --git a/src/main/java/net/minecraft/server/CustomFunction.java b/src/main/java/net/minecraft/server/CustomFunction.java
index 8d7a6d2403722c7e7ff437f8e153ffa6194679d7..707bd2600d19699f58405eaa23ec36f406ca20ba 100644
--- a/src/main/java/net/minecraft/server/CustomFunction.java
+++ b/src/main/java/net/minecraft/server/CustomFunction.java
@@ -13,12 +13,22 @@ public class CustomFunction {
private final CustomFunction.c[] a;
private final MinecraftKey b;
+ // Paper start
+ public co.aikar.timings.Timing timing;
+ public co.aikar.timings.Timing getTiming() {
+ if (timing == null) {
+ timing = co.aikar.timings.MinecraftTimings.getCommandFunctionTiming(this);
+ }
+ return timing;
+ }
+ // Paper end
public CustomFunction(MinecraftKey minecraftkey, CustomFunction.c[] acustomfunction_c) {
this.b = minecraftkey;
this.a = acustomfunction_c;
}
+ public MinecraftKey getMinecraftKey() { return this.a(); } // Paper - OBFHELPER
public MinecraftKey a() {
return this.b;
}
diff --git a/src/main/java/net/minecraft/server/CustomFunctionData.java b/src/main/java/net/minecraft/server/CustomFunctionData.java
index ba40d5fbb5fe69225d25bdc4e299857f5ab21b40..ee42e1dfa493c3d7f5af8cc7b8e17e80fcb32b71 100644
--- a/src/main/java/net/minecraft/server/CustomFunctionData.java
+++ b/src/main/java/net/minecraft/server/CustomFunctionData.java
@@ -103,7 +103,7 @@ public class CustomFunctionData implements IResourcePackListener {
} else {
int j;
- try {
+ try (co.aikar.timings.Timing timing = customfunction.getTiming().startTiming()) { // Paper
this.h = true;
int k = 0;
CustomFunction.c[] acustomfunction_c = customfunction.b();
diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java
index 9eed98e3796be6d49dc51af9038a7376c94edeee..d6646d7e61b63c116fa87951b0ef3131b68ebe97 100644
--- a/src/main/java/net/minecraft/server/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/DedicatedServer.java
@@ -20,6 +20,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.function.BooleanSupplier;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -32,7 +34,7 @@ import org.apache.logging.log4j.Level;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.LoggerOutputStream;
-import org.bukkit.craftbukkit.SpigotTimings; // Spigot
+import co.aikar.timings.MinecraftTimings; // Paper
import org.bukkit.event.server.ServerCommandEvent;
import org.bukkit.craftbukkit.util.Waitable;
import org.bukkit.event.server.RemoteServerCommandEvent;
@@ -438,7 +440,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
}
public void handleCommandQueue() {
- SpigotTimings.serverCommandTimer.startTiming(); // Spigot
+ MinecraftTimings.serverCommandTimer.startTiming(); // Spigot
while (!this.serverCommandQueue.isEmpty()) {
ServerCommand servercommand = (ServerCommand) this.serverCommandQueue.remove(0);
@@ -453,7 +455,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
// CraftBukkit end
}
- SpigotTimings.serverCommandTimer.stopTiming(); // Spigot
+ MinecraftTimings.serverCommandTimer.stopTiming(); // Spigot
}
@Override
@@ -679,6 +681,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
@Override
public String executeRemoteCommand(String s) {
+ Waitable[] waitableArray = new Waitable[1];
this.remoteControlCommandListener.clearMessages();
this.executeSync(() -> {
// CraftBukkit start - fire RemoteServerCommandEvent
@@ -687,10 +690,39 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
if (event.isCancelled()) {
return;
}
+ // Paper start
+ if (s.toLowerCase().startsWith("timings") && s.toLowerCase().matches("timings (report|paste|get|merged|seperate)")) {
+ org.bukkit.command.BufferedCommandSender sender = new org.bukkit.command.BufferedCommandSender();
+ Waitable<String> waitable = new Waitable<String>() {
+ @Override
+ protected String evaluate() {
+ return sender.getBuffer();
+ }
+ };
+ waitableArray[0] = waitable;
+ co.aikar.timings.Timings.generateReport(new co.aikar.timings.TimingsReportListener(sender, waitable));
+ } else {
+ // Paper end
ServerCommand serverCommand = new ServerCommand(event.getCommand(), remoteControlCommandListener.getWrapper());
server.dispatchServerCommand(remoteConsole, serverCommand);
+ } // Paper
// CraftBukkit end
});
+ // Paper start
+ if (waitableArray[0] != null) {
+ //noinspection unchecked
+ Waitable<String> waitable = waitableArray[0];
+ try {
+ return waitable.get();
+ } catch (java.util.concurrent.ExecutionException e) {
+ throw new RuntimeException("Exception processing rcon command " + s, e.getCause());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // Maintain interrupted state
+ throw new RuntimeException("Interrupted processing rcon command " + s, e);
+ }
+
+ }
+ // Paper end
return this.remoteControlCommandListener.getMessages();
}
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index 0d8262b1d2722e716f95db4c9a8a132c54b613cf..19d68aa4585ccfc156e9db6024b7a99bbeca4de4 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -29,7 +29,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Vehicle;
-import org.spigotmc.CustomTimingsHandler; // Spigot
+import co.aikar.timings.MinecraftTimings; // Paper
+import co.aikar.timings.Timing; // Paper
import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
@@ -165,7 +166,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
public boolean valid;
public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
public boolean forceExplosionKnockback; // SPIGOT-949
- public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getEntityTimings(this); // Spigot
+ public Timing tickTimer = MinecraftTimings.getEntityTimings(this); // Paper
// Spigot start
public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
public final boolean defaultActivationState;
@@ -504,7 +505,6 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
}
public void move(EnumMoveType enummovetype, Vec3D vec3d) {
- org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.startTiming(); // Spigot
if (this.noclip) {
this.a(this.getBoundingBox().b(vec3d));
this.recalcPosition();
@@ -656,7 +656,6 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
this.world.getMethodProfiler().exit();
}
- org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.stopTiming(); // Spigot
}
protected BlockPosition ag() {
diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
index 3ace8ee854c11abd607dc27b93fe61a0982a73de..690c1ce0f6707b2f5dd787e0fe340af5bd719783 100644
--- a/src/main/java/net/minecraft/server/EntityLiving.java
+++ b/src/main/java/net/minecraft/server/EntityLiving.java
@@ -37,7 +37,7 @@ import org.bukkit.event.entity.EntityTeleportEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
// CraftBukkit end
-import org.bukkit.craftbukkit.SpigotTimings; // Spigot
+import co.aikar.timings.MinecraftTimings; // Paper
public abstract class EntityLiving extends Entity {
@@ -2265,7 +2265,6 @@ public abstract class EntityLiving extends Entity {
@Override
public void tick() {
- SpigotTimings.timerEntityBaseTick.startTiming(); // Spigot
super.tick();
this.o();
this.r();
@@ -2353,9 +2352,7 @@ public abstract class EntityLiving extends Entity {
}
}
- SpigotTimings.timerEntityBaseTick.stopTiming(); // Spigot
this.movementTick();
- SpigotTimings.timerEntityTickRest.startTiming(); // Spigot
double d0 = this.locX() - this.lastX;
double d1 = this.locZ() - this.lastZ;
float f = (float) (d0 * d0 + d1 * d1);
@@ -2435,8 +2432,6 @@ public abstract class EntityLiving extends Entity {
if (this.isSleeping()) {
this.pitch = 0.0F;
}
-
- SpigotTimings.timerEntityTickRest.stopTiming(); // Spigot
}
protected float f(float f, float f1) {
@@ -2515,7 +2510,6 @@ public abstract class EntityLiving extends Entity {
this.setMot(d4, d5, d6);
this.world.getMethodProfiler().enter("ai");
- SpigotTimings.timerEntityAI.startTiming(); // Spigot
if (this.isFrozen()) {
this.jumping = false;
this.aZ = 0.0F;
@@ -2525,7 +2519,6 @@ public abstract class EntityLiving extends Entity {
this.doTick();
this.world.getMethodProfiler().exit();
}
- SpigotTimings.timerEntityAI.stopTiming(); // Spigot
this.world.getMethodProfiler().exit();
this.world.getMethodProfiler().enter("jump");
@@ -2549,9 +2542,7 @@ public abstract class EntityLiving extends Entity {
this.n();
AxisAlignedBB axisalignedbb = this.getBoundingBox();
- SpigotTimings.timerEntityAIMove.startTiming(); // Spigot
this.e(new Vec3D((double) this.aZ, (double) this.ba, (double) this.bb));
- SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot
this.world.getMethodProfiler().exit();
this.world.getMethodProfiler().enter("push");
if (this.bn > 0) {
@@ -2559,9 +2550,7 @@ public abstract class EntityLiving extends Entity {
this.a(axisalignedbb, this.getBoundingBox());
}
- SpigotTimings.timerEntityAICollision.startTiming(); // Spigot
this.collideNearby();
- SpigotTimings.timerEntityAICollision.stopTiming(); // Spigot
this.world.getMethodProfiler().exit();
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 786d38438cc1bd5a736b2dfa80aca9b9c6253e65..5429d8eee93980a01cdf008b57e88e1dccc1ef67 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -63,7 +63,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.Main;
import org.bukkit.event.server.ServerLoadEvent;
// CraftBukkit end
-import org.bukkit.craftbukkit.SpigotTimings; // Spigot
+import co.aikar.timings.MinecraftTimings; // Paper
import org.spigotmc.SlackActivityAccountant; // Spigot
public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTask> implements IMojangStatistics, ICommandListener, AutoCloseable, Runnable {
@@ -128,8 +128,8 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
});
});
private long nextTick = SystemUtils.getMonotonicMillis();
- private long ab;
- private boolean ac;
+ private long ab; final long getTickOversleepMaxTime() { return this.ab; } // Paper - OBFHELPER
+ private boolean ac; final boolean hasExecutedTask() { return this.ac; } // Paper - OBFHELPER
private final IReloadableResourceManager ae;
private final ResourcePackRepository<ResourcePackLoader> resourcePackRepository;
@Nullable
@@ -694,6 +694,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
}
// CraftBukkit end
MinecraftServer.LOGGER.info("Stopping server");
+ MinecraftTimings.stopServer(); // Paper
// CraftBukkit start
if (this.server != null) {
this.server.disablePlugins();
@@ -884,9 +885,21 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
private boolean canSleepForTick() {
// CraftBukkit start
+ if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken
return this.forceTicks || this.isEntered() || SystemUtils.getMonotonicMillis() < (this.ac ? this.ab : this.nextTick);
}
+ // Paper start
+ boolean isOversleep = false;
+ private boolean canOversleep() {
+ return this.hasExecutedTask() && SystemUtils.getMonotonicMillis() < this.getTickOversleepMaxTime();
+ }
+
+ private boolean canSleepForTickNoOversleep() {
+ return this.forceTicks || this.isEntered() || SystemUtils.getMonotonicMillis() < this.nextTick;
+ }
+ // Paper end
+
private void executeModerately() {
this.executeAll();
java.util.concurrent.locks.LockSupport.parkNanos("executing tasks", 1000L);
@@ -894,9 +907,9 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
// CraftBukkit end
protected void sleepForTick() {
- this.executeAll();
+ //this.executeAll(); // Paper - move this into the tick method for timings
this.awaitTasks(() -> {
- return !this.canSleepForTick();
+ return !this.canSleepForTickNoOversleep(); // Paper - move oversleep into full server tick
});
}
@@ -979,10 +992,18 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
protected void exit() {}
protected void a(BooleanSupplier booleansupplier) {
- SpigotTimings.serverTickTimer.startTiming(); // Spigot
+ co.aikar.timings.TimingsManager.FULL_SERVER_TICK.startTiming(); // Paper
this.slackActivityAccountant.tickStarted(); // Spigot
long i = SystemUtils.getMonotonicNanos();
+ // Paper start - move oversleep into full server tick
+ isOversleep = true;MinecraftTimings.serverOversleep.startTiming();
+ this.awaitTasks(() -> {
+ return !this.canOversleep();
+ });
+ isOversleep = false;MinecraftTimings.serverOversleep.stopTiming();
+ // Paper end
+
++this.ticks;
this.b(booleansupplier);
if (i - this.Z >= 5000000000L) {
@@ -1000,14 +1021,12 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
}
if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit
- SpigotTimings.worldSaveTimer.startTiming(); // Spigot
MinecraftServer.LOGGER.debug("Autosave started");
this.methodProfiler.enter("save");
this.playerList.savePlayers();
this.saveChunks(true, false, false);
this.methodProfiler.exit();
MinecraftServer.LOGGER.debug("Autosave finished");
- SpigotTimings.worldSaveTimer.stopTiming(); // Spigot
}
this.methodProfiler.enter("snooper");
@@ -1020,6 +1039,13 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
}
this.methodProfiler.exit();
+
+ // Paper start - move executeAll() into full server tick timing
+ try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) {
+ this.executeAll();
+ }
+ // Paper end
+
this.methodProfiler.enter("tallying");
long l = this.f[this.ticks % 100] = SystemUtils.getMonotonicNanos() - i;
@@ -1030,30 +1056,29 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
this.methodProfiler.exit();
org.spigotmc.WatchdogThread.tick(); // Spigot
this.slackActivityAccountant.tickEnded(l); // Spigot
- SpigotTimings.serverTickTimer.stopTiming(); // Spigot
- org.spigotmc.CustomTimingsHandler.tick(); // Spigot
+ co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper
}
protected void b(BooleanSupplier booleansupplier) {
- SpigotTimings.schedulerTimer.startTiming(); // Spigot
+ MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper
this.server.getScheduler().mainThreadHeartbeat(this.ticks); // CraftBukkit
- SpigotTimings.schedulerTimer.stopTiming(); // Spigot
+ MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper
this.methodProfiler.enter("commandFunctions");
- SpigotTimings.commandFunctionsTimer.startTiming(); // Spigot
+ MinecraftTimings.commandFunctionsTimer.startTiming(); // Spigot // Paper
this.getFunctionData().tick();
- SpigotTimings.commandFunctionsTimer.stopTiming(); // Spigot
+ MinecraftTimings.commandFunctionsTimer.stopTiming(); // Spigot // Paper
this.methodProfiler.exitEnter("levels");
Iterator iterator = this.getWorlds().iterator();
// CraftBukkit start
// Run tasks that are waiting on processing
- SpigotTimings.processQueueTimer.startTiming(); // Spigot
+ MinecraftTimings.processQueueTimer.startTiming(); // Spigot
while (!processQueue.isEmpty()) {
processQueue.remove().run();
}
- SpigotTimings.processQueueTimer.stopTiming(); // Spigot
+ MinecraftTimings.processQueueTimer.stopTiming(); // Spigot
- SpigotTimings.timeUpdateTimer.startTiming(); // Spigot
+ MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper
// Send time updates to everyone, it will get the right time from the world the player is in.
if (this.ticks % 20 == 0) {
for (int i = 0; i < this.getPlayerList().players.size(); ++i) {
@@ -1061,7 +1086,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateTime(entityplayer.world.getTime(), entityplayer.getPlayerTime(), entityplayer.world.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE))); // Add support for per player time
}
}
- SpigotTimings.timeUpdateTimer.stopTiming(); // Spigot
+ MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper
while (iterator.hasNext()) {
WorldServer worldserver = (WorldServer) iterator.next();
@@ -1104,24 +1129,24 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
}
this.methodProfiler.exitEnter("connection");
- SpigotTimings.connectionTimer.startTiming(); // Spigot
+ MinecraftTimings.connectionTimer.startTiming(); // Spigot
this.getServerConnection().c();
- SpigotTimings.connectionTimer.stopTiming(); // Spigot
+ MinecraftTimings.connectionTimer.stopTiming(); // Spigot
this.methodProfiler.exitEnter("players");
- SpigotTimings.playerListTimer.startTiming(); // Spigot
+ MinecraftTimings.playerListTimer.startTiming(); // Spigot // Paper
this.playerList.tick();
- SpigotTimings.playerListTimer.stopTiming(); // Spigot
+ MinecraftTimings.playerListTimer.stopTiming(); // Spigot // Paper
if (SharedConstants.b) {
GameTestHarnessTicker.a.b();
}
this.methodProfiler.exitEnter("server gui refresh");
- SpigotTimings.tickablesTimer.startTiming(); // Spigot
+ MinecraftTimings.tickablesTimer.startTiming(); // Spigot // Paper
for (int i = 0; i < this.tickables.size(); ++i) {
((Runnable) this.tickables.get(i)).run();
}
- SpigotTimings.tickablesTimer.stopTiming(); // Spigot
+ MinecraftTimings.tickablesTimer.stopTiming(); // Spigot // Paper
this.methodProfiler.exit();
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index b505244516321292e56609eaa54693d84e0bf617..65134c87772cb6d4d732fc223929cfda7524dde2 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -1,7 +1,9 @@
package net.minecraft.server;
+import co.aikar.timings.Timing; // Paper
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import com.google.common.collect.ComparisonChain; // Paper
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
@@ -507,11 +509,14 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
private CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> f(ChunkCoordIntPair chunkcoordintpair) {
return CompletableFuture.supplyAsync(() -> {
- try {
+ try (Timing ignored = this.world.timings.chunkLoad.startTimingIfSync()) { // Paper
this.world.getMethodProfiler().c("chunkLoad");
- NBTTagCompound nbttagcompound = this.readChunkData(chunkcoordintpair);
+ NBTTagCompound nbttagcompound; // Paper
+ try (Timing ignored2 = this.world.timings.chunkIO.startTimingIfSync()) { // Paper start - timings
+ nbttagcompound = this.readChunkData(chunkcoordintpair);
+ } // Paper end
- if (nbttagcompound != null) {
+ if (nbttagcompound != null) {try (Timing ignored2 = this.world.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings
boolean flag = nbttagcompound.hasKeyOfType("Level", 10) && nbttagcompound.getCompound("Level").hasKeyOfType("Status", 8);
if (flag) {
@@ -522,7 +527,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
}
PlayerChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", chunkcoordintpair);
- }
+ }} // Paper
} catch (ReportedException reportedexception) {
Throwable throwable = reportedexception.getCause();
@@ -549,7 +554,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return "chunkGenerate " + chunkstatus.d();
});
return completablefuture.thenComposeAsync((either) -> {
- return (CompletableFuture) either.map((list) -> {
+ return either.map((list) -> { // Paper - Shut up.
try {
CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture1 = chunkstatus.a(this.world, this.chunkGenerator, this.definedStructureManager, this.lightEngine, (ichunkaccess) -> {
return this.c(playerchunk);
@@ -602,6 +607,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
ChunkStatus chunkstatus = PlayerChunk.getChunkStatus(playerchunk.getTicketLevel());
return !chunkstatus.b(ChunkStatus.FULL) ? PlayerChunk.UNLOADED_CHUNK_ACCESS : either.mapLeft((ichunkaccess) -> {
+ try (Timing ignored = world.timings.chunkPostLoad.startTimingIfSync()) { // Paper
ChunkCoordIntPair chunkcoordintpair = playerchunk.i();
Chunk chunk;
@@ -653,6 +659,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
}
return chunk;
+ } // Paper
});
}, (runnable) -> {
Mailbox mailbox = this.mailboxMain;
@@ -1094,6 +1101,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
PlayerChunkMap.EntityTracker playerchunkmap_entitytracker;
ObjectIterator objectiterator;
+ world.timings.tracker1.startTiming(); // Paper
for (objectiterator = this.trackedEntities.values().iterator(); objectiterator.hasNext(); playerchunkmap_entitytracker.trackerEntry.a()) {
playerchunkmap_entitytracker = (PlayerChunkMap.EntityTracker) objectiterator.next();
@@ -1111,16 +1119,20 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
playerchunkmap_entitytracker.e = sectionposition1;
}
}
+ world.timings.tracker1.stopTiming(); // Paper
if (!list.isEmpty()) {
objectiterator = this.trackedEntities.values().iterator();
+ world.timings.tracker2.startTiming(); // Paper
while (objectiterator.hasNext()) {
playerchunkmap_entitytracker = (PlayerChunkMap.EntityTracker) objectiterator.next();
playerchunkmap_entitytracker.track(list);
}
+ world.timings.tracker2.stopTiming(); // Paper
}
+
}
protected void broadcast(Entity entity, Packet<?> packet) {
diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
index f40cb14d5301631161f1701043ee987359d9a8e9..87119b4fe5ae27c63d272c8e436e3734eddd8f68 100644
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
@@ -58,6 +58,7 @@ import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.InventoryView;
import org.bukkit.util.NumberConversions;
+import co.aikar.timings.MinecraftTimings; // Paper
// CraftBukkit end
public class PlayerConnection implements PacketListenerPlayIn {
@@ -135,7 +136,6 @@ public class PlayerConnection implements PacketListenerPlayIn {
// CraftBukkit end
public void tick() {
- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.startTiming(); // Spigot
this.syncPosition();
this.player.lastX = this.player.locX();
this.player.lastY = this.player.locY();
@@ -211,7 +211,6 @@ public class PlayerConnection implements PacketListenerPlayIn {
this.player.resetIdleTimer(); // CraftBukkit - SPIGOT-854
this.disconnect(new ChatMessage("multiplayer.disconnect.idling", new Object[0]));
}
- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.stopTiming(); // Spigot
}
@@ -1639,7 +1638,7 @@ public class PlayerConnection implements PacketListenerPlayIn {
// CraftBukkit end
private void handleCommand(String s) {
- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.startTiming(); // Spigot
+ MinecraftTimings.playerCommandTimer.startTiming(); // Paper
// CraftBukkit start - whole method
if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot
this.LOGGER.info(this.player.getName() + " issued server command: " + s);
@@ -1650,7 +1649,7 @@ public class PlayerConnection implements PacketListenerPlayIn {
this.server.getPluginManager().callEvent(event);
if (event.isCancelled()) {
- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot
+ MinecraftTimings.playerCommandTimer.stopTiming(); // Paper
return;
}
@@ -1663,7 +1662,7 @@ public class PlayerConnection implements PacketListenerPlayIn {
java.util.logging.Logger.getLogger(PlayerConnection.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
return;
} finally {
- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot
+ MinecraftTimings.playerCommandTimer.stopTiming(); // Paper
}
// this.minecraftServer.getCommandDispatcher().a(this.player.getCommandListener(), s);
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/PlayerConnectionUtils.java b/src/main/java/net/minecraft/server/PlayerConnectionUtils.java
index 2c671629a43f42da8335e7216f9fd399bb878729..eb3269e0ea3ce33d08e9eee3bca7cf434921e991 100644
--- a/src/main/java/net/minecraft/server/PlayerConnectionUtils.java
+++ b/src/main/java/net/minecraft/server/PlayerConnectionUtils.java
@@ -2,6 +2,8 @@ package net.minecraft.server;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import co.aikar.timings.MinecraftTimings; // Paper
+import co.aikar.timings.Timing; // Paper
public class PlayerConnectionUtils {
@@ -13,10 +15,13 @@ public class PlayerConnectionUtils {
public static <T extends PacketListener> void ensureMainThread(Packet<T> packet, T t0, IAsyncTaskHandler<?> iasynctaskhandler) throws CancelledPacketHandleException {
if (!iasynctaskhandler.isMainThread()) {
+ Timing timing = MinecraftTimings.getPacketTiming(packet); // Paper - timings
iasynctaskhandler.execute(() -> {
if (MinecraftServer.getServer().hasStopped() || (t0 instanceof PlayerConnection && ((PlayerConnection) t0).processedDisconnect)) return; // CraftBukkit, MC-142590
if (t0.a().isConnected()) {
+ try (Timing ignored = timing.startTiming()) { // Paper - timings
packet.a(t0);
+ } // Paper - timings
} else {
PlayerConnectionUtils.LOGGER.debug("Ignoring packet due to disconnection: " + packet);
}
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
index 7e8c50aa92e036b88b1fd725021c31846eb06097..79cfcbce85e779fc8e8589840a27961f59209f3d 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
@@ -1,5 +1,6 @@
package net.minecraft.server;
+import co.aikar.timings.MinecraftTimings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -898,10 +899,11 @@ public abstract class PlayerList {
}
public void savePlayers() {
+ MinecraftTimings.savePlayers.startTiming(); // Paper
for (int i = 0; i < this.players.size(); ++i) {
this.savePlayerFile((EntityPlayer) this.players.get(i));
}
-
+ MinecraftTimings.savePlayers.stopTiming(); // Paper
}
public WhiteList getWhitelist() {
diff --git a/src/main/java/net/minecraft/server/TickListServer.java b/src/main/java/net/minecraft/server/TickListServer.java
index 00bbd34b6a2a8185bc6395d6c85bce6353c3cbc4..f533860bbed19ff2915c90186c259b466f41ce90 100644
--- a/src/main/java/net/minecraft/server/TickListServer.java
+++ b/src/main/java/net/minecraft/server/TickListServer.java
@@ -28,13 +28,18 @@ public class TickListServer<T> implements TickList<T> {
private final List<NextTickListEntry<T>> h = Lists.newArrayList();
private final Consumer<NextTickListEntry<T>> i;
- public TickListServer(WorldServer worldserver, Predicate<T> predicate, Function<T, MinecraftKey> function, Function<MinecraftKey, T> function1, Consumer<NextTickListEntry<T>> consumer) {
+ public TickListServer(WorldServer worldserver, Predicate<T> predicate, Function<T, MinecraftKey> function, Function<MinecraftKey, T> function1, Consumer<NextTickListEntry<T>> consumer, String timingsType) { // Paper
this.a = predicate;
this.b = function;
this.c = function1;
this.f = worldserver;
this.i = consumer;
+ this.timingCleanup = co.aikar.timings.WorldTimingsHandler.getTickList(worldserver, timingsType + " - Cleanup");
+ this.timingTicking = co.aikar.timings.WorldTimingsHandler.getTickList(worldserver, timingsType + " - Ticking");
}
+ private final co.aikar.timings.Timing timingCleanup; // Paper
+ private final co.aikar.timings.Timing timingTicking; // Paper
+ // Paper end
public void b() {
int i = this.nextTickList.size();
@@ -57,6 +62,7 @@ public class TickListServer<T> implements TickList<T> {
this.f.getMethodProfiler().enter("cleaning");
+ this.timingCleanup.startTiming(); // Paper
NextTickListEntry nextticklistentry;
while (i > 0 && iterator.hasNext()) {
@@ -72,7 +78,9 @@ public class TickListServer<T> implements TickList<T> {
--i;
}
}
+ this.timingCleanup.stopTiming(); // Paper
+ this.timingTicking.startTiming(); // Paper
this.f.getMethodProfiler().exitEnter("ticking");
while ((nextticklistentry = (NextTickListEntry) this.g.poll()) != null) {
@@ -93,6 +101,7 @@ public class TickListServer<T> implements TickList<T> {
}
this.f.getMethodProfiler().exit();
+ this.timingTicking.stopTiming(); // Paper
this.h.clear();
this.g.clear();
}
diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java
index 820180ab3f7053c348caa80cc21f15dfa3d26afd..fa6400dccd4df635d696e0858c0c164a0f19b4a4 100644
--- a/src/main/java/net/minecraft/server/TileEntity.java
+++ b/src/main/java/net/minecraft/server/TileEntity.java
@@ -9,11 +9,12 @@ import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
import org.bukkit.inventory.InventoryHolder;
// CraftBukkit end
-import org.spigotmc.CustomTimingsHandler; // Spigot
+import co.aikar.timings.MinecraftTimings; // Paper
+import co.aikar.timings.Timing; // Paper
public abstract class TileEntity implements KeyedObject { // Paper
- public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot
+ public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper
// CraftBukkit start - data containers
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
public CraftPersistentDataContainer persistentDataContainer;
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 45ded8cd3aee69083f6196765208d8c2430f0a02..a126a6d22ccee90d0aadb8513bda60455a703bf6 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -1,5 +1,7 @@
package net.minecraft.server;
+import co.aikar.timings.Timing;
+import co.aikar.timings.Timings;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.Collection;
@@ -18,7 +20,7 @@ import org.apache.logging.log4j.util.Supplier;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
-import org.bukkit.craftbukkit.SpigotTimings; // Spigot
+import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.CapturedBlockState;
@@ -73,7 +75,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
- public final SpigotTimings.WorldTimingsHandler timings; // Spigot
+ public final co.aikar.timings.WorldTimingsHandler timings; // Paper
public static BlockPosition lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
@@ -139,7 +141,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
public void c(WorldBorder worldborder, double d0) {}
});
// CraftBukkit end
- timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings
+ timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings
this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
}
@@ -723,15 +725,14 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
}
timings.tileEntityPending.stopTiming(); // Spigot
+ co.aikar.timings.TimingHistory.tileEntityTicks += this.tileEntityListTick.size(); // Paper
gameprofilerfiller.exit();
spigotConfig.currentPrimedTnt = 0; // Spigot
}
public void a(Consumer<Entity> consumer, Entity entity) {
try {
- SpigotTimings.tickEntityTimer.startTiming(); // Spigot
consumer.accept(entity);
- SpigotTimings.tickEntityTimer.stopTiming(); // Spigot
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Ticking entity");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being ticked");
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 545ec5a2de00e9a91b349e358db44ed16aa50e68..4ab77e8dc0f918bd4f069a0f886d04dea473f046 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -1,6 +1,8 @@
package net.minecraft.server;
import com.google.common.annotations.VisibleForTesting;
+import co.aikar.timings.TimingHistory; // Paper
+import co.aikar.timings.Timings; // Paper
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Queues;
@@ -40,7 +42,6 @@ import org.apache.logging.log4j.Logger;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.WeatherType;
-import org.bukkit.craftbukkit.SpigotTimings; // Spigot
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.server.MapInitializeEvent;
@@ -97,10 +98,10 @@ public class WorldServer extends World {
// CraftBukkit end
this.nextTickListBlock = new TickListServer<>(this, (block) -> {
return block == null || block.getBlockData().isAir();
- }, IRegistry.BLOCK::getKey, IRegistry.BLOCK::get, this::b);
+ }, IRegistry.BLOCK::getKey, IRegistry.BLOCK::get, this::b, "Blocks"); // Paper - Timings
this.nextTickListFluid = new TickListServer<>(this, (fluidtype) -> {
return fluidtype == null || fluidtype == FluidTypes.EMPTY;
- }, IRegistry.FLUID::getKey, IRegistry.FLUID::get, this::a);
+ }, IRegistry.FLUID::getKey, IRegistry.FLUID::get, this::a, "Fluids"); // Paper - Timings
this.navigators = Sets.newHashSet();
this.I = new ObjectLinkedOpenHashSet();
this.dataManager = worldnbtstorage;
@@ -305,20 +306,24 @@ public class WorldServer extends World {
this.N();
this.a();
gameprofilerfiller.exitEnter("chunkSource");
+ this.timings.chunkProviderTick.startTiming(); // Paper - timings
this.getChunkProvider().tick(booleansupplier);
+ this.timings.chunkProviderTick.stopTiming(); // Paper - timings
gameprofilerfiller.exitEnter("tickPending");
- timings.doTickPending.startTiming(); // Spigot
+ timings.scheduledBlocks.startTiming(); // Spigot
if (this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) {
this.nextTickListBlock.b();
this.nextTickListFluid.b();
}
- timings.doTickPending.stopTiming(); // Spigot
+ timings.scheduledBlocks.stopTiming(); // Spigot
gameprofilerfiller.exitEnter("raid");
+ this.timings.raids.startTiming(); // Paper - timings
this.persistentRaid.a();
if (this.mobSpawnerTrader != null) {
this.mobSpawnerTrader.a();
}
+ this.timings.raids.stopTiming(); // Paper - timings
gameprofilerfiller.exitEnter("blockEvents");
timings.doSounds.startTiming(); // Spigot
@@ -361,6 +366,7 @@ public class WorldServer extends World {
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
timings.entityTick.startTiming(); // Spigot
+ TimingHistory.entityTicks += this.globalEntityList.size(); // Paper
while (objectiterator.hasNext()) {
Entry<Entity> entry = (Entry) objectiterator.next();
Entity entity1 = (Entity) entry.getValue();
@@ -409,9 +415,11 @@ public class WorldServer extends World {
this.tickingEntities = false;
+ try (co.aikar.timings.Timing ignored = this.timings.newEntities.startTiming()) { // Paper - timings
while ((entity = (Entity) this.entitiesToAdd.poll()) != null) {
this.registerEntity(entity);
}
+ } // Paper - timings
gameprofilerfiller.exit();
timings.tickEntities.stopTiming(); // Spigot
@@ -476,6 +484,7 @@ public class WorldServer extends World {
}
gameprofilerfiller.exitEnter("tickBlocks");
+ timings.chunkTicksBlocks.startTiming(); // Paper
if (i > 0) {
ChunkSection[] achunksection = chunk.getSections();
int l = achunksection.length;
@@ -507,7 +516,7 @@ public class WorldServer extends World {
}
}
}
-
+ timings.chunkTicksBlocks.stopTiming(); // Paper
gameprofilerfiller.exit();
}
@@ -603,6 +612,7 @@ public class WorldServer extends World {
public void entityJoinedWorld(Entity entity) {
if (entity instanceof EntityHuman || this.getChunkProvider().a(entity)) {
+ ++TimingHistory.entityTicks; // Paper - timings
// Spigot start
if (!org.spigotmc.ActivationRange.checkIfActive(entity)) {
entity.ticksLived++;
@@ -611,7 +621,9 @@ public class WorldServer extends World {
}
// Spigot end
+ TimingHistory.activatedEntityTicks++; // Paper - timings
entity.tickTimer.startTiming(); // Spigot
+ try { // Paper - timings
entity.f(entity.locX(), entity.locY(), entity.locZ());
entity.lastYaw = entity.yaw;
entity.lastPitch = entity.pitch;
@@ -638,7 +650,9 @@ public class WorldServer extends World {
this.a(entity, entity1);
}
}
+ } finally { // Paper - timings
entity.tickTimer.stopTiming(); // Spigot
+ } // Paper - timings
}
}
@@ -799,6 +813,7 @@ public class WorldServer extends World {
if (!flag1) {
org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit
+ try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { // Paper
if (iprogressupdate != null) {
iprogressupdate.a(new ChatMessage("menu.savingLevel", new Object[0]));
}
@@ -808,7 +823,10 @@ public class WorldServer extends World {
iprogressupdate.c(new ChatMessage("menu.savingChunks", new Object[0]));
}
+ timings.worldSaveChunks.startTiming(); // Paper
chunkproviderserver.save(flag);
+ timings.worldSaveChunks.stopTiming(); // Paper
+ } // Paper
}
// CraftBukkit start - moved from MinecraftServer.saveChunks
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index ad1dcf53040695a1b3194efa92b549172bea56ec..1ceba5f7eae58426834d7042af17f7e3b1990a56 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1973,12 +1973,31 @@ public final class CraftServer implements Server {
private final Spigot spigot = new Spigot()
{
+ @Deprecated
@Override
public YamlConfiguration getConfig()
{
return org.spigotmc.SpigotConfig.config;
}
+ @Override
+ public YamlConfiguration getBukkitConfig()
+ {
+ return configuration;
+ }
+
+ @Override
+ public YamlConfiguration getSpigotConfig()
+ {
+ return org.spigotmc.SpigotConfig.config;
+ }
+
+ @Override
+ public YamlConfiguration getPaperConfig()
+ {
+ return com.destroystokyo.paper.PaperConfig.config;
+ }
+
@Override
public void restart() {
org.spigotmc.RestartCommand.restart();
diff --git a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java
deleted file mode 100644
index 2bd22a369825040c7f5074117d82ae83f07b6096..0000000000000000000000000000000000000000
--- a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package org.bukkit.craftbukkit;
-
-import java.util.HashMap;
-import net.minecraft.server.Entity;
-import net.minecraft.server.TileEntity;
-import net.minecraft.server.World;
-import org.bukkit.craftbukkit.scheduler.CraftTask;
-import org.bukkit.plugin.java.JavaPluginLoader;
-import org.bukkit.scheduler.BukkitTask;
-import org.spigotmc.CustomTimingsHandler;
-
-public class SpigotTimings {
-
- public static final CustomTimingsHandler serverTickTimer = new CustomTimingsHandler("** Full Server Tick");
- public static final CustomTimingsHandler playerListTimer = new CustomTimingsHandler("Player List");
- public static final CustomTimingsHandler commandFunctionsTimer = new CustomTimingsHandler("Command Functions");
- public static final CustomTimingsHandler connectionTimer = new CustomTimingsHandler("Connection Handler");
- public static final CustomTimingsHandler playerConnectionTimer = new CustomTimingsHandler("** PlayerConnection");
- public static final CustomTimingsHandler tickablesTimer = new CustomTimingsHandler("Tickables");
- public static final CustomTimingsHandler schedulerTimer = new CustomTimingsHandler("Scheduler");
- public static final CustomTimingsHandler timeUpdateTimer = new CustomTimingsHandler("Time Update");
- public static final CustomTimingsHandler serverCommandTimer = new CustomTimingsHandler("Server Command");
- public static final CustomTimingsHandler worldSaveTimer = new CustomTimingsHandler("World Save");
-
- public static final CustomTimingsHandler entityMoveTimer = new CustomTimingsHandler("** entityMove");
- public static final CustomTimingsHandler tickEntityTimer = new CustomTimingsHandler("** tickEntity");
- public static final CustomTimingsHandler activatedEntityTimer = new CustomTimingsHandler("** activatedTickEntity");
- public static final CustomTimingsHandler tickTileEntityTimer = new CustomTimingsHandler("** tickTileEntity");
-
- public static final CustomTimingsHandler timerEntityBaseTick = new CustomTimingsHandler("** livingEntityBaseTick");
- public static final CustomTimingsHandler timerEntityAI = new CustomTimingsHandler("** livingEntityAI");
- public static final CustomTimingsHandler timerEntityAICollision = new CustomTimingsHandler("** livingEntityAICollision");
- public static final CustomTimingsHandler timerEntityAIMove = new CustomTimingsHandler("** livingEntityAIMove");
- public static final CustomTimingsHandler timerEntityTickRest = new CustomTimingsHandler("** livingEntityTickRest");
-
- public static final CustomTimingsHandler processQueueTimer = new CustomTimingsHandler("processQueue");
- public static final CustomTimingsHandler schedulerSyncTimer = new CustomTimingsHandler("** Scheduler - Sync Tasks", JavaPluginLoader.pluginParentTimer);
-
- public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand");
-
- public static final CustomTimingsHandler entityActivationCheckTimer = new CustomTimingsHandler("entityActivationCheck");
- public static final CustomTimingsHandler checkIfActiveTimer = new CustomTimingsHandler("** checkIfActive");
-
- public static final HashMap<String, CustomTimingsHandler> entityTypeTimingMap = new HashMap<String, CustomTimingsHandler>();
- public static final HashMap<String, CustomTimingsHandler> tileEntityTypeTimingMap = new HashMap<String, CustomTimingsHandler>();
- public static final HashMap<String, CustomTimingsHandler> pluginTaskTimingMap = new HashMap<String, CustomTimingsHandler>();
-
- /**
- * Gets a timer associated with a plugins tasks.
- * @param task
- * @param period
- * @return
- */
- public static CustomTimingsHandler getPluginTaskTimings(BukkitTask task, long period) {
- if (!task.isSync()) {
- return null;
- }
- String plugin;
- final CraftTask ctask = (CraftTask) task;
-
- if (task.getOwner() != null) {
- plugin = task.getOwner().getDescription().getFullName();
- } else {
- plugin = "Unknown";
- }
- String taskname = ctask.getTaskName();
-
- String name = "Task: " + plugin + " Runnable: " + taskname;
- if (period > 0) {
- name += "(interval:" + period +")";
- } else {
- name += "(Single)";
- }
- CustomTimingsHandler result = pluginTaskTimingMap.get(name);
- if (result == null) {
- result = new CustomTimingsHandler(name, SpigotTimings.schedulerSyncTimer);
- pluginTaskTimingMap.put(name, result);
- }
- return result;
- }
-
- /**
- * Get a named timer for the specified entity type to track type specific timings.
- * @param entity
- * @return
- */
- public static CustomTimingsHandler getEntityTimings(Entity entity) {
- String entityType = entity.getClass().getName();
- CustomTimingsHandler result = entityTypeTimingMap.get(entityType);
- if (result == null) {
- result = new CustomTimingsHandler("** tickEntity - " + entity.getClass().getSimpleName(), activatedEntityTimer);
- entityTypeTimingMap.put(entityType, result);
- }
- return result;
- }
-
- /**
- * Get a named timer for the specified tile entity type to track type specific timings.
- * @param entity
- * @return
- */
- public static CustomTimingsHandler getTileEntityTimings(TileEntity entity) {
- String entityType = entity.getClass().getName();
- CustomTimingsHandler result = tileEntityTypeTimingMap.get(entityType);
- if (result == null) {
- result = new CustomTimingsHandler("** tickTileEntity - " + entity.getClass().getSimpleName(), tickTileEntityTimer);
- tileEntityTypeTimingMap.put(entityType, result);
- }
- return result;
- }
-
- /**
- * Set of timers per world, to track world specific timings.
- */
- public static class WorldTimingsHandler {
- public final CustomTimingsHandler mobSpawn;
- public final CustomTimingsHandler doChunkUnload;
- public final CustomTimingsHandler doTickPending;
- public final CustomTimingsHandler doTickTiles;
- public final CustomTimingsHandler doChunkMap;
- public final CustomTimingsHandler doSounds;
- public final CustomTimingsHandler entityTick;
- public final CustomTimingsHandler tileEntityTick;
- public final CustomTimingsHandler tileEntityPending;
- public final CustomTimingsHandler tracker;
- public final CustomTimingsHandler doTick;
- public final CustomTimingsHandler tickEntities;
-
- public final CustomTimingsHandler syncChunkLoadTimer;
- public final CustomTimingsHandler syncChunkLoadStructuresTimer;
- public final CustomTimingsHandler syncChunkLoadEntitiesTimer;
- public final CustomTimingsHandler syncChunkLoadTileEntitiesTimer;
- public final CustomTimingsHandler syncChunkLoadTileTicksTimer;
- public final CustomTimingsHandler syncChunkLoadPostTimer;
-
- public WorldTimingsHandler(World server) {
- String name = server.worldData.getName() +" - ";
-
- mobSpawn = new CustomTimingsHandler("** " + name + "mobSpawn");
- doChunkUnload = new CustomTimingsHandler("** " + name + "doChunkUnload");
- doTickPending = new CustomTimingsHandler("** " + name + "doTickPending");
- doTickTiles = new CustomTimingsHandler("** " + name + "doTickTiles");
- doChunkMap = new CustomTimingsHandler("** " + name + "doChunkMap");
- doSounds = new CustomTimingsHandler("** " + name + "doSounds");
- entityTick = new CustomTimingsHandler("** " + name + "entityTick");
- tileEntityTick = new CustomTimingsHandler("** " + name + "tileEntityTick");
- tileEntityPending = new CustomTimingsHandler("** " + name + "tileEntityPending");
-
- syncChunkLoadTimer = new CustomTimingsHandler("** " + name + "syncChunkLoad");
- syncChunkLoadStructuresTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Structures");
- syncChunkLoadEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Entities");
- syncChunkLoadTileEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileEntities");
- syncChunkLoadTileTicksTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileTicks");
- syncChunkLoadPostTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Post");
-
-
- tracker = new CustomTimingsHandler(name + "tracker");
- doTick = new CustomTimingsHandler(name + "doTick");
- tickEntities = new CustomTimingsHandler(name + "tickEntities");
- }
- }
-}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index db0bd5cc0acb5523815183ba9c4a8b853a9e9d12..48d1397a6846c64dfa372390783ce66827153bf9 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1717,6 +1717,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
packet.components = components;
getHandle().playerConnection.sendPacket(packet);
}
+
+ // Paper start
+ @Override
+ public int getPing()
+ {
+ return getHandle().ping;
+ }
+ // Paper end
};
public Player.Spigot spigot()
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index 533c0bc55fc7ac4cc1f493f898a85a6617371031..de332758e03a563a9b72c134332db9e6a1c5ed2b 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.scheduler;
+import co.aikar.timings.MinecraftTimings; // Paper
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.ArrayList;
import java.util.Comparator;
@@ -179,7 +180,8 @@ public class CraftScheduler implements BukkitScheduler {
}
public BukkitTask scheduleInternalTask(Runnable run, int delay, String taskName) {
- final CraftTask task = new CraftTask(run, nextId(), taskName);
+ final CraftTask task = new CraftTask(run, nextId(), "Internal - " + (taskName != null ? taskName : "Unknown"));
+ task.internal = true;
return handle(task, delay);
}
@@ -260,7 +262,7 @@ public class CraftScheduler implements BukkitScheduler {
}
return false;
}
- });
+ }){{this.timings=co.aikar.timings.MinecraftTimings.getCancelTasksTimer();}}; // Paper
handle(task, 0L);
for (CraftTask taskPending = head.getNext(); taskPending != null; taskPending = taskPending.getNext()) {
if (taskPending == task) {
@@ -295,7 +297,7 @@ public class CraftScheduler implements BukkitScheduler {
}
}
}
- });
+ }){{this.timings=co.aikar.timings.MinecraftTimings.getCancelTasksTimer(plugin);}}; // Paper
handle(task, 0L);
for (CraftTask taskPending = head.getNext(); taskPending != null; taskPending = taskPending.getNext()) {
if (taskPending == task) {
@@ -402,9 +404,7 @@ public class CraftScheduler implements BukkitScheduler {
if (task.isSync()) {
currentTask = task;
try {
- task.timings.startTiming(); // Spigot
task.run();
- task.timings.stopTiming(); // Spigot
} catch (final Throwable throwable) {
task.getOwner().getLogger().log(
Level.WARNING,
@@ -431,8 +431,10 @@ public class CraftScheduler implements BukkitScheduler {
runners.remove(task.getTaskId());
}
}
+ MinecraftTimings.bukkitSchedulerFinishTimer.startTiming();
pending.addAll(temp);
temp.clear();
+ MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming();
debugHead = debugHead.getNextHead(currentTick);
}
@@ -465,6 +467,7 @@ public class CraftScheduler implements BukkitScheduler {
}
private void parsePending() {
+ MinecraftTimings.bukkitSchedulerPendingTimer.startTiming();
CraftTask head = this.head;
CraftTask task = head.getNext();
CraftTask lastTask = head;
@@ -483,6 +486,7 @@ public class CraftScheduler implements BukkitScheduler {
task.setNext(null);
}
this.head = lastTask;
+ MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming();
}
private boolean isReady(final int currentTick) {
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java
index d85e21b75054067b926ecfee89d62c6dd0744189..ce495907f13dd10b5daba521101a78d65a2e8836 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java
@@ -1,9 +1,11 @@
package org.bukkit.craftbukkit.scheduler;
import java.util.function.Consumer;
+
+import co.aikar.timings.NullTimingHandler;
import org.bukkit.Bukkit;
-import org.bukkit.craftbukkit.SpigotTimings; // Spigot
-import org.spigotmc.CustomTimingsHandler; // Spigot
+import co.aikar.timings.MinecraftTimings; // Paper
+import co.aikar.timings.Timing; // Paper
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
@@ -26,12 +28,12 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot
*/
private volatile long period;
private long nextRun;
- private final Runnable rTask;
- private final Consumer<BukkitTask> cTask;
+ public final Runnable rTask; // Paper
+ public final Consumer<BukkitTask> cTask; // Paper
+ public Timing timings; // Paper
private final Plugin plugin;
private final int id;
- final CustomTimingsHandler timings; // Spigot
CraftTask() {
this(null, null, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING);
}
@@ -51,11 +53,11 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot
this.id = id;
this.period = CraftTask.NO_REPEATING;
this.taskName = taskName;
- this.timings = null; // Will be changed in later patch
+ this.timings = MinecraftTimings.getInternalTaskName(taskName);
}
// Paper end
- CraftTask(final Plugin plugin, final Object task, final int id, final long period) {
+ CraftTask(final Plugin plugin, final Object task, final int id, final long period) { // Paper
this.plugin = plugin;
if (task instanceof Runnable) {
this.rTask = (Runnable) task;
@@ -72,7 +74,7 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot
}
this.id = id;
this.period = period;
- this.timings = this.isSync() ? SpigotTimings.getPluginTaskTimings(this, period) : null; // Spigot
+ timings = task != null ? MinecraftTimings.getPluginTaskTimings(this, period) : NullTimingHandler.NULL; // Paper
}
@Override
@@ -92,11 +94,13 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot
@Override
public void run() {
+ try (Timing ignored = timings.startTiming()) { // Paper
if (rTask != null) {
rTask.run();
} else {
cTask.accept(this);
}
+ } // Paper
}
long getPeriod() {
@@ -123,7 +127,7 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot
this.next = next;
}
- Class<?> getTaskClass() {
+ public Class<?> getTaskClass() {
return (rTask != null) ? rTask.getClass() : ((cTask != null) ? cTask.getClass() : null);
}
@@ -147,9 +151,4 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot
return true;
}
- // Spigot start
- public String getTaskName() {
- return (getTaskClass() == null) ? "Unknown" : getTaskClass().getName();
- }
- // Spigot end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java
index e52ef47b783785dc214746b678e7b549aea9a274..3d90b3426873a3528af14f7f1ab0adae0027da2e 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java
@@ -5,6 +5,7 @@ import org.bukkit.util.CachedServerIcon;
public class CraftIconCache implements CachedServerIcon {
public final String value;
+ public String getData() { return value; } // Paper
public CraftIconCache(final String value) {
this.value = value;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index 68728b4d86c4037fb1907bd16d86df5e23e8fe77..f647450b8c6977b4a6bb1819b34052c4ae2fe0f4 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -133,6 +133,12 @@ public final class CraftMagicNumbers implements UnsafeValues {
return CraftNamespacedKey.toMinecraft(mat.getKey());
}
// ========================================================================
+ // Paper start
+ @Override
+ public void reportTimings() {
+ co.aikar.timings.TimingsExport.reportTimings();
+ }
+ // Paper end
public static byte toLegacyData(IBlockData data) {
return CraftLegacy.toLegacyData(data);
@@ -298,6 +304,13 @@ public final class CraftMagicNumbers implements UnsafeValues {
return clazz;
}
+ // Paper start
+ @Override
+ public String getTimingsServerName() {
+ return com.destroystokyo.paper.PaperConfig.timingsServerName;
+ }
+ // Paper end
+
/**
* This helper class represents the different NBT Tags.
* <p>
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index ca7789b5e0f0baf0a1b0529236d6469b2abae236..4423839697987e255e5a93bdd6742186dde2e4c4 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -31,7 +31,7 @@ import net.minecraft.server.EntityWither;
import net.minecraft.server.MathHelper;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.World;
-import org.bukkit.craftbukkit.SpigotTimings;
+import co.aikar.timings.MinecraftTimings;
public class ActivationRange
{
@@ -75,8 +75,8 @@ public class ActivationRange
/**
* These entities are excluded from Activation range checks.
*
- * @param entity
- * @param config
+ * @param entity Entity to initialize
+ * @param config Spigot config to determine ranges
* @return boolean If it should always tick.
*/
public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config)
@@ -111,7 +111,7 @@ public class ActivationRange
*/
public static void activateEntities(World world)
{
- SpigotTimings.entityActivationCheckTimer.startTiming();
+ MinecraftTimings.entityActivationCheckTimer.startTiming();
final int miscActivationRange = world.spigotConfig.miscActivationRange;
final int raiderActivationRange = world.spigotConfig.raiderActivationRange;
final int animalActivationRange = world.spigotConfig.animalActivationRange;
@@ -148,7 +148,7 @@ public class ActivationRange
}
}
}
- SpigotTimings.entityActivationCheckTimer.stopTiming();
+ MinecraftTimings.entityActivationCheckTimer.stopTiming();
}
/**
@@ -245,10 +245,8 @@ public class ActivationRange
*/
public static boolean checkIfActive(Entity entity)
{
- SpigotTimings.checkIfActiveTimer.startTiming();
// Never safe to skip fireworks or entities not yet added to chunk
if ( !entity.inChunk || entity instanceof EntityFireworks ) {
- SpigotTimings.checkIfActiveTimer.stopTiming();
return true;
}
@@ -272,7 +270,6 @@ public class ActivationRange
{
isActive = false;
}
- SpigotTimings.checkIfActiveTimer.stopTiming();
return isActive;
}
}