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 4f6bc05180
commit ab45edb82c
3 changed files with 82 additions and 47 deletions

View File

@ -4,8 +4,10 @@
<artifactId>dynmap</artifactId>
<name>dynmap</name>
<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>
<BUILD_NUMBER>Dev</BUILD_NUMBER>
<BUILD_NUMBER>Dev(${timestamp})</BUILD_NUMBER>
</properties>
<url>http://github.com/webbukkit/dynmap/</url>
<issueManagement>

View File

@ -49,7 +49,6 @@ import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerBedLeaveEvent;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
@ -111,7 +110,17 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private Method ismodloaded;
private HashMap<String, BukkitWorld> world_by_name = new HashMap<String, BukkitWorld>();
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>();
/* Lookup cache */
private World last_world;
@ -201,8 +210,6 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
public class BukkitServer implements DynmapServerInterface {
/* Chunk load handling */
private Object loadlock = new Object();
private int chunks_in_cur_tick = 0;
private long cur_tick;
@Override
public int getBlockIDAt(String wname, int x, int y, int z) {
@ -298,36 +305,22 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}, DynmapPlugin.this);
break;
case PLAYER_CHAT:
try {
Class.forName("org.bukkit.event.player.AsyncPlayerChatEvent");
pm.registerEvents(new Listener() {
@EventHandler(priority=EventPriority.MONITOR)
public void onPlayerChat(AsyncPlayerChatEvent evt) {
if(evt.isCancelled()) return;
final Player p = evt.getPlayer();
final String msg = evt.getMessage();
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
public void run() {
DynmapPlayer dp = null;
if(p != null)
dp = new BukkitPlayer(p);
core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
}
});
}
}, 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);
}
pm.registerEvents(new Listener() {
@EventHandler(priority=EventPriority.MONITOR)
public void onPlayerChat(AsyncPlayerChatEvent evt) {
if(evt.isCancelled()) return;
final Player p = evt.getPlayer();
final String msg = evt.getMessage();
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
public void run() {
DynmapPlayer dp = null;
if(p != null)
dp = new BukkitPlayer(p);
core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
}
});
}
}, DynmapPlugin.this);
break;
case BLOCK_BREAK:
pm.registerEvents(new Listener() {
@ -458,22 +451,25 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
final MapChunkCache cc = c;
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>() {
public Boolean call() throws Exception {
boolean exhausted;
boolean exhausted = true;
synchronized(loadlock) {
if (prev_tick != cur_tick) {
prev_tick = cur_tick;
cur_tick_starttime = System.nanoTime();
}
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;
}
@ -528,6 +524,11 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
return false;
}
@Override
public double getServerTPS() {
return tps;
}
}
/**
* Player access abstraction class
@ -811,6 +812,16 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
else {
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() {
@ -872,7 +883,24 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
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
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
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
fullrenderplayerlimit: 0
# If nonzero, server will pause update render processing when 'updateplayerlimit' or more users are logged in
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