From ce48a8a1394d0489e664237ca15a0e2249f10672 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 22 Feb 2015 12:02:19 +1100 Subject: [PATCH] Allow Capping (Tile)Entity Tick Time. This patch adds world configuration options for max-tick-time.entity / max-tick-time.tile which allows setting a hard cap on the amount of time (in milliseconds) that a tick can consume. The default values of 50ms each are very conservative and mean this feature will not activate until the server is well below 15tps (minimum). Values of 20ms each have been reported to provide a good performance increase, however I personally think 25ms for entities and 10-15ms for tiles would give even more significant gains, assuming that these things are not a large priority on your server. For tiles there is very little tradeoff for this option, as tile ticks are based on wall time for most things, however for entities setting this option too low could lead to jerkiness / lag. The gain however is a faster and more responsive server to other actions such as blocks, chat, combat etc. This feature was commisioned by Chunkr. --- ...-Allow-Capping-Tile-Entity-Tick-Time.patch | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 CraftBukkit-Patches/0160-Allow-Capping-Tile-Entity-Tick-Time.patch diff --git a/CraftBukkit-Patches/0160-Allow-Capping-Tile-Entity-Tick-Time.patch b/CraftBukkit-Patches/0160-Allow-Capping-Tile-Entity-Tick-Time.patch new file mode 100644 index 000000000..54aab0a64 --- /dev/null +++ b/CraftBukkit-Patches/0160-Allow-Capping-Tile-Entity-Tick-Time.patch @@ -0,0 +1,126 @@ +From 68ec195e993411b192de078d2c00a47146558487 Mon Sep 17 00:00:00 2001 +From: md_5 +Date: Fri, 20 Feb 2015 21:39:31 +1100 +Subject: [PATCH] Allow Capping (Tile)Entity Tick Time. + +This patch adds world configuration options for max-tick-time.entity / max-tick-time.tile which allows setting a hard cap on the amount of time (in milliseconds) that a tick can consume. The default values of 50ms each are very conservative and mean this feature will not activate until the server is well below 15tps (minimum). Values of 20ms each have been reported to provide a good performance increase, however I personally think 25ms for entities and 10-15ms for tiles would give even more significant gains, assuming that these things are not a large priority on your server. + +For tiles there is very little tradeoff for this option, as tile ticks are based on wall time for most things, however for entities setting this option too low could lead to jerkiness / lag. The gain however is a faster and more responsive server to other actions such as blocks, chat, combat etc. + +This feature was commisioned by Chunkr. + +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index c50aa62..ade51a9 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -134,6 +134,9 @@ public abstract class World implements IBlockAccess { + public static boolean haveWeSilencedAPhysicsCrash; + public static String blockLocation; + public List triggerHoppersList = new ArrayList(); // Spigot, When altHopperTicking, tile entities being added go through here. ++ private org.spigotmc.TickLimiter entityLimiter; ++ private org.spigotmc.TickLimiter tileLimiter; ++ private int tileTickPosition; + + public static long chunkToKey(int x, int z) + { +@@ -234,6 +237,8 @@ public abstract class World implements IBlockAccess { + + this.getServer().addWorld(this.world); // CraftBukkit + timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - 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); + } + + public World b() { +@@ -1393,7 +1398,11 @@ public abstract class World implements IBlockAccess { + timings.entityTick.startTiming(); // Spigot + guardEntityList = true; // Spigot + // CraftBukkit start - Use field for loop variable +- for (this.tickPosition = 0; this.tickPosition < this.entityList.size(); ++this.tickPosition) { ++ int entitiesThisCycle = 0; ++ for (entityLimiter.initTick(); ++ entitiesThisCycle < entityList.size() && (entitiesThisCycle % 10 == 0 || entityLimiter.shouldContinue()); ++ tickPosition++, entitiesThisCycle++) { ++ tickPosition = (tickPosition < entityList.size()) ? tickPosition : 0; + entity = (Entity) this.entityList.get(this.tickPosition); + // CraftBukkit end + if (entity.vehicle != null) { +@@ -1451,14 +1460,18 @@ public abstract class World implements IBlockAccess { + // CraftBukkit end + + this.initializeHoppers(); // Spigot - Initializes hoppers which have been added recently. +- Iterator iterator = this.tileEntityList.iterator(); + +- while (iterator.hasNext()) { +- TileEntity tileentity = (TileEntity) iterator.next(); ++ // Spigot start ++ int tilesThisCycle = 0; ++ for (tileLimiter.initTick(); ++ tilesThisCycle < tileEntityList.size() && (tilesThisCycle % 10 == 0 || tileLimiter.shouldContinue()); ++ tileTickPosition++, tilesThisCycle++) { ++ tileTickPosition = (tileTickPosition < tileEntityList.size()) ? tileTickPosition : 0; ++ TileEntity tileentity = (TileEntity) this.tileEntityList.get(tileTickPosition); + // Spigot start + if (tileentity == null) { + getServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash"); +- iterator.remove(); ++ this.tileEntityList.remove(tileTickPosition--); + continue; + } + // Spigot end +@@ -1486,7 +1499,7 @@ public abstract class World implements IBlockAccess { + } + + if (tileentity.x()) { +- iterator.remove(); ++ this.tileEntityList.remove(tileTickPosition--); + this.h.remove(tileentity); + if (this.isLoaded(tileentity.getPosition())) { + this.getChunkAtWorldCoords(tileentity.getPosition()).e(tileentity.getPosition()); +diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java +index b4f32f0..908d980 100644 +--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java ++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java +@@ -355,4 +355,13 @@ public class SpigotWorldConfig + { + hangingTickFrequency = getInt( "hanging-tick-frequency", 100 ); + } ++ ++ public int tileMaxTickTime; ++ public int entityMaxTickTime; ++ private void maxTickTimes() ++ { ++ tileMaxTickTime = getInt("max-tick-time.tile", 50); ++ entityMaxTickTime = getInt("max-tick-time.entity", 50); ++ log("Tile Max Tick Time: " + tileMaxTickTime + "ms Entity max Tick Time: " + entityMaxTickTime + "ms"); ++ } + } +diff --git a/src/main/java/org/spigotmc/TickLimiter.java b/src/main/java/org/spigotmc/TickLimiter.java +new file mode 100644 +index 0000000..23a3938 +--- /dev/null ++++ b/src/main/java/org/spigotmc/TickLimiter.java +@@ -0,0 +1,20 @@ ++package org.spigotmc; ++ ++public class TickLimiter { ++ ++ private final int maxTime; ++ private long startTime; ++ ++ public TickLimiter(int maxtime) { ++ this.maxTime = maxtime; ++ } ++ ++ public void initTick() { ++ startTime = System.currentTimeMillis(); ++ } ++ ++ public boolean shouldContinue() { ++ long remaining = System.currentTimeMillis() - startTime; ++ return remaining < maxTime; ++ } ++} +-- +2.1.0 +