From 65f16463eccd3191a7693046522d12a027df02eb Mon Sep 17 00:00:00 2001 From: tom lee Date: Sun, 6 Feb 2022 18:07:53 +0800 Subject: [PATCH] Added Memory Stat Dumping via pressing `p` --- .../com/seibel/lod/core/api/ClientApi.java | 40 +++++++++++-- .../lod/core/objects/lod/LevelContainer.java | 6 ++ .../lod/core/objects/lod/LodDimension.java | 42 ++++++++++++- .../lod/core/objects/lod/LodRegion.java | 3 + .../objects/lod/VerticalLevelContainer.java | 6 ++ .../lod/core/util/SpamReducedLogger.java | 59 +++++++++++++++++++ .../com/seibel/lod/core/util/UnitBytes.java | 44 ++++++++++++++ 7 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/seibel/lod/core/util/SpamReducedLogger.java create mode 100644 src/main/java/com/seibel/lod/core/util/UnitBytes.java diff --git a/src/main/java/com/seibel/lod/core/api/ClientApi.java b/src/main/java/com/seibel/lod/core/api/ClientApi.java index 89633d414..d76eb3941 100644 --- a/src/main/java/com/seibel/lod/core/api/ClientApi.java +++ b/src/main/java/com/seibel/lod/core/api/ClientApi.java @@ -19,7 +19,11 @@ package com.seibel.lod.core.api; +import java.lang.ref.WeakReference; import java.time.Duration; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -35,6 +39,7 @@ import com.seibel.lod.core.render.GLProxy; import com.seibel.lod.core.render.LodRenderer; import com.seibel.lod.core.util.DetailDistanceUtil; import com.seibel.lod.core.util.SingletonHandler; +import com.seibel.lod.core.util.SpamReducedLogger; import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; @@ -52,7 +57,11 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper; * @version 12-8-2021 */ public class ClientApi -{ +{ + public static boolean prefLoggerEnabled = false; + public static List> spamReducedLoggers + = Collections.synchronizedList(new LinkedList>()); + public static final ClientApi INSTANCE = new ClientApi(); public static final Logger LOGGER = LogManager.getLogger(ModInfo.NAME); @@ -67,6 +76,8 @@ public class ClientApi public static final boolean ENABLE_LAG_SPIKE_LOGGING = false; public static final long LAG_SPIKE_THRESOLD_NS = TimeUnit.NANOSECONDS.convert(16, TimeUnit.MILLISECONDS); + public static final long SPAM_LOGGER_FLUSH_NS = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); + public static class LagSpikeCatcher { long timer = System.nanoTime(); @@ -94,6 +105,16 @@ public class ClientApi { } + + private void flushSpamLoggersState() { + synchronized(spamReducedLoggers) { + spamReducedLoggers.removeIf((logger) -> logger.get()==null); + spamReducedLoggers.forEach((logger) -> { + SpamReducedLogger l = logger.get(); + if (l!=null) l.reset(); + }); + } + } private final ConcurrentHashMap.KeySetView generating = ConcurrentHashMap.newKeySet(); public final ConcurrentHashMap.KeySetView toBeLoaded = ConcurrentHashMap.newKeySet(); @@ -106,6 +127,8 @@ public class ClientApi clientChunkLoad.end("clientChunkLoad"); } + private long lastFlush = 0; + public void renderLods(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks) { // comment out when creating a release @@ -116,6 +139,12 @@ public class ClientApi try { + if (System.nanoTime() - lastFlush >= SPAM_LOGGER_FLUSH_NS) { + lastFlush = System.nanoTime(); + flushSpamLoggersState(); + } + + // only run the first time setup once if (!firstTimeSetupComplete) firstFrameSetup(); @@ -134,6 +163,7 @@ public class ClientApi ApiShared.lodBuilder.defaultDimensionWidthInRegions); ApiShared.lodWorld.addLodDimension(lodDim); } + if (prefLoggerEnabled) lodDim.dumpRamUsage(); LagSpikeCatcher updateToBeLoadedChunk = new LagSpikeCatcher(); for (long pos : toBeLoaded) { @@ -267,9 +297,11 @@ public class ClientApi .setDrawLods(!CONFIG.client().advanced().debugging().getDrawLods()); MC.sendChatMessage("F6: Set rendering to " + CONFIG.client().advanced().debugging().getDrawLods()); } - - - + + if (glfwKey == GLFW.GLFW_KEY_P) { + prefLoggerEnabled = !prefLoggerEnabled; + MC.sendChatMessage("P: Debug Pref Logger is " + (prefLoggerEnabled ? "enabled" : "disabled")); + } } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java b/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java index 9f9fb0024..a64ec592e 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java @@ -122,4 +122,10 @@ public interface LevelContainer */ int getMaxNumberOfLods(); + /** + * This will return a ram usage estimation of this object + * @return long as byte + */ + long getRoughRamUsage(); + } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java index c9c70c5e4..e315e1025 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java @@ -26,8 +26,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import javax.crypto.spec.GCMParameterSpec; - import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.enums.config.DistanceGenerationMode; import com.seibel.lod.core.enums.config.DropoffQuality; @@ -44,6 +42,8 @@ import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.MovabeGridRingList; import com.seibel.lod.core.util.MovabeGridRingList.Pos; import com.seibel.lod.core.util.SingletonHandler; +import com.seibel.lod.core.util.SpamReducedLogger; +import com.seibel.lod.core.util.UnitBytes; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper; @@ -687,6 +687,44 @@ public class LodDimension generateIteratorList(); } + private final SpamReducedLogger ramLogger = new SpamReducedLogger(1); + public void dumpRamUsage() + { + if (!ramLogger.canMaybeLog()) return; + int regionCount = width*width; + ramLogger.info("Dumping Ram Usage for LodDim in {} with {} regions...", dimension.getDimensionName(), regionCount); + int nonNullRegionCount = 0; + int dirtiedRegionCount = 0; + long totalUsage = 0; + int[] detailCount = new int[LodUtil.DETAIL_OPTIONS]; + long[] detailUsage = new long[LodUtil.DETAIL_OPTIONS]; + for (LodRegion r : regions) { + if (r==null) continue; + nonNullRegionCount++; + if (r.needSaving) dirtiedRegionCount++; + LevelContainer[] container = r.debugGetDataContainers().clone(); + if (container == null || container.length != LodUtil.DETAIL_OPTIONS) { + ClientApi.LOGGER.warn("DumpRamUsage encountered an invalid region!"); + continue; + } + for (int i = 0; i < LodUtil.DETAIL_OPTIONS; i++) { + if (container[i] == null) continue; + detailCount[i]++; + long byteUsage = container[i].getRoughRamUsage(); + detailUsage[i] += byteUsage; + totalUsage += byteUsage; + } + } + ramLogger.info("================================================"); + ramLogger.info("Non Null Regions: [{}], Dirtied Regions: [{}], Bytes: [{}]", + nonNullRegionCount, dirtiedRegionCount, new UnitBytes(totalUsage)); + ramLogger.info("------------------------------------------------"); + for (int i = 0; i < LodUtil.DETAIL_OPTIONS; i++) { + ramLogger.info("DETAIL {}: Containers: [{}], Bytes: [{}]", i, detailCount[i], new UnitBytes(detailUsage[i])); + } + ramLogger.info("================================================"); + ramLogger.incLogTries(); + } @Override public String toString() diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java index 03fd8bd8a..c487c0f4e 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java @@ -29,6 +29,7 @@ import com.seibel.lod.core.util.DataPointUtil; import com.seibel.lod.core.util.DetailDistanceUtil; import com.seibel.lod.core.util.LevelPosUtil; import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.util.SpamReducedLogger; /** * This object holds all loaded LevelContainers acting as a quad tree for a @@ -610,6 +611,8 @@ public class LodRegion { return dataContainer[detailLevel].getVerticalSize(); } + public LevelContainer[] debugGetDataContainers() {return dataContainer;} + @Override public String toString() { return getLevel(LodUtil.REGION_DETAIL_LEVEL).toString(); diff --git a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java index b53a368f7..1dbd351bd 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java @@ -1269,6 +1269,12 @@ public class VerticalLevelContainer implements LevelContainer { return size * size * getVerticalSize(); } + + @Override + public long getRoughRamUsage() + { + return dataContainer.length * Long.BYTES; + } } diff --git a/src/main/java/com/seibel/lod/core/util/SpamReducedLogger.java b/src/main/java/com/seibel/lod/core/util/SpamReducedLogger.java new file mode 100644 index 000000000..2d187ede8 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/util/SpamReducedLogger.java @@ -0,0 +1,59 @@ +package com.seibel.lod.core.util; + +import java.lang.ref.WeakReference; +import java.util.concurrent.atomic.AtomicInteger; + +import com.seibel.lod.core.api.ClientApi; + +public class SpamReducedLogger { + private final int maxLogCount; + private final AtomicInteger logTries = new AtomicInteger(0); + private int sectionLogCount = -1; + public SpamReducedLogger(int maxLogPerSec) { + maxLogCount = maxLogPerSec; + ClientApi.spamReducedLoggers.add(new WeakReference(this)); + } + public void reset() {logTries.set(0);} + public boolean canMaybeLog() {return logTries.get() < maxLogCount;} + + public void info(String str, Object... param) { + if (sectionLogCount == -1) sectionLogCount = logTries.getAndIncrement(); + if (sectionLogCount >= maxLogCount) return; + ClientApi.LOGGER.info(str, param); + } + public void debug(String str, Object... param) { + if (sectionLogCount == -1) sectionLogCount = logTries.getAndIncrement(); + if (sectionLogCount >= maxLogCount) return; + ClientApi.LOGGER.debug(str, param); + } + public void warn(String str, Object... param) { + if (sectionLogCount == -1) sectionLogCount = logTries.getAndIncrement(); + if (sectionLogCount >= maxLogCount) return; + ClientApi.LOGGER.warn(str, param); + } + public void error(String str, Object... param) { + if (sectionLogCount == -1) sectionLogCount = logTries.getAndIncrement(); + if (sectionLogCount >= maxLogCount) return; + ClientApi.LOGGER.error(str, param); + } + public void incLogTries() { + sectionLogCount = -1; + } + + public void infoInc(String str, Object... param) { + if (logTries.getAndIncrement() >= maxLogCount) return; + ClientApi.LOGGER.info(str, param); + } + public void debugInc(String str, Object... param) { + if (logTries.getAndIncrement() >= maxLogCount) return; + ClientApi.LOGGER.debug(str, param); + } + public void warnInc(String str, Object... param) { + if (logTries.getAndIncrement() >= maxLogCount) return; + ClientApi.LOGGER.warn(str, param); + } + public void errorInc(String str, Object... param) { + if (logTries.getAndIncrement() >= maxLogCount) return; + ClientApi.LOGGER.error(str, param); + } +} \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/core/util/UnitBytes.java b/src/main/java/com/seibel/lod/core/util/UnitBytes.java new file mode 100644 index 000000000..6a8081e96 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/util/UnitBytes.java @@ -0,0 +1,44 @@ +package com.seibel.lod.core.util; + +public class UnitBytes +{ + public final long value; + public UnitBytes(long value) { + this.value = value; + } + public static long byteToGB(long v) { + return v/1073741824; + } + public static long byteToMB(long v) { + return v/1048576; + } + public static long byteToKB(long v) { + return v/1024; + } + public static long GBToByte(long v) { + return v*1073741824; + } + public static long MBToByte(long v) { + return v*1048576; + } + public static long KBToByte(long v) { + return v*1024; + } + + @Override + public String toString() { + long v = value; + StringBuilder str = new StringBuilder(); + long GB = byteToGB(v); + if (GB != 0) str.append(GB+ "GB "); + v -= GBToByte(GB); + long MB = byteToMB(v); + if (MB != 0) str.append(MB+ "MB "); + v -= MBToByte(MB); + long KB = byteToKB(v); + if (KB != 0) str.append(KB+ "KB "); + v -= KBToByte(KB); + str.append(v+"B"); + return str.toString(); + } +}