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:
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user