Move the world gen thread pool into the WorldGenQueue
We want Core to handle the world gen threads, not the individual world generators
This commit is contained in:
+21
-48
@@ -41,7 +41,6 @@ import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
@@ -64,18 +63,14 @@ import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.chunk.UpgradeData;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFile;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
||||
import net.minecraft.world.level.levelgen.DebugLevelSource;
|
||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/*
|
||||
Total: 3.135214124s
|
||||
=====================================
|
||||
@@ -169,39 +164,32 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
||||
public final StepFeatures stepFeatures = new StepFeatures(this);
|
||||
public final StepLight stepLight = new StepLight(this);
|
||||
public boolean unsafeThreadingRecorded = false;
|
||||
//public boolean safeMode = false;
|
||||
//private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||
public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
|
||||
public static final int EXCEPTION_COUNTER_TRIGGER = 20;
|
||||
public static final int RANGE_TO_RANGE_EMPTY_EXTENSION = 1;
|
||||
public int unknownExceptionCount = 0;
|
||||
public long lastExceptionTriggerTime = 0;
|
||||
|
||||
private AtomicReference<RegionFileStorageExternalCache> regionFileStorageCache = new AtomicReference<>();
|
||||
private AtomicReference<RegionFileStorageExternalCache> regionFileStorageCacheRef = new AtomicReference<>();
|
||||
|
||||
public RegionFileStorageExternalCache getOrCreateRegionFileCache(RegionFileStorage storage)
|
||||
{
|
||||
RegionFileStorageExternalCache cache = regionFileStorageCache.get();
|
||||
RegionFileStorageExternalCache cache = regionFileStorageCacheRef.get();
|
||||
if (cache == null)
|
||||
{
|
||||
cache = new RegionFileStorageExternalCache(storage);
|
||||
if (!regionFileStorageCache.compareAndSet(null, cache))
|
||||
if (!regionFileStorageCacheRef.compareAndSet(null, cache))
|
||||
{
|
||||
cache = regionFileStorageCache.get();
|
||||
cache = regionFileStorageCacheRef.get();
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
public static final LodThreadFactory threadFactory = new LodThreadFactory("DH-Gen-Worker-Thread", Thread.MIN_PRIORITY);
|
||||
|
||||
public static ThreadLocal<Boolean> isDistantGeneratorThread = new ThreadLocal<>();
|
||||
|
||||
public static boolean isCurrentThreadDistantGeneratorThread() { return (isDistantGeneratorThread.get() != null); }
|
||||
|
||||
public ExecutorService executorService = Executors.newFixedThreadPool(
|
||||
Math.max(Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get().intValue(), 1),
|
||||
threadFactory);
|
||||
public static final LodThreadFactory threadFactory = new LodThreadFactory("DH-Gen-Worker-Thread", Thread.MIN_PRIORITY);
|
||||
|
||||
|
||||
|
||||
@@ -227,16 +215,16 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
||||
if (generator.getClass().toString().equals("class com.terraforged.mod.chunk.TFChunkGenerator"))
|
||||
{
|
||||
EVENT_LOGGER.info("TerraForge Chunk Generator detected: ["+generator.getClass()+"], Distant Generation will try its best to support it.");
|
||||
EVENT_LOGGER.info("If it does crash, turn Distant Generation off or set it to to "+EDhApiWorldGenerationStep.EMPTY+".");
|
||||
EVENT_LOGGER.info("If it does crash, turn Distant Generation off or set it to to ["+EDhApiWorldGenerationStep.EMPTY+"].");
|
||||
}
|
||||
else
|
||||
{
|
||||
EVENT_LOGGER.warn("Unknown Chunk Generator detected: ["+generator.getClass()+"], Distant Generation May Fail!");
|
||||
EVENT_LOGGER.warn("If it does crash, set Distant Generation to OFF or Generation Mode to None.");
|
||||
EVENT_LOGGER.warn("If it does crash, disable Distant Generation or set the Generation Mode to ["+EDhApiWorldGenerationStep.EMPTY+"].");
|
||||
}
|
||||
}
|
||||
|
||||
params = new GlobalParameters(serverlevel);
|
||||
this.params = new GlobalParameters(serverlevel);
|
||||
}
|
||||
|
||||
|
||||
@@ -254,8 +242,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
||||
return future.join();
|
||||
}
|
||||
|
||||
public void resizeThreadPool(int newThreadCount) { executorService = Executors.newFixedThreadPool(newThreadCount, new LodThreadFactory("DH-Gen-Worker-Thread", Thread.MIN_PRIORITY)); }
|
||||
|
||||
public void updateAllFutures()
|
||||
{
|
||||
if (unknownExceptionCount > 0)
|
||||
@@ -599,12 +585,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
||||
public int getEventCount() { return this.generationEventList.size(); }
|
||||
|
||||
@Override
|
||||
public void stop(boolean blocking)
|
||||
public void stop()
|
||||
{
|
||||
EVENT_LOGGER.info(BatchGenerationEnvironment.class.getSimpleName()+" shutting down...");
|
||||
|
||||
EVENT_LOGGER.info("Canceling futures...");
|
||||
this.executorService.shutdownNow();
|
||||
EVENT_LOGGER.info("Canceling in progress generation event futures...");
|
||||
Iterator<GenerationEvent> iter = this.generationEventList.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
@@ -613,52 +598,40 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
||||
iter.remove();
|
||||
}
|
||||
|
||||
EVENT_LOGGER.info("Awaiting termination...");
|
||||
if (blocking)
|
||||
// clear the chunk cache
|
||||
var regionStorage = this.regionFileStorageCacheRef.get();
|
||||
if (regionStorage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
int waitTimeInSeconds = 3;
|
||||
if (!this.executorService.awaitTermination(waitTimeInSeconds, TimeUnit.SECONDS))
|
||||
{
|
||||
EVENT_LOGGER.error("Batch Chunk Generator shutdown didn't complete after ["+waitTimeInSeconds+"] seconds! Ignoring child threads...");
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
EVENT_LOGGER.error("Batch Chunk Generator shutdown interrupted! Ignoring child threads...", e);
|
||||
}
|
||||
}
|
||||
var r = regionFileStorageCache.get();
|
||||
if (r != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
r.close();
|
||||
regionStorage.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
EVENT_LOGGER.error("Failed to close region file storage cache!", e);
|
||||
}
|
||||
}
|
||||
|
||||
EVENT_LOGGER.info(BatchGenerationEnvironment.class.getSimpleName()+" shutdown complete.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> generateChunks(int minX, int minZ, int genSize, EDhApiWorldGenerationStep targetStep, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer)
|
||||
public CompletableFuture<Void> generateChunks(
|
||||
int minX, int minZ, int genSize, EDhApiWorldGenerationStep targetStep,
|
||||
ExecutorService worldGeneratorThreadPool, Consumer<IChunkWrapper> resultConsumer)
|
||||
{
|
||||
//System.out.println("GenerationEvent: "+genSize+"@"+minX+","+minZ+" "+targetStep);
|
||||
|
||||
// TODO: Check event overlap via e.tooClose()
|
||||
GenerationEvent genEvent = GenerationEvent.startEvent(new DhChunkPos(minX, minZ), genSize, this, targetStep, runTimeRatio, resultConsumer);
|
||||
generationEventList.add(genEvent);
|
||||
GenerationEvent genEvent = GenerationEvent.startEvent(new DhChunkPos(minX, minZ), genSize, this, targetStep, resultConsumer, worldGeneratorThreadPool);
|
||||
this.generationEventList.add(genEvent);
|
||||
return genEvent.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before code that may run for an extended period of time. <br>
|
||||
* This is necessary to allow canceling world gen since waiting
|
||||
* for them to cancel when leaving a world can take a while.
|
||||
* for some world gen requests to finish can take a while.
|
||||
*/
|
||||
private static void throwIfThreadInterrupted() throws InterruptedException
|
||||
{
|
||||
|
||||
+21
-30
@@ -21,6 +21,7 @@ package com.seibel.lod.common.wrappers.worldGeneration;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -40,23 +41,22 @@ public final class GenerationEvent
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static int generationFutureDebugIDs = 0;
|
||||
|
||||
final int id;
|
||||
final ThreadedParameters threadedParam;
|
||||
final DhChunkPos minPos;
|
||||
final int size;
|
||||
final EDhApiWorldGenerationStep targetGenerationStep;
|
||||
final ELightGenerationMode lightMode;
|
||||
final double runTimeRatio;
|
||||
EventTimer timer = null;
|
||||
long inQueueTime;
|
||||
long timeoutTime = -1;
|
||||
public final int id;
|
||||
public final ThreadedParameters threadedParam;
|
||||
public final DhChunkPos minPos;
|
||||
public final int size;
|
||||
public final EDhApiWorldGenerationStep targetGenerationStep;
|
||||
public final ELightGenerationMode lightMode;
|
||||
public EventTimer timer = null;
|
||||
public long inQueueTime;
|
||||
public long timeoutTime = -1;
|
||||
public CompletableFuture<Void> future = null;
|
||||
final Consumer<IChunkWrapper> resultConsumer;
|
||||
public final Consumer<IChunkWrapper> resultConsumer;
|
||||
|
||||
|
||||
|
||||
public GenerationEvent(DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
||||
EDhApiWorldGenerationStep targetGenerationStep, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer)
|
||||
EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer)
|
||||
{
|
||||
this.inQueueTime = System.nanoTime();
|
||||
this.id = generationFutureDebugIDs++;
|
||||
@@ -65,51 +65,42 @@ public final class GenerationEvent
|
||||
this.targetGenerationStep = targetGenerationStep;
|
||||
this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params);
|
||||
this.lightMode = Config.Client.WorldGenerator.lightGenerationMode.get();
|
||||
this.runTimeRatio = runTimeRatio;
|
||||
this.resultConsumer = resultConsumer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static GenerationEvent startEvent(DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
||||
EDhApiWorldGenerationStep target, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer)
|
||||
public static GenerationEvent startEvent(
|
||||
DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment,
|
||||
EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
||||
ExecutorService worldGeneratorThreadPool)
|
||||
{
|
||||
if (size % 2 == 0)
|
||||
{
|
||||
size += 1; // size must be odd for vanilla world gen regions to work
|
||||
}
|
||||
|
||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, generationGroup, target, runTimeRatio, resultConsumer);
|
||||
|
||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, target, resultConsumer);
|
||||
generationEvent.future = CompletableFuture.runAsync(() ->
|
||||
{
|
||||
long runStartTime = System.nanoTime();
|
||||
generationEvent.timeoutTime = runStartTime;
|
||||
generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime;
|
||||
generationEvent.timer = new EventTimer("setup");
|
||||
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
||||
try
|
||||
{
|
||||
//LOGGER.info("generating [{}]", event.minPos);
|
||||
generationGroup.generateLodFromList(generationEvent);
|
||||
genEnvironment.generateLodFromList(generationEvent);
|
||||
}
|
||||
catch (InterruptedException ignored) { }
|
||||
finally
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
|
||||
if (!Thread.interrupted() && runTimeRatio < 1.0)
|
||||
{
|
||||
long endTime = System.nanoTime();
|
||||
try
|
||||
{
|
||||
long deltaMs = TimeUnit.NANOSECONDS.toMillis(endTime - runStartTime);
|
||||
Thread.sleep((long) (deltaMs / runTimeRatio - deltaMs));
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}, generationGroup.executorService);
|
||||
}, worldGeneratorThreadPool);
|
||||
return generationEvent;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule coreSubProjects updated: 05d4e4bf61...8f6109768c
Reference in New Issue
Block a user