Add a config to change the number of light baking threads

This commit is contained in:
James Seibel
2023-10-20 20:09:16 -05:00
parent 146d9da417
commit 2900417a3a
4 changed files with 110 additions and 10 deletions
@@ -20,6 +20,8 @@
package com.seibel.distanthorizons.core.api.internal;
import com.seibel.distanthorizons.core.Initializer;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder;
import com.seibel.distanthorizons.core.dataObjects.transformers.ChunkToLodBuilder;
import com.seibel.distanthorizons.core.dataObjects.transformers.FullDataToRenderDataTransformer;
@@ -47,21 +49,20 @@ import java.util.concurrent.ThreadPoolExecutor;
/** Contains code and variables used by both {@link ClientApi} and {@link ServerApi} */
public class SharedApi
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final SharedApi INSTANCE = new SharedApi();
private static final Set<DhChunkPos> UPDATING_CHUNK_SET = ConcurrentHashMap.newKeySet();
private static AbstractDhWorld currentWorld;
private static int lastWorldGenTickDelta = 0;
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
// TODO make an interface or object for handling thread pools like this, this same code is in ~8 places
private static ThreadPoolExecutor lightPopulatorThreadPool;
private static ConfigChangeListener<Integer> threadConfigListener;
private static final ThreadPoolExecutor LIGHT_POPULATOR_THREAD_POOL = ThreadUtil.makeRateLimitedThreadPool(
// thread count doesn't need to be very high since the player can only move so fast, 1 should be plenty
(Runtime.getRuntime().availableProcessors() <= 12) ? 1 : 2,
"Server Light Populator",
(Runtime.getRuntime().availableProcessors() <= 12) ? 0.5 : 0.9,
ThreadUtil.MINIMUM_RELATIVE_PRIORITY);
private static final Set<DhChunkPos> UPDATING_CHUNK_SET = ConcurrentHashMap.newKeySet();
@@ -95,6 +96,7 @@ public class SharedApi
ColumnRenderBufferBuilder.setupExecutorService();
WorldGenerationQueue.setupWorldGenThreadPool();
ChunkToLodBuilder.setupExecutorService();
SharedApi.setupExecutorService();
}
else
{
@@ -104,6 +106,7 @@ public class SharedApi
ColumnRenderBufferBuilder.shutdownExecutorService();
WorldGenerationQueue.shutdownWorldGenThreadPool();
ChunkToLodBuilder.shutdownExecutorService();
SharedApi.shutdownExecutorService();
DebugRenderer.clearRenderables();
@@ -235,7 +238,7 @@ public class SharedApi
private static void bakeChunkLightingAndSendToLevelAsync(IChunkWrapper chunkWrapper, @Nullable ArrayList<IChunkWrapper> neighbourChunkList, IDhLevel dhLevel)
{
// lighting the chunk needs to be done on a separate thread to prevent lagging any of the event threads
LIGHT_POPULATOR_THREAD_POOL.execute(() ->
lightPopulatorThreadPool.execute(() ->
{
try
{
@@ -285,4 +288,52 @@ public class SharedApi
}
//==========================//
// executor handler methods //
//==========================//
/**
* Creates a new executor. <br>
* Does nothing if an executor already exists.
*/
public static void setupExecutorService()
{
// static setup
if (threadConfigListener == null)
{
threadConfigListener = new ConfigChangeListener<>(Config.Client.Advanced.MultiThreading.numberOfChunkLightBakingThreads, (threadCount) -> { setThreadPoolSize(threadCount); });
}
if (lightPopulatorThreadPool == null || lightPopulatorThreadPool.isTerminated())
{
LOGGER.info("Starting " + ChunkToLodBuilder.class.getSimpleName());
setThreadPoolSize(Config.Client.Advanced.MultiThreading.numberOfChunkLightBakingThreads.get());
}
}
public static void setThreadPoolSize(int threadPoolSize)
{
if (lightPopulatorThreadPool != null && !lightPopulatorThreadPool.isTerminated())
{
lightPopulatorThreadPool.shutdownNow();
}
lightPopulatorThreadPool = ThreadUtil.makeRateLimitedThreadPool(threadPoolSize, SharedApi.class.getSimpleName()+" - Light Populator", Config.Client.Advanced.MultiThreading.runTimeRatioForChunkLightBakingThreads);
}
/**
* Stops any executing tasks and destroys the executor. <br>
* Does nothing if the executor isn't running.
*/
public static void shutdownExecutorService()
{
if (lightPopulatorThreadPool != null)
{
LOGGER.info("Stopping " + ChunkToLodBuilder.class.getSimpleName());
lightPopulatorThreadPool.shutdownNow();
}
}
}
@@ -29,7 +29,6 @@ import com.seibel.distanthorizons.core.config.eventHandlers.presets.*;
import com.seibel.distanthorizons.core.config.types.*;
import com.seibel.distanthorizons.core.config.types.enums.*;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
@@ -924,6 +923,24 @@ public class Config
.comment(THREAD_RUN_TIME_RATIO_NOTE)
.build();
public static final ConfigEntry<Integer> numberOfChunkLightBakingThreads = new ConfigEntry.Builder<Integer>()
.setMinDefaultMax(1,
ThreadPresetConfigEventHandler.getLightBakingDefaultThreadCount(),
Runtime.getRuntime().availableProcessors())
.comment(""
+ "How many threads should be used to either pull existing or generating new lighting for chunks \n"
+ "that were recently loading/unloaded? \n"
+ "\n"
+ "These threads run when traveling around the world\n"
+ "and when moving between dimensions. \n"
+ "\n"
+ THREAD_NOTE)
.build();
public static final ConfigEntry<Double> runTimeRatioForChunkLightBakingThreads = new ConfigEntry.Builder<Double>()
.setMinDefaultMax(0.01, ThreadPresetConfigEventHandler.getLightBakingDefaultRunTimeRatio(), 1.0)
.comment(THREAD_RUN_TIME_RATIO_NOTE)
.build();
}
public static class GpuBuffers
@@ -151,6 +151,28 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
}});
public static int getLightBakingDefaultThreadCount() { return getThreadCountByPercent(0.1); }
private final ConfigEntryWithPresetOptions<EThreadPreset, Integer> lightBakingThreadCount = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfChunkLightBakingThreads,
new HashMap<EThreadPreset, Integer>()
{{
this.put(EThreadPreset.MINIMAL_IMPACT, 1);
this.put(EThreadPreset.LOW_IMPACT, getChunkLodConverterDefaultThreadCount());
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.2));
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.4));
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
}});
public static double getLightBakingDefaultRunTimeRatio() { return LOW_THREAD_COUNT_CPU ? 0.25 : 0.4; }
private final ConfigEntryWithPresetOptions<EThreadPreset, Double> lightBakingRunTime = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.runTimeRatioForChunkLightBakingThreads,
new HashMap<EThreadPreset, Double>()
{{
this.put(EThreadPreset.MINIMAL_IMPACT, 0.1);
this.put(EThreadPreset.LOW_IMPACT, getChunkLodConverterDefaultRunTimeRatio());
this.put(EThreadPreset.BALANCED, LOW_THREAD_COUNT_CPU ? 0.5 : 0.65);
this.put(EThreadPreset.AGGRESSIVE, LOW_THREAD_COUNT_CPU ? 0.75 : 1.0);
//this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, 1.0);
}});
//==============//
// constructors //
@@ -175,6 +197,9 @@ public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHan
this.configList.add(this.chunkLodConverterThreadCount);
this.configList.add(this.chunkLodConverterRunTime);
this.configList.add(this.lightBakingThreadCount);
this.configList.add(this.lightBakingRunTime);
for (ConfigEntryWithPresetOptions<EThreadPreset, ?> config : this.configList)
{
@@ -388,6 +388,13 @@
"distanthorizons.config.client.advanced.multiThreading.runTimeRatioForChunkLodConverterThreads":
"Runtime % for chunk LOD converter threads",
"distanthorizons.config.client.advanced.multiThreading.numberOfLightBakingThreads":
"NO. of chunk light baking threads",
"distanthorizons.config.client.advanced.multiThreading.numberOfLightBakingThreads.@tooltip":
"How many threads should be used to either pull existing or generating new lighting for chunks\n that were recently loading/unloaded?\n\n These threads run when traveling around the world\n and when moving between dimensions.",
"distanthorizons.config.client.advanced.multiThreading.runTimeRatioForLightBakingThreads":
"Runtime % for chunk light baking threads",
"distanthorizons.config.client.advanced.debugging":