diff --git a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java index 07d1b2983..52eed894c 100644 --- a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java +++ b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java @@ -585,6 +585,8 @@ public class LodBufferBuilderFactory long bufferCount = 0; long fullBufferCount = 0; long totalUsage = 0; + long builderCount = 0; + long totalBuilderUsage = 0; int maxLength = MAX_TRIANGLES_PER_BUFFER*(LodUtil.LOD_VERTEX_FORMAT.getByteSize()*3); for (LodVertexBuffer[] buffers : buildableVbos) { if (buffers == null) continue; @@ -600,6 +602,11 @@ public class LodBufferBuilderFactory totalUsage += b.size; } } + for (LodBufferBuilder builder : buildableBuffers) { + if (builder == null) continue; + builderCount++; + totalBuilderUsage += builder.getMemUsage(); + } for (LodVertexBuffer[] buffers : drawableVbos) { if (buffers == null) continue; LodVertexBuffer[] bs = buffers.clone(); @@ -617,6 +624,8 @@ public class LodBufferBuilderFactory ramLogger.info("================================================"); ramLogger.info("Buffers: [{}], Full-sized Buffers: [{}], Total: [{}]", bufferCount, fullBufferCount, new UnitBytes(totalUsage)); + ramLogger.info("Builders: [{}], Total: [{}]", + builderCount, new UnitBytes(totalBuilderUsage)); ramLogger.info("================================================"); ramLogger.incLogTries(); } diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java index 8b660ea56..988120676 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java @@ -205,7 +205,7 @@ public class LodBuilder private boolean writeAllLodNodeData(LodDimension lodDim, LodRegion region, int chunkX, int chunkZ, long[] data, LodBuilderConfig config, boolean override) { - region.isWriting++; + region.isWriting.incrementAndGet(); try { if (region.getMinDetailLevel()!= 0) { if (!LodUtil.checkRamUsage(0.05, 16)) { @@ -230,7 +230,7 @@ public class LodBuilder } catch (Exception e) { e.printStackTrace(); } finally { - region.isWriting--; + region.isWriting.decrementAndGet(); } return true; } @@ -238,7 +238,7 @@ public class LodBuilder private boolean writePartialLodNodeData(LodDimension lodDim, LodRegion region, int chunkX, int chunkZ, long[] data, LodBuilderConfig config, boolean override) { - region.isWriting++; + region.isWriting.incrementAndGet(); try { byte targetLevel = region.getMinDetailLevel(); int vertQual = DetailDistanceUtil.getMaxVerticalData(targetLevel); @@ -295,7 +295,7 @@ public class LodBuilder } catch (Exception e) { e.printStackTrace(); } finally { - region.isWriting--; + region.isWriting.decrementAndGet(); } return true; } diff --git a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java index f4d091514..1bc02e749 100644 --- a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java @@ -24,6 +24,7 @@ import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.time.Duration; import java.time.Instant; +import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; @@ -37,12 +38,15 @@ import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream; import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.enums.config.VerticalQuality; +import com.seibel.lod.core.objects.lod.LevelContainer; import com.seibel.lod.core.objects.lod.LodDimension; import com.seibel.lod.core.objects.lod.LodRegion; import com.seibel.lod.core.objects.lod.RegionPos; import com.seibel.lod.core.objects.lod.VerticalLevelContainer; import com.seibel.lod.core.util.LodThreadFactory; import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.util.SpamReducedLogger; +import com.seibel.lod.core.util.UnitBytes; /** @@ -316,6 +320,47 @@ public class LodDimensionFileHandler public void addRegionsToSave(LodRegion r) { regionToSave.put(r.getRegionPos(), r); } + + private final SpamReducedLogger ramLogger = new SpamReducedLogger(1); + public void dumpBufferMemoryUsage() { + if (!ramLogger.canMaybeLog()) return; + ArrayList regions = new ArrayList(regionToSave.values()); + ramLogger.info("Dumping Ram Usage for file writer for {} with {} regions...", + lodDimension.dimension.getDimensionName(), regions.size()); + int nonNullRegionCount = 0; + int nonDirtiedRegionCount = 0; + int writingRegionCount = 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) nonDirtiedRegionCount++; + if (r.isWriting.get() != 0) writingRegionCount++; + 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: [{}], Non-Dirtied Regions: [{}], Writing Regions: [{}], Bytes: [{}]", + nonNullRegionCount, nonDirtiedRegionCount, writingRegionCount, 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(); + } /** Save all dirty regions in this LodDimension to file */ public void saveDirtyRegionsToFile(boolean blockUntilFinished) @@ -380,9 +425,9 @@ public class LodDimensionFileHandler // this for loop should be safe and loop until all values are gone. while (!regionToSave.isEmpty()) { for (LodRegion r : regionToSave.values()) { - r.isWriting++; + try { - if (r.isWriting>1) continue; + if (r.isWriting.getAndIncrement()>0) continue; //Check if the data has been swapped out right under me. Otherwise remove it from the entry if (!regionToSave.remove(r.getRegionPos(), r)) continue; r.needSaving = false; @@ -399,7 +444,7 @@ public class LodDimensionFileHandler { e.printStackTrace(); } finally { - r.isWriting--; + r.isWriting.decrementAndGet(); } } } 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 662c2bdcf..963c7b416 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 @@ -295,7 +295,7 @@ public class LodDimension LodRegion region = regions.get(x+minPos.x, z+minPos.y); if (region != null && region.needSaving) totalDirtiedRegions++; - if (region != null && !region.needSaving && region.isWriting==0) { + if (region != null && !region.needSaving && region.isWriting.get()==0) { // check what detail level this region should be // and cut it if it is higher then that minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, x+minPos.x, z+minPos.y, @@ -366,7 +366,7 @@ public class LodDimension regionZ = z + minPos.y; final RegionPos regionPos = new RegionPos(regionX, regionZ); region = regions.get(regionX, regionZ); - if (region != null && region.isWriting!=0) return; // FIXME: A crude attempt at lowering chance of race condition! + if (region != null && region.isWriting.get()!=0) return; // FIXME: A crude attempt at lowering chance of race condition! minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX, playerPosZ); @@ -716,15 +716,12 @@ public class LodDimension if (r==null) continue; nonNullRegionCount++; if (r.needSaving) dirtiedRegionCount++; - if (r.isWriting != 0) writingRegionCount++; + if (r.isWriting.get() != 0) writingRegionCount++; 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]++; @@ -742,6 +739,7 @@ public class LodDimension } ramLogger.info("================================================"); ramLogger.incLogTries(); + fileHandler.dumpBufferMemoryUsage(); } @Override 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 f79cd15bb..7b034e17c 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 @@ -19,6 +19,9 @@ package com.seibel.lod.core.objects.lod; +import java.util.ConcurrentModificationException; +import java.util.concurrent.atomic.AtomicInteger; + import com.seibel.lod.core.enums.config.DistanceGenerationMode; import com.seibel.lod.core.enums.config.DropoffQuality; import com.seibel.lod.core.enums.config.GenerationPriority; @@ -69,7 +72,7 @@ public class LodRegion { public volatile boolean needRecheckGenPoint = true; public volatile int needRegenBuffer = 2; public volatile boolean needSaving = false; - public volatile int isWriting = 0; + public final AtomicInteger isWriting = new AtomicInteger(0); public static byte calculateFarModeSwitch(byte targetLevel) { if (targetLevel==0) return 0; // Always use detail 0 if it's way too close @@ -100,7 +103,7 @@ public class LodRegion { * @return true if the data was added successfully */ public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data) { - assert(isWriting!=0); + if(isWriting.get()<=0) throw new ConcurrentModificationException("isWriting counter lock should have been aquired!"); posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); @@ -121,7 +124,7 @@ public class LodRegion { * @return true if the data was added successfully */ public boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data, boolean override) { - assert(isWriting!=0); + if(isWriting.get()<=0) throw new ConcurrentModificationException("isWriting counter lock should have been aquired!"); posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); @@ -145,7 +148,7 @@ public class LodRegion { * @return true if the data was added successfully */ public boolean addChunkOfData(byte detailLevel, int posX, int posZ, int widthX, int widthZ, long[] data, int verticalSize, boolean override) { - assert(isWriting!=0); + if(isWriting.get()<=0) throw new ConcurrentModificationException("isWriting counter lock should have been aquired!"); posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); diff --git a/src/main/java/com/seibel/lod/core/objects/opengl/LodBufferBuilder.java b/src/main/java/com/seibel/lod/core/objects/opengl/LodBufferBuilder.java index db77fd4f3..a298e73c1 100644 --- a/src/main/java/com/seibel/lod/core/objects/opengl/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/core/objects/opengl/LodBufferBuilder.java @@ -64,6 +64,8 @@ public class LodBufferBuilder this.buffer = allocateByteBuffer(bufferSizeInBytes * 4); } + public int getMemUsage() {return buffer.capacity();} + /** originally from MC's GLAllocation class */ diff --git a/src/main/java/com/seibel/lod/core/util/DataPointUtil.java b/src/main/java/com/seibel/lod/core/util/DataPointUtil.java index e73c5532a..b1a23fdc6 100644 --- a/src/main/java/com/seibel/lod/core/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/core/util/DataPointUtil.java @@ -261,10 +261,9 @@ public class DataPointUtil /** Return (>0) if dataA should replace dataB, (0) if equal, (<0) if dataB should replace dataA */ public static int compareDatapointPriority(long dataA, long dataB) { - if (dataA==0 || dataB==0) { - if (dataA!=0) dataA = Integer.MAX_VALUE; - if (dataB!=0) dataB = Integer.MAX_VALUE; - return (int)(dataA-dataB); + if (!doesItExist(dataA) || !doesItExist(dataB)) { + if (doesItExist(dataA)) return Integer.MAX_VALUE; + if (doesItExist(dataB)) return Integer.MIN_VALUE; } int genA = (int)getGenerationMode(dataA); int genB = (int)getGenerationMode(dataB);