Add settings for TPS limits and per-tick msec limits

This commit is contained in:
Mike Primm 2013-06-19 23:20:38 -05:00
parent 1f32d0d535
commit e0cce6bbd3
3 changed files with 82 additions and 47 deletions

View file

@ -4,8 +4,10 @@
<artifactId>dynmap</artifactId> <artifactId>dynmap</artifactId>
<name>dynmap</name> <name>dynmap</name>
<properties> <properties>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<BUILD_NUMBER>Dev</BUILD_NUMBER> <BUILD_NUMBER>Dev(${timestamp})</BUILD_NUMBER>
</properties> </properties>
<url>http://github.com/webbukkit/dynmap/</url> <url>http://github.com/webbukkit/dynmap/</url>
<issueManagement> <issueManagement>

View file

@ -49,7 +49,6 @@ import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerBedLeaveEvent; import org.bukkit.event.player.PlayerBedLeaveEvent;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
@ -111,7 +110,17 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private Method ismodloaded; private Method ismodloaded;
private HashMap<String, BukkitWorld> world_by_name = new HashMap<String, BukkitWorld>(); private HashMap<String, BukkitWorld> world_by_name = new HashMap<String, BukkitWorld>();
private HashSet<String> modsused = new HashSet<String>(); private HashSet<String> modsused = new HashSet<String>();
// TPS calculator
private double tps;
private long lasttick;
private long perTickLimit;
private long cur_tick_starttime;
private long avgticklen = 50000000;
private int chunks_in_cur_tick = 0;
private long cur_tick;
private long prev_tick;
private HashMap<String, Integer> sortWeights = new HashMap<String, Integer>(); private HashMap<String, Integer> sortWeights = new HashMap<String, Integer>();
/* Lookup cache */ /* Lookup cache */
private World last_world; private World last_world;
@ -201,8 +210,6 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
public class BukkitServer implements DynmapServerInterface { public class BukkitServer implements DynmapServerInterface {
/* Chunk load handling */ /* Chunk load handling */
private Object loadlock = new Object(); private Object loadlock = new Object();
private int chunks_in_cur_tick = 0;
private long cur_tick;
@Override @Override
public int getBlockIDAt(String wname, int x, int y, int z) { public int getBlockIDAt(String wname, int x, int y, int z) {
@ -298,36 +305,22 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}, DynmapPlugin.this); }, DynmapPlugin.this);
break; break;
case PLAYER_CHAT: case PLAYER_CHAT:
try { pm.registerEvents(new Listener() {
Class.forName("org.bukkit.event.player.AsyncPlayerChatEvent"); @EventHandler(priority=EventPriority.MONITOR)
pm.registerEvents(new Listener() { public void onPlayerChat(AsyncPlayerChatEvent evt) {
@EventHandler(priority=EventPriority.MONITOR) if(evt.isCancelled()) return;
public void onPlayerChat(AsyncPlayerChatEvent evt) { final Player p = evt.getPlayer();
if(evt.isCancelled()) return; final String msg = evt.getMessage();
final Player p = evt.getPlayer(); getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
final String msg = evt.getMessage(); public void run() {
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() { DynmapPlayer dp = null;
public void run() { if(p != null)
DynmapPlayer dp = null; dp = new BukkitPlayer(p);
if(p != null) core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
dp = new BukkitPlayer(p); }
core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg); });
} }
}); }, DynmapPlugin.this);
}
}, DynmapPlugin.this);
} catch (ClassNotFoundException cnfx) {
pm.registerEvents(new Listener() {
@EventHandler(priority=EventPriority.MONITOR)
public void onPlayerChat(PlayerChatEvent evt) {
if(evt.isCancelled()) return;
DynmapPlayer p = null;
if(evt.getPlayer() != null)
p = new BukkitPlayer(evt.getPlayer());
core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, p, evt.getMessage());
}
}, DynmapPlugin.this);
}
break; break;
case BLOCK_BREAK: case BLOCK_BREAK:
pm.registerEvents(new Listener() { pm.registerEvents(new Listener() {
@ -458,22 +451,25 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
final MapChunkCache cc = c; final MapChunkCache cc = c;
while(!cc.isDoneLoading()) { while(!cc.isDoneLoading()) {
synchronized(loadlock) {
long now = System.currentTimeMillis();
if(cur_tick != (now/50)) { /* New tick? */
chunks_in_cur_tick = mapManager.getMaxChunkLoadsPerTick();
cur_tick = now/50;
}
}
Future<Boolean> f = core.getServer().callSyncMethod(new Callable<Boolean>() { Future<Boolean> f = core.getServer().callSyncMethod(new Callable<Boolean>() {
public Boolean call() throws Exception { public Boolean call() throws Exception {
boolean exhausted; boolean exhausted = true;
synchronized(loadlock) { synchronized(loadlock) {
if (prev_tick != cur_tick) {
prev_tick = cur_tick;
cur_tick_starttime = System.nanoTime();
}
if(chunks_in_cur_tick > 0) { if(chunks_in_cur_tick > 0) {
chunks_in_cur_tick -= cc.loadChunks(chunks_in_cur_tick); boolean done = false;
while (!done) {
int cnt = chunks_in_cur_tick;
if (cnt > 5) cnt = 5;
chunks_in_cur_tick -= cc.loadChunks(cnt);
exhausted = (chunks_in_cur_tick == 0) || ((System.nanoTime() - cur_tick_starttime) > perTickLimit);
done = exhausted || cc.isDoneLoading();
}
} }
exhausted = (chunks_in_cur_tick == 0);
} }
return exhausted; return exhausted;
} }
@ -528,6 +524,11 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
} }
return false; return false;
} }
@Override
public double getServerTPS() {
return tps;
}
} }
/** /**
* Player access abstraction class * Player access abstraction class
@ -811,6 +812,16 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
else { else {
doEnable(); doEnable();
} }
// Start tps calculation
lasttick = System.nanoTime();
tps = 20.0;
perTickLimit = core.getMaxTickUseMS() * 1000000;
getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
processTick();
}
}, 1, 1);
} }
private boolean readyToEnable() { private boolean readyToEnable() {
@ -872,7 +883,24 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
} }
Log.info("Disabled"); Log.info("Disabled");
} }
private void processTick() {
long now = System.nanoTime();
long elapsed = now - lasttick;
lasttick = now;
avgticklen = ((avgticklen * 99) / 100) + (elapsed / 100);
tps = (double)1E9 / (double)avgticklen;
if (mapManager != null) {
chunks_in_cur_tick = mapManager.getMaxChunkLoadsPerTick();
}
cur_tick++;
// Tick core
if (core != null) {
core.serverTick(tps);
}
}
@Override @Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
DynmapCommandSender dsender; DynmapCommandSender dsender;

View file

@ -310,9 +310,14 @@ updaterate: 2000
# If nonzero, server will pause fullrender/radiusrender processing when 'fullrenderplayerlimit' or more users are logged in # If nonzero, server will pause fullrender/radiusrender processing when 'fullrenderplayerlimit' or more users are logged in
fullrenderplayerlimit: 0 fullrenderplayerlimit: 0
# If nonzero, server will pause update render processing when 'updateplayerlimit' or more users are logged in # If nonzero, server will pause update render processing when 'updateplayerlimit' or more users are logged in
updateplayerlimit: 0 updateplayerlimit: 0
# Target limit on server thread use - msec per tick
per-tick-time-limit: 50
# If TPS of server is below this setting, update renders processing is paused
update-min-tps: 18.0
# If TPS of server is below this setting, full/radius renders processing is paused
fullrender-min-tps: 18.0
showplayerfacesinmenu: true showplayerfacesinmenu: true