From 11cab800e382f6e422a033322fc95fcabf8ab242 Mon Sep 17 00:00:00 2001 From: Daniel Mills Date: Sat, 12 Sep 2020 01:44:54 -0400 Subject: [PATCH] Faster caching --- pom.xml | 5 + .../java/com/volmit/iris/IrisSettings.java | 8 + .../com/volmit/iris/command/CommandIris.java | 2 +- .../iris/gen/ContextualTerrainProvider.java | 2 +- .../volmit/iris/gen/IrisTerrainProvider.java | 4 +- .../iris/gen/ParallelTerrainProvider.java | 1 - .../iris/gen/TopographicTerrainProvider.java | 119 ++++---- .../iris/gen/atomics/AtomicMulticache.java | 266 ++++-------------- .../java/com/volmit/iris/gui/IrisVision.java | 1 - .../java/com/volmit/iris/gui/PregenGui.java | 2 +- .../java/com/volmit/iris/util/PregenJob.java | 3 +- 11 files changed, 121 insertions(+), 292 deletions(-) diff --git a/pom.xml b/pom.xml index 2c40092d6..9a1ca2994 100644 --- a/pom.xml +++ b/pom.xml @@ -198,6 +198,11 @@ provided + + com.github.ben-manes.caffeine + caffeine + 2.8.5 + org.bstats bstats-bukkit diff --git a/src/main/java/com/volmit/iris/IrisSettings.java b/src/main/java/com/volmit/iris/IrisSettings.java index 61837f392..67d410504 100644 --- a/src/main/java/com/volmit/iris/IrisSettings.java +++ b/src/main/java/com/volmit/iris/IrisSettings.java @@ -21,6 +21,10 @@ public class IrisSettings @Desc("Iris generator threads (must be 2 or higher). Threads in iris are not a perfect scale for performance as a lot of data has to be shared. 16 Threads is a good rule of thumb. Use 8 threads on a quad core processor.") public int threads = 16; + @DontObfuscate + @Desc("Iris uses a lot of caching to speed up chunk generation. Setting this higher uses more memory, but may improve performance. Anything past 15,000 should be avoided because there is little benefit past this value.") + public int atomicCacheSize = 10000; + @DontObfuscate @Desc("Compress parallax data in memory to reduce memory usage in exchange for more cpu usage.") public boolean parallaxCompression = true; @@ -37,6 +41,10 @@ public class IrisSettings @Desc("If A is a child of B, and B is a child of A, how deep should iris follow the children in biomes. Lower is faster gen.") public int maxBiomeChildDepth = 5; + @DontObfuscate + @Desc("The size of each tile pregen will generate (in chunks)") + public int pregenTileSize = 32; + @DontObfuscate @Desc("When enabled, The cache is shared for all chunks and cleared periodically instead of per chunk. This uses more memory but provides a ~15% speedup.") public boolean sharedCaching = true; diff --git a/src/main/java/com/volmit/iris/command/CommandIris.java b/src/main/java/com/volmit/iris/command/CommandIris.java index d3290e55b..1d1f9e091 100644 --- a/src/main/java/com/volmit/iris/command/CommandIris.java +++ b/src/main/java/com/volmit/iris/command/CommandIris.java @@ -21,7 +21,7 @@ public class CommandIris extends MortarCommand @Command private CommandIrisDownload download; - + @Command private CommandIrisWhat what; diff --git a/src/main/java/com/volmit/iris/gen/ContextualTerrainProvider.java b/src/main/java/com/volmit/iris/gen/ContextualTerrainProvider.java index cc16e36a2..58b4c506a 100644 --- a/src/main/java/com/volmit/iris/gen/ContextualTerrainProvider.java +++ b/src/main/java/com/volmit/iris/gen/ContextualTerrainProvider.java @@ -85,7 +85,7 @@ public abstract class ContextualTerrainProvider implements TerrainProvider, List tickLatch = new ChronoLatch(650); perSecond = new ChronoLatch(1000); hlast = M.ms(); - cache = new AtomicMulticache(); + cache = new AtomicMulticache((IrisTerrainProvider) this); CNG.creates = 0; generated = 0; ticks = 0; diff --git a/src/main/java/com/volmit/iris/gen/IrisTerrainProvider.java b/src/main/java/com/volmit/iris/gen/IrisTerrainProvider.java index 170d452fa..f4d048f4c 100644 --- a/src/main/java/com/volmit/iris/gen/IrisTerrainProvider.java +++ b/src/main/java/com/volmit/iris/gen/IrisTerrainProvider.java @@ -249,7 +249,7 @@ public class IrisTerrainProvider extends SkyTerrainProvider implements IrisConte int iz = (int) z; double height = getTerrainHeight(ix, iz); IrisRegion region = sampleRegion(ix, iz); - IrisBiome biome = sampleTrueBiome(ix, iz, height); + IrisBiome biome = sampleTrueBiome(ix, iz); if(biome.getCachedColor() != null) { @@ -276,7 +276,7 @@ public class IrisTerrainProvider extends SkyTerrainProvider implements IrisConte int iz = (int) z; double height = getTerrainHeight(ix, iz); IrisRegion region = sampleRegion(ix, iz); - IrisBiome biome = sampleTrueBiome(ix, iz, height); + IrisBiome biome = sampleTrueBiome(ix, iz); hb = biome; hr = region; return biome.getName() + " (" + Form.capitalizeWords(biome.getInferredType().name().toLowerCase().replaceAll("\\Q_\\E", " ") + ") in " + region.getName() + "\nY: " + (int) height); diff --git a/src/main/java/com/volmit/iris/gen/ParallelTerrainProvider.java b/src/main/java/com/volmit/iris/gen/ParallelTerrainProvider.java index 6d47b120f..1997ebe92 100644 --- a/src/main/java/com/volmit/iris/gen/ParallelTerrainProvider.java +++ b/src/main/java/com/volmit/iris/gen/ParallelTerrainProvider.java @@ -65,7 +65,6 @@ public abstract class ParallelTerrainProvider extends DimensionalTerrainProvider protected void onGenerate(RNG random, int x, int z, TerrainChunk terrain) { - getCache().targetChunk(x, z); PrecisionStopwatch p = PrecisionStopwatch.start(); AtomicSliverMap map = new AtomicSliverMap(); HeightMap height = new HeightMap(); diff --git a/src/main/java/com/volmit/iris/gen/TopographicTerrainProvider.java b/src/main/java/com/volmit/iris/gen/TopographicTerrainProvider.java index 369d0c8ef..c095eb52b 100644 --- a/src/main/java/com/volmit/iris/gen/TopographicTerrainProvider.java +++ b/src/main/java/com/volmit/iris/gen/TopographicTerrainProvider.java @@ -84,20 +84,10 @@ public abstract class TopographicTerrainProvider extends ParallelTerrainProvider { if(ignoreFluid) { - return getCache().getCarvedHeightIgnoreWater(x, z, () -> - { - int h = (int) Math.round(getTerrainHeight(x, z)); - h = getGlCarve().getSurfaceCarve(x, h, z); - return h; - }); + return getCache().getCarvedHeightIgnoreWater(x, z); } - return getCache().getCarvedHeightIgnoreWater(x, z, () -> - { - int h = (int) Math.round(getTerrainWaterHeight(x, z)); - h = getGlCarve().getSurfaceCarve(x, h, z); - return h; - }); + return getCache().getCarvedHeight(x, z); } public int getCarvedHeight(int x, int z) @@ -140,7 +130,7 @@ public abstract class TopographicTerrainProvider extends ParallelTerrainProvider int height = (int) Math.round(noise); boolean carvable = getGlCarve().couldCarveBelow(rx, height, rz); IrisRegion region = sampleRegion(rx, rz); - IrisBiome biome = sampleTrueBiome(rx, rz, noise); + IrisBiome biome = sampleTrueBiome(rx, rz); IrisBiome carveBiome = null; Biome onlyBiome = Iris.biome3d ? null : biome.getGroundBiome(getMasterRandom(), rz, getDimension().getFluidHeight(), rx); @@ -582,20 +572,21 @@ public abstract class TopographicTerrainProvider extends ParallelTerrainProvider } - private double getNoiseHeight(int rx, int rz) + public double getNoiseHeight(int rx, int rz) { double h = getBiomeHeight(rx, rz); return h; } - public IrisBiome sampleTrueBiomeBase(int x, int z, int height) + public IrisBiome sampleTrueBiomeBase(int x, int z) { if(!getDimension().getFocus().equals("")) { return focus(); } + int height = (int) Math.round(getTerrainHeight(x, z)); double wx = getModifiedX(x, z); double wz = getModifiedZ(x, z); IrisRegion region = sampleRegion(x, z); @@ -671,29 +662,19 @@ public abstract class TopographicTerrainProvider extends ParallelTerrainProvider return sampleTrueBiome(x, z); } - public IrisBiome sampleTrueBiome(int x, int z) - { - return sampleTrueBiome(x, z, getTerrainHeight(x, z)); - } - public IrisRegion sampleRegion(int x, int z) { - return getCache().getRegion(x, z, () -> - { - double wx = getModifiedX(x, z); - double wz = getModifiedZ(x, z); - return glBiome.getRegion(wx, wz); - }); + return getCache().getRegion(x, z); } - public IrisBiome sampleTrueBiome(int x, int z, double noise) + public IrisBiome sampleTrueBiome(int x, int z) { if(!getDimension().getFocus().equals("")) { return focus(); } - return getCache().getBiome(x, z, () -> sampleTrueBiomeBase(x, z, (int) Math.round(noise))); + return getCache().getBiome(x, z); } @Override @@ -724,7 +705,7 @@ public abstract class TopographicTerrainProvider extends ParallelTerrainProvider public double getTerrainHeight(int x, int z) { - return getCache().getHeight(x, z, () -> getNoiseHeight(x, z) + getFluidHeight()); + return getCache().getHeight(x, z); } public double getTerrainWaterHeight(int x, int z) @@ -885,47 +866,49 @@ public abstract class TopographicTerrainProvider extends ParallelTerrainProvider Iris.info("Loaded " + generators.size() + " Generators"); } + + public IrisBiome computeRawBiome(int x, int z) + { + if(!getDimension().getFocus().equals("")) + { + IrisBiome biome = loadBiome(getDimension().getFocus()); + + for(String i : getDimension().getRegions()) + { + IrisRegion reg = loadRegion(i); + + if(reg.getLandBiomes().contains(biome.getLoadKey())) + { + biome.setInferredType(InferredType.LAND); + break; + } + + if(reg.getSeaBiomes().contains(biome.getLoadKey())) + { + biome.setInferredType(InferredType.SEA); + break; + } + + if(reg.getShoreBiomes().contains(biome.getLoadKey())) + { + biome.setInferredType(InferredType.SHORE); + break; + } + } + + return biome; + } + + double wx = getModifiedX(x, z); + double wz = getModifiedZ(x, z); + IrisRegion region = glBiome.getRegion(wx, wz); + IrisBiome res = glBiome.generateRegionData(wx, wz, x, z, region); + + return res; + } public IrisBiome sampleBiome(int x, int z) { - return getCache().getRawBiome(x, z, () -> - { - if(!getDimension().getFocus().equals("")) - { - IrisBiome biome = loadBiome(getDimension().getFocus()); - - for(String i : getDimension().getRegions()) - { - IrisRegion reg = loadRegion(i); - - if(reg.getLandBiomes().contains(biome.getLoadKey())) - { - biome.setInferredType(InferredType.LAND); - break; - } - - if(reg.getSeaBiomes().contains(biome.getLoadKey())) - { - biome.setInferredType(InferredType.SEA); - break; - } - - if(reg.getShoreBiomes().contains(biome.getLoadKey())) - { - biome.setInferredType(InferredType.SHORE); - break; - } - } - - return biome; - } - - double wx = getModifiedX(x, z); - double wz = getModifiedZ(x, z); - IrisRegion region = glBiome.getRegion(wx, wz); - IrisBiome res = glBiome.generateRegionData(wx, wz, x, z, region); - - return res; - }); + return getCache().getRawBiome(x, z); } } diff --git a/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java b/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java index f83b31170..90bf27ffe 100644 --- a/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java +++ b/src/main/java/com/volmit/iris/gen/atomics/AtomicMulticache.java @@ -1,245 +1,81 @@ package com.volmit.iris.gen.atomics; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; - -import com.volmit.iris.Iris; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.volmit.iris.IrisSettings; +import com.volmit.iris.gen.IrisTerrainProvider; import com.volmit.iris.object.IrisBiome; import com.volmit.iris.object.IrisRegion; -import com.volmit.iris.util.KMap; +import com.volmit.iris.util.ChunkPosition; public class AtomicMulticache { public static boolean broken = false; - private final AtomicInteger x; - private final AtomicInteger z; - private int hit = 0; - private int miss = 0; - private final KMap height; - private final KMap carvedHeight; - private final KMap carvedHeightIgnoreWater; - private final KMap biome; - private final KMap rawBiome; - private final KMap region; + private final LoadingCache height; + private final LoadingCache carvedHeight; + private final LoadingCache carvedHeightIgnoreWater; + private final LoadingCache biome; + private final LoadingCache rawBiome; + private final LoadingCache region; - public AtomicMulticache() + public AtomicMulticache(IrisTerrainProvider gen) { - x = new AtomicInteger(0); - z = new AtomicInteger(0); - height = new KMap(); - carvedHeight = new KMap(); - carvedHeightIgnoreWater = new KMap(); - biome = new KMap(); - rawBiome = new KMap(); - region = new KMap(); - } - - public void targetChunk(int x, int z) - { - if(broken) + height = Caffeine.newBuilder().maximumSize(getLimit()).build((c) -> gen.getNoiseHeight(c.getX(), c.getZ()) + gen.getFluidHeight()); + carvedHeight = Caffeine.newBuilder().maximumSize(getLimit()).build((c) -> { - return; - } - - this.x.set(x); - this.z.set(z); - - if(!IrisSettings.get().sharedCaching || Iris.lowMemoryMode) + int h = (int) Math.round(gen.getTerrainWaterHeight(c.getX(), c.getZ())); + h = gen.getGlCarve().getSurfaceCarve(c.getX(), h, c.getZ()); + return h; + }); + carvedHeightIgnoreWater = Caffeine.newBuilder().maximumSize(getLimit()).build((c) -> { - drop(); - } - - else + int h = (int) Math.round(gen.getTerrainHeight(c.getX(), c.getZ())); + h = gen.getGlCarve().getSurfaceCarve(c.getX(), h, c.getZ()); + return h; + }); + biome = Caffeine.newBuilder().maximumSize(getLimit()).build((c) -> gen.sampleTrueBiomeBase(c.getX(), c.getZ())); + rawBiome = Caffeine.newBuilder().maximumSize(getLimit()).build((c) -> gen.computeRawBiome(c.getX(), c.getZ())); + region = Caffeine.newBuilder().maximumSize(getLimit()).build((c) -> { - if(height.size() > getLimit()) - { - height.clear(); - } - - if(carvedHeight.size() > getLimit()) - { - carvedHeight.clear(); - } - - if(carvedHeightIgnoreWater.size() > getLimit()) - { - carvedHeightIgnoreWater.clear(); - } - - if(biome.size() > getLimit()) - { - biome.clear(); - } - - if(rawBiome.size() > getLimit()) - { - rawBiome.clear(); - } - - if(region.size() > getLimit()) - { - region.clear(); - } - } + double wx = gen.getModifiedX(c.getX(), c.getZ()); + double wz = gen.getModifiedZ(c.getX(), c.getZ()); + return gen.getGlBiome().getRegion(wx, wz); + }); } private int getLimit() { - return 1024; + return IrisSettings.get().getAtomicCacheSize(); } - public double getHeight(int x, int z, Supplier g) + public double getHeight(int x, int z) { - if(broken) - { - return -5784; - } - - long pos = pos(x, z); - Double r = height.get(pos); - - if(r == null) - { - miss++; - r = g.get(); - height.put(pos, r); - } - - else - { - hit++; - } - - return r; + return height.get(new ChunkPosition(x, z)); } - public int getCarvedHeight(int x, int z, Supplier g) + public int getCarvedHeight(int x, int z) { - if(broken) - { - return -57841; - } - - long pos = pos(x, z); - Integer r = carvedHeight.get(pos); - - if(r == null) - { - miss++; - r = g.get(); - carvedHeight.put(pos, r); - } - - else - { - hit++; - } - - return r; + return carvedHeight.get(new ChunkPosition(x, z)); } - public int getCarvedHeightIgnoreWater(int x, int z, Supplier g) + public int getCarvedHeightIgnoreWater(int x, int z) { - if(broken) - { - return -57841; - } - - long pos = pos(x, z); - Integer r = carvedHeightIgnoreWater.get(pos); - - if(r == null) - { - miss++; - r = g.get(); - carvedHeightIgnoreWater.put(pos, r); - } - - else - { - hit++; - } - - return r; + return carvedHeightIgnoreWater.get(new ChunkPosition(x, z)); } - public IrisRegion getRegion(int x, int z, Supplier g) + public IrisRegion getRegion(int x, int z) { - long pos = pos(x, z); - IrisRegion r = region.get(pos); - - if(r == null) - { - miss++; - r = g.get(); - region.put(pos, r); - } - - else - { - hit++; - } - - return r; + return region.get(new ChunkPosition(x, z)); } - public IrisBiome getBiome(int x, int z, Supplier g) + public IrisBiome getBiome(int x, int z) { - long pos = pos(x, z); - IrisBiome r = biome.get(pos); - - if(r == null) - { - miss++; - r = g.get(); - biome.put(pos, r); - } - - else - { - hit++; - } - - return r; + return biome.get(new ChunkPosition(x, z)); } - public IrisBiome getRawBiome(int x, int z, Supplier g) + public IrisBiome getRawBiome(int x, int z) { - if(broken) - { - return null; - } - long pos = pos(x, z); - IrisBiome r = rawBiome.get(pos); - - if(r == null) - { - miss++; - r = g.get(); - rawBiome.put(pos, r); - } - - else - { - hit++; - } - - return r; - } - - public double getCacheHitRate() - { - return (double) hit / (double) (hit + miss); - } - - private long pos(int x, int z) - { - if(broken) - { - return 1; - } - return (((long) x) << 32) | (z & 0xffffffffL); + return rawBiome.get(new ChunkPosition(x, z)); } public void updateHeight(int x, int z, int h) @@ -248,12 +84,12 @@ public class AtomicMulticache { return; } - height.put(pos(x, z), (double) h); + height.put(new ChunkPosition(x, z), (double) h); } public double getSize() { - return height.size() + region.size() + biome.size() + rawBiome.size(); + return height.estimatedSize() + region.estimatedSize() + biome.estimatedSize() + rawBiome.estimatedSize() + carvedHeight.estimatedSize() + carvedHeightIgnoreWater.estimatedSize(); } public void drop() @@ -263,13 +99,11 @@ public class AtomicMulticache return; } - hit = 0; - miss = 0; - height.clear(); - region.clear(); - biome.clear(); - rawBiome.clear(); - carvedHeight.clear(); - carvedHeightIgnoreWater.clear(); + height.invalidateAll(); + region.invalidateAll(); + biome.invalidateAll(); + rawBiome.invalidateAll(); + carvedHeight.invalidateAll(); + carvedHeightIgnoreWater.invalidateAll(); } } diff --git a/src/main/java/com/volmit/iris/gui/IrisVision.java b/src/main/java/com/volmit/iris/gui/IrisVision.java index 4152a17de..9b1fa8429 100644 --- a/src/main/java/com/volmit/iris/gui/IrisVision.java +++ b/src/main/java/com/volmit/iris/gui/IrisVision.java @@ -124,7 +124,6 @@ public class IrisVision extends JPanel implements MouseWheelListener public BufferedImage getTile(KSet fg, int div, int x, int z, O m) { - Iris.proj.getCurrentProject().getCache().targetChunk(x, z); BlockPosition key = new BlockPosition((int) mscale, Math.floorDiv(x, div), Math.floorDiv(z, div)); fg.add(key); diff --git a/src/main/java/com/volmit/iris/gui/PregenGui.java b/src/main/java/com/volmit/iris/gui/PregenGui.java index 49f3669d0..d8a3b01b8 100644 --- a/src/main/java/com/volmit/iris/gui/PregenGui.java +++ b/src/main/java/com/volmit/iris/gui/PregenGui.java @@ -81,7 +81,7 @@ public class PregenGui extends JPanel g.drawString(i, 20, hh += h); } - J.sleep((long) 1); + J.sleep((long) 1000); repaint(); } diff --git a/src/main/java/com/volmit/iris/util/PregenJob.java b/src/main/java/com/volmit/iris/util/PregenJob.java index eacfc756a..68c2ad873 100644 --- a/src/main/java/com/volmit/iris/util/PregenJob.java +++ b/src/main/java/com/volmit/iris/util/PregenJob.java @@ -11,6 +11,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkUnloadEvent; import com.volmit.iris.Iris; +import com.volmit.iris.IrisSettings; import com.volmit.iris.gui.PregenGui; public class PregenJob implements Listener @@ -37,7 +38,7 @@ public class PregenJob implements Listener private Spiraler chunkSpiraler; private boolean first; private Consumer2 consumer; - private int cubeSize = 7; + private int cubeSize = IrisSettings.get().getPregenTileSize(); int xc = 0; public PregenJob(World world, int size, MortarSender sender, Runnable onDone)