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 int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true;
public boolean useMulticore = false;
}
@Data
@@ -255,6 +256,7 @@ public class IrisSettings {
@Data
public static class IrisSettingsEngineSVC {
public boolean useVirtualThreads = true;
public boolean forceMulticoreWrite = false;
public int priority = Thread.NORM_PRIORITY;
public int getPriority() {

View File

@@ -205,7 +205,7 @@ public class IrisEngineSVC implements IrisService {
try {
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) {
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++) {
int xx = x + i;
int zz = z + j;
MantleChunk mc = getMantle().getChunk(xx, zz);
MantleChunk mc = getMantle().getChunk(xx, zz).use();
burst.queue(() -> {
IrisContext.touch(getEngine().getContext());
pair.getA().forEach(k -> generateMantleComponent(writer, xx, zz, k, mc, context));
if (last) mc.flag(MantleFlag.PLANNED, true);
try {
IrisContext.touch(getEngine().getContext());
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.context.ChunkContext;
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.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle;
@@ -53,10 +54,11 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
}
@Override
@ChunkCoordinates
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
PrecisionStopwatch p = PrecisionStopwatch.start();
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<IrisPosition, MatterCavern> walls = new KMap<>();
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
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);
}
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);
}
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);
}
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);
}

View File

@@ -19,6 +19,7 @@
package com.volmit.iris.engine.platform;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.IrisWorlds;
import com.volmit.iris.core.loader.IrisData;
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.util.collection.KList;
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.ChunkDataHunkHolder;
import com.volmit.iris.util.io.ReactiveFolder;
@@ -46,8 +46,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -367,7 +365,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} else {
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
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();
biomes.apply();
}

View File

@@ -29,7 +29,7 @@ import lombok.Data;
@Data
public class IrisContext {
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 ChunkContext chunkContext;
@@ -53,9 +53,10 @@ public class IrisContext {
}
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()) {
dereference();
}
@@ -63,15 +64,13 @@ public class IrisContext {
}
public static void dereference() {
synchronized (context) {
for (Thread i : context.k()) {
if (!i.isAlive() || context.get(i).engine.isClosed()) {
if (context.get(i).engine.isClosed()) {
Iris.debug("Dereferenced Context<Engine> " + i.getName() + " " + i.getId());
}
context.remove(i);
for (Thread i : context.k()) {
if (!i.isAlive() || context.get(i).engine.isClosed()) {
if (context.get(i).engine.isClosed()) {
Iris.debug("Dereferenced Context<Engine> " + i.getName() + " " + i.threadId());
}
context.remove(i);
}
}
}

View File

@@ -529,30 +529,31 @@ public class Mantle {
try {
if (!trim || !unload) {
try {
return getSafe(x, z).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
return getSafe(x, z);
} catch (Throwable e) {
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 {
return getSafe(x, z).get();
return getSafe(x, z);
} catch (InterruptedException e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)");
Iris.reportError(e);
} catch (ExecutionException e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
Iris.reportError(e);
} catch (Throwable e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a unknown exception");
Iris.reportError(e);
}
} finally {
if (trim) ioTrim.release();
@@ -572,50 +573,52 @@ public class Mantle {
* @return the future of a tectonic plate.
*/
@RegionCoordinates
private Future<TectonicPlate> getSafe(int x, int z) {
return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> {
private TectonicPlate getSafe(int x, int z) throws Throwable {
return hyperLock.withNastyResult(x, z, () -> {
Long k = key(x, z);
use(k);
TectonicPlate region = loadedRegions.get(k);
if (region != null && !region.isClosed()) {
return region;
TectonicPlate r = loadedRegions.get(k);
if (r != null && !r.isClosed()) {
return r;
}
File file = fileForRegion(dataFolder, x, z);
if (file.exists()) {
try {
Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath());
region = worker.read(file.getName());
return ioBurst.completeValue(() -> {
TectonicPlate region;
File file = fileForRegion(dataFolder, x, z);
if (file.exists()) {
try {
Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath());
region = worker.read(file.getName());
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);
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);
}
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);
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);
use(k);
return region;
}
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;
}
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;
}));
}).get();
});
}
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.util.data.Varint;
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.io.CountingDataInputStream;
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 lombok.Getter;
import lombok.SneakyThrows;
import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@@ -146,11 +148,10 @@ public class MantleChunk {
}
public void raiseFlag(MantleFlag flag, Runnable r) {
synchronized (this) {
if (!isFlagged(flag)) flag(flag, true);
else return;
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
if (flags.getAndSet(flag.ordinal(), 1) == 0) {
r.run();
}
r.run();
}
public boolean isFlagged(MantleFlag flag) {
@@ -179,6 +180,15 @@ public class MantleChunk {
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
*/

View File

@@ -22,6 +22,7 @@ import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.util.function.NastyRunnable;
import com.volmit.iris.util.function.NastySupplier;
import com.volmit.iris.util.io.IORunnable;
import java.io.IOException;
@@ -107,6 +108,15 @@ public class HyperLock {
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) {
return getLock(x, z).tryLock();
}