9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-19 15:09:18 +00:00

performance optimizations and add two experimental options for further optimizations

This commit is contained in:
Julian Krings
2025-08-24 22:33:35 +02:00
parent 558f6fa8dd
commit e48cbe1f69
9 changed files with 103 additions and 75 deletions

View File

@@ -242,6 +242,7 @@ public class IrisSettings {
public String defaultWorldType = "overworld"; public String defaultWorldType = "overworld";
public int maxBiomeChildDepth = 4; public int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true; public boolean preventLeafDecay = true;
public boolean useMulticore = false;
} }
@Data @Data
@@ -255,6 +256,7 @@ public class IrisSettings {
@Data @Data
public static class IrisSettingsEngineSVC { public static class IrisSettingsEngineSVC {
public boolean useVirtualThreads = true; public boolean useVirtualThreads = true;
public boolean forceMulticoreWrite = false;
public int priority = Thread.NORM_PRIORITY; public int priority = Thread.NORM_PRIORITY;
public int getPriority() { public int getPriority() {

View File

@@ -205,7 +205,7 @@ public class IrisEngineSVC implements IrisService {
try { try {
long unloadStart = System.currentTimeMillis(); long unloadStart = System.currentTimeMillis();
int count = engine.getMantle().unloadTectonicPlate(tectonicLimit()); int count = engine.getMantle().unloadTectonicPlate(IrisSettings.get().getPerformance().getEngineSVC().forceMulticoreWrite ? 0 : tectonicLimit());
if (count > 0) { if (count > 0) {
Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2)); Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2));
} }

View File

@@ -213,12 +213,16 @@ public interface EngineMantle extends IObjectPlacer {
for (int j = -radius; j <= radius; j++) { for (int j = -radius; j <= radius; j++) {
int xx = x + i; int xx = x + i;
int zz = z + j; int zz = z + j;
MantleChunk mc = getMantle().getChunk(xx, zz); MantleChunk mc = getMantle().getChunk(xx, zz).use();
burst.queue(() -> { burst.queue(() -> {
IrisContext.touch(getEngine().getContext()); try {
pair.getA().forEach(k -> generateMantleComponent(writer, xx, zz, k, mc, context)); IrisContext.touch(getEngine().getContext());
if (last) mc.flag(MantleFlag.PLANNED, true); pair.getA().forEach(k -> generateMantleComponent(writer, xx, zz, k, mc, context));
if (last) mc.flag(MantleFlag.PLANNED, true);
} finally {
mc.release();
}
}); });
} }
} }

View File

@@ -27,6 +27,7 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
@@ -53,10 +54,11 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
} }
@Override @Override
@ChunkCoordinates
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) { public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
Mantle mantle = getEngine().getMantle().getMantle(); Mantle mantle = getEngine().getMantle().getMantle();
MantleChunk mc = getEngine().getMantle().getMantle().getChunk(x, z).use(); MantleChunk mc = mantle.getChunk(x, z).use();
KMap<Long, KList<Integer>> positions = new KMap<>(); KMap<Long, KList<Integer>> positions = new KMap<>();
KMap<IrisPosition, MatterCavern> walls = new KMap<>(); KMap<IrisPosition, MatterCavern> walls = new KMap<>();
Consumer4<Integer, Integer, Integer, MatterCavern> iterator = (xx, yy, zz, c) -> { Consumer4<Integer, Integer, Integer, MatterCavern> iterator = (xx, yy, zz, c) -> {
@@ -81,19 +83,19 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
//todo: Fix chunk decoration not working on chunk's border //todo: Fix chunk decoration not working on chunk's border
if (rz < 15 && mantle.get(xx, yy, zz + 1, MatterCavern.class) == null) { if (rz < 15 && mc.get(xx, yy, zz + 1, MatterCavern.class) == null) {
walls.put(new IrisPosition(rx, yy, rz + 1), c); walls.put(new IrisPosition(rx, yy, rz + 1), c);
} }
if (rx < 15 && mantle.get(xx + 1, yy, zz, MatterCavern.class) == null) { if (rx < 15 && mc.get(xx + 1, yy, zz, MatterCavern.class) == null) {
walls.put(new IrisPosition(rx + 1, yy, rz), c); walls.put(new IrisPosition(rx + 1, yy, rz), c);
} }
if (rz > 0 && mantle.get(xx, yy, zz - 1, MatterCavern.class) == null) { if (rz > 0 && mc.get(xx, yy, zz - 1, MatterCavern.class) == null) {
walls.put(new IrisPosition(rx, yy, rz - 1), c); walls.put(new IrisPosition(rx, yy, rz - 1), c);
} }
if (rx > 0 && mantle.get(xx - 1, yy, zz, MatterCavern.class) == null) { if (rx > 0 && mc.get(xx - 1, yy, zz, MatterCavern.class) == null) {
walls.put(new IrisPosition(rx - 1, yy, rz), c); walls.put(new IrisPosition(rx - 1, yy, rz), c);
} }

View File

@@ -19,6 +19,7 @@
package com.volmit.iris.engine.platform; package com.volmit.iris.engine.platform;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.IrisWorlds;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
@@ -34,7 +35,6 @@ import com.volmit.iris.engine.object.StudioMode;
import com.volmit.iris.engine.platform.studio.StudioGenerator; import com.volmit.iris.engine.platform.studio.StudioGenerator;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.IrisBiomeStorage; import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
import com.volmit.iris.util.io.ReactiveFolder; import com.volmit.iris.util.io.ReactiveFolder;
@@ -46,8 +46,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Setter; import lombok.Setter;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -367,7 +365,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} else { } else {
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc); ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight()); BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
getEngine().generate(x << 4, z << 4, blocks, biomes, false); getEngine().generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore);
blocks.apply(); blocks.apply();
biomes.apply(); biomes.apply();
} }

View File

@@ -29,7 +29,7 @@ import lombok.Data;
@Data @Data
public class IrisContext { public class IrisContext {
private static final KMap<Thread, IrisContext> context = new KMap<>(); private static final KMap<Thread, IrisContext> context = new KMap<>();
private static ChronoLatch cl = new ChronoLatch(60000); private static final ChronoLatch cl = new ChronoLatch(60000);
private final Engine engine; private final Engine engine;
private ChunkContext chunkContext; private ChunkContext chunkContext;
@@ -53,9 +53,10 @@ public class IrisContext {
} }
public static void touch(IrisContext c) { public static void touch(IrisContext c) {
synchronized (context) { context.put(Thread.currentThread(), c);
context.put(Thread.currentThread(), c);
if (!cl.couldFlip()) return;
synchronized (cl) {
if (cl.flip()) { if (cl.flip()) {
dereference(); dereference();
} }
@@ -63,15 +64,13 @@ public class IrisContext {
} }
public static void dereference() { public static void dereference() {
synchronized (context) { for (Thread i : context.k()) {
for (Thread i : context.k()) { if (!i.isAlive() || context.get(i).engine.isClosed()) {
if (!i.isAlive() || context.get(i).engine.isClosed()) { if (context.get(i).engine.isClosed()) {
if (context.get(i).engine.isClosed()) { Iris.debug("Dereferenced Context<Engine> " + i.getName() + " " + i.threadId());
Iris.debug("Dereferenced Context<Engine> " + i.getName() + " " + i.getId());
}
context.remove(i);
} }
context.remove(i);
} }
} }
} }

View File

@@ -529,30 +529,31 @@ public class Mantle {
try { try {
if (!trim || !unload) { if (!trim || !unload) {
try { try {
return getSafe(x, z).get(); return getSafe(x, z);
} catch (InterruptedException e) { } catch (Throwable e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace(); e.printStackTrace();
} }
} else {
Long key = key(x, z);
TectonicPlate p = loadedRegions.get(key);
if (p != null && !p.isClosed()) {
use(key);
return p;
}
} }
Long key = key(x, z);
TectonicPlate p = loadedRegions.get(key);
if (p != null && !p.isClosed()) {
use(key);
return p;
}
try { try {
return getSafe(x, z).get(); return getSafe(x, z);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)"); Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)");
Iris.reportError(e); Iris.reportError(e);
} catch (ExecutionException e) { } catch (ExecutionException e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)"); Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
Iris.reportError(e); Iris.reportError(e);
} catch (Throwable e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a unknown exception");
Iris.reportError(e);
} }
} finally { } finally {
if (trim) ioTrim.release(); if (trim) ioTrim.release();
@@ -572,50 +573,52 @@ public class Mantle {
* @return the future of a tectonic plate. * @return the future of a tectonic plate.
*/ */
@RegionCoordinates @RegionCoordinates
private Future<TectonicPlate> getSafe(int x, int z) { private TectonicPlate getSafe(int x, int z) throws Throwable {
return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> { return hyperLock.withNastyResult(x, z, () -> {
Long k = key(x, z); Long k = key(x, z);
use(k); use(k);
TectonicPlate region = loadedRegions.get(k); TectonicPlate r = loadedRegions.get(k);
if (r != null && !r.isClosed()) {
if (region != null && !region.isClosed()) { return r;
return region;
} }
File file = fileForRegion(dataFolder, x, z); return ioBurst.completeValue(() -> {
if (file.exists()) { TectonicPlate region;
try { File file = fileForRegion(dataFolder, x, z);
Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath()); if (file.exists()) {
region = worker.read(file.getName()); try {
Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath());
region = worker.read(file.getName());
if (region.getX() != x || region.getZ() != z) { if (region.getX() != x || region.getZ() != z) {
Iris.warn("Loaded Tectonic Plate " + x + "," + z + " but read it as " + region.getX() + "," + region.getZ() + "... Assuming " + x + "," + z); Iris.warn("Loaded Tectonic Plate " + x + "," + z + " but read it as " + region.getX() + "," + region.getZ() + "... Assuming " + x + "," + z);
}
loadedRegions.put(k, region);
Iris.debug("Loaded Tectonic Plate " + C.DARK_GREEN + x + " " + z + C.DARK_AQUA + " " + file.getName());
} catch (Throwable e) {
Iris.error("Failed to read Tectonic Plate " + file.getAbsolutePath() + " creating a new chunk instead.");
Iris.reportError(e);
if (!(e instanceof EOFException)) {
e.printStackTrace();
}
Iris.panic();
region = new TectonicPlate(worldHeight, x, z);
loadedRegions.put(k, region);
Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z);
} }
loadedRegions.put(k, region); use(k);
Iris.debug("Loaded Tectonic Plate " + C.DARK_GREEN + x + " " + z + C.DARK_AQUA + " " + file.getName()); return region;
} catch (Throwable e) {
Iris.error("Failed to read Tectonic Plate " + file.getAbsolutePath() + " creating a new chunk instead.");
Iris.reportError(e);
if (!(e instanceof EOFException)) {
e.printStackTrace();
}
Iris.panic();
region = new TectonicPlate(worldHeight, x, z);
loadedRegions.put(k, region);
Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z);
} }
region = new TectonicPlate(worldHeight, x, z);
loadedRegions.put(k, region);
Iris.debug("Created new Tectonic Plate " + C.DARK_GREEN + x + " " + z);
use(k); use(k);
return region; return region;
} }).get();
});
region = new TectonicPlate(worldHeight, x, z);
loadedRegions.put(k, region);
Iris.debug("Created new Tectonic Plate " + C.DARK_GREEN + x + " " + z);
use(k);
return region;
}));
} }
private void use(Long key) { private void use(Long key) {

View File

@@ -21,6 +21,7 @@ package com.volmit.iris.util.mantle;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.data.Varint;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.ChunkRelativeBlockCoordinates;
import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.io.CountingDataInputStream; import com.volmit.iris.util.io.CountingDataInputStream;
import com.volmit.iris.util.matter.IrisMatter; import com.volmit.iris.util.matter.IrisMatter;
@@ -28,6 +29,7 @@ import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.MatterSlice; import com.volmit.iris.util.matter.MatterSlice;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
@@ -146,11 +148,10 @@ public class MantleChunk {
} }
public void raiseFlag(MantleFlag flag, Runnable r) { public void raiseFlag(MantleFlag flag, Runnable r) {
synchronized (this) { if (closed.get()) throw new IllegalStateException("Chunk is closed!");
if (!isFlagged(flag)) flag(flag, true); if (flags.getAndSet(flag.ordinal(), 1) == 0) {
else return; r.run();
} }
r.run();
} }
public boolean isFlagged(MantleFlag flag) { public boolean isFlagged(MantleFlag flag) {
@@ -179,6 +180,15 @@ public class MantleChunk {
return sections.get(section); return sections.get(section);
} }
@Nullable
@ChunkRelativeBlockCoordinates
@SuppressWarnings("unchecked")
public <T> T get(int x, int y, int z, Class<T> type) {
return (T) getOrCreate(y >> 4)
.slice(type)
.get(x & 15, y & 15, z & 15);
}
/** /**
* Clear all matter from this chunk * Clear all matter from this chunk
*/ */

View File

@@ -22,6 +22,7 @@ import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.util.function.NastyRunnable; import com.volmit.iris.util.function.NastyRunnable;
import com.volmit.iris.util.function.NastySupplier;
import com.volmit.iris.util.io.IORunnable; import com.volmit.iris.util.io.IORunnable;
import java.io.IOException; import java.io.IOException;
@@ -107,6 +108,15 @@ public class HyperLock {
return t; return t;
} }
public <T> T withNastyResult(int x, int z, NastySupplier<T> r) throws Throwable {
lock(x, z);
try {
return r.get();
} finally {
unlock(x, z);
}
}
public boolean tryLock(int x, int z) { public boolean tryLock(int x, int z) {
return getLock(x, z).tryLock(); return getLock(x, z).tryLock();
} }