From 8281788d504c1618e1129a3dc19ce80b64d1c22c Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 4 Nov 2016 02:12:10 -0400
Subject: [PATCH] Chunk Save Stats Debug Option

Adds a command line flag to enable stats on how chunk saves are processing.

Stats on current queue, how many was processed and how many were queued.

diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index c1a42e61e7..c96f1b2753 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -36,6 +36,11 @@ public class ChunkProviderServer implements IChunkProvider {
     public final Long2ObjectMap<Chunk> chunks = Long2ObjectMaps.synchronize(new ChunkMap(8192));
     private final ChunkTaskScheduler f;
     private final SchedulerBatch<ChunkCoordIntPair, ChunkStatus, ProtoChunk> g;
+    // Paper start - chunk save stats
+    private long lastQueuedSaves = 0L; // Paper
+    private long lastProcessedSaves = 0L; // Paper
+    private long lastSaveStatPrinted = System.currentTimeMillis();
+    // Paper end
     public final WorldServer world;
 
     public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, ChunkGenerator<?> chunkgenerator, IAsyncTaskHandler iasynctaskhandler) {
@@ -263,6 +268,30 @@ public class ChunkProviderServer implements IChunkProvider {
         // Paper start
         final ChunkRegionLoader chunkLoader = (ChunkRegionLoader) world.getChunkProviderServer().chunkLoader;
         final int queueSize = chunkLoader.getQueueSize();
+
+        final long now = System.currentTimeMillis();
+        final long timeSince = (now - lastSaveStatPrinted) / 1000;
+        final Integer printRateSecs = Integer.getInteger("printSaveStats");
+        if (printRateSecs != null && timeSince >= printRateSecs) {
+            final String timeStr = "/" + timeSince  +"s";
+            final long queuedSaves = chunkLoader.getQueuedSaves();
+            long queuedDiff = queuedSaves - lastQueuedSaves;
+            lastQueuedSaves = queuedSaves;
+
+            final long processedSaves = chunkLoader.getProcessedSaves();
+            long processedDiff = processedSaves - lastProcessedSaves;
+            lastProcessedSaves = processedSaves;
+
+            lastSaveStatPrinted = now;
+            if (processedDiff > 0 || queueSize > 0 || queuedDiff > 0) {
+                System.out.println("[Chunk Save Stats] " + world.worldData.getName() +
+                    " - Current: " + queueSize +
+                    " - Queued: " + queuedDiff + timeStr +
+                    " - Processed: " +processedDiff + timeStr
+                );
+            }
+        }
+
         if (queueSize > world.paperConfig.queueSizeAutoSaveThreshold){
             return false;
         }
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index 859148cb86..ea8684747d 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -137,7 +137,13 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
         }
     }
 
-    public int getQueueSize() { return queue.size(); } // Paper
+    // Paper start
+    private long queuedSaves = 0;
+    private final java.util.concurrent.atomic.AtomicLong processedSaves = new java.util.concurrent.atomic.AtomicLong(0L);
+    public int getQueueSize() { return queue.size(); }
+    public long getQueuedSaves() { return queuedSaves; }
+    public long getProcessedSaves() { return processedSaves.longValue(); }
+    // Paper end
 
     // CraftBukkit start - Add async variant, provide compatibility
     @Nullable
@@ -325,6 +331,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
 
     protected synchronized void a(ChunkCoordIntPair chunkcoordintpair, Supplier<NBTTagCompound> nbttagcompound) { // Spigot
         queue.add(new QueuedChunk(chunkcoordintpair, nbttagcompound)); // Paper - Chunk queue improvements
+        queuedSaves++; // Paper
         this.b.put(chunkcoordintpair, nbttagcompound);
         FileIOThread.a().a(this);
     }
@@ -348,6 +355,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
             return false;
         } else {
             ChunkCoordIntPair chunkcoordintpair = chunk.coords; // Paper - Chunk queue improvements
+            processedSaves.incrementAndGet(); // Paper
 
             boolean flag;
 
-- 
2.18.0