add thread config listeners

This commit is contained in:
James Seibel
2023-06-05 09:10:33 -05:00
parent 05d4e4bf61
commit d64446ecda
4 changed files with 134 additions and 37 deletions
@@ -1,7 +1,9 @@
package com.seibel.lod.core.api.internal;
import com.seibel.lod.core.Initializer;
import com.seibel.lod.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder;
import com.seibel.lod.core.dataObjects.transformers.DataRenderTransformer;
import com.seibel.lod.core.file.fullDatafile.FullDataFileHandler;
import com.seibel.lod.core.world.*;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
@@ -29,10 +31,14 @@ public class SharedApi
if (currentWorld == null)
{
DataRenderTransformer.shutdownExecutorService();
FullDataFileHandler.shutdownExecutorService();
ColumnRenderBufferBuilder.shutdownExecutorService();
}
else
{
DataRenderTransformer.setupExecutorService();
FullDataFileHandler.setupExecutorService();
ColumnRenderBufferBuilder.setupExecutorService();
}
}
@@ -4,8 +4,10 @@ import com.seibel.lod.api.enums.config.EGpuUploadMethod;
import com.seibel.lod.api.enums.rendering.EDebugMode;
import com.seibel.lod.api.enums.rendering.EGLProxyContext;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
import com.seibel.lod.core.dataObjects.render.ColumnRenderSource;
import com.seibel.lod.core.dataObjects.render.columnViews.ColumnArrayView;
import com.seibel.lod.core.dataObjects.transformers.DataRenderTransformer;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.level.IDhClientLevel;
import com.seibel.lod.core.logging.ConfigBasedLogger;
@@ -13,7 +15,6 @@ import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.pos.DhBlockPos;
import com.seibel.lod.core.render.glObject.GLProxy;
import com.seibel.lod.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.RenderDataPointUtil;
import com.seibel.lod.core.util.ThreadUtil;
import com.seibel.lod.core.util.objects.Reference;
@@ -37,11 +38,13 @@ public class ColumnRenderBufferBuilder
() -> Config.Client.Advanced.Debugging.DebugSwitch.logRendererBufferEvent.get());
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
//TODO: Make the pool change thread count after the config value is changed
public static final ExecutorService BUFFER_BUILDER_THREADS = ThreadUtil.makeThreadPool(Config.Client.Advanced.Threading.numberOfBufferBuilderThreads.get(), "BufferBuilder");
public static final ExecutorService BUFFER_UPLOADER = ThreadUtil.makeSingleThreadPool("ColumnBufferUploader");
// TODO this should probably be based on the number of builder threads
public static final int MAX_CONCURRENT_CALL = 8;
public static ExecutorService bufferUploaderThreadPool = ThreadUtil.makeSingleThreadPool("ColumnBufferUploader");
public static ExecutorService bufferBuilderThreadPool;
private static ConfigChangeListener<Integer> configListener;
public static final int MAX_NUMBER_OF_CONCURRENT_CALLS_PER_THREAD = 3;
public static int maxNumberOfConcurrentCalls = MAX_NUMBER_OF_CONCURRENT_CALLS_PER_THREAD;
@@ -50,7 +53,6 @@ public class ColumnRenderBufferBuilder
// vbo building //
//==============//
/// TODO this is static, it should be moved to its own class to prevent confusion
/** @return null if busy */
public static CompletableFuture<ColumnRenderBuffer> buildBuffers(IDhClientLevel clientLevel, Reference<ColumnRenderBuffer> renderBufferRef, ColumnRenderSource renderSource, ColumnRenderSource[] adjData)
{
@@ -90,7 +92,7 @@ public class ColumnRenderBufferBuilder
throw e3;
}
}, BUFFER_BUILDER_THREADS)
}, bufferBuilderThreadPool)
.thenApplyAsync((quadBuilder) ->
{
try
@@ -134,7 +136,7 @@ public class ColumnRenderBufferBuilder
throw e3;
}
},
BUFFER_UPLOADER).handle((columnRenderBuffer, ex) ->
bufferUploaderThreadPool).handle((columnRenderBuffer, ex) ->
{
//LOGGER.info("RenderRegion endBuild @ {}", renderSource.sectionPos);
if (ex != null)
@@ -356,6 +358,50 @@ public class ColumnRenderBufferBuilder
//==========================//
// executor handler methods //
//==========================//
/**
* Creates a new executor. <br>
* Does nothing if an executor already exists.
*/
public static void setupExecutorService()
{
// static setup
if (configListener == null)
{
configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfBufferBuilderThreads, (threadCount) -> { setThreadPoolSize(threadCount); });
}
if (bufferBuilderThreadPool == null || bufferBuilderThreadPool.isTerminated())
{
LOGGER.info("Starting "+ ColumnRenderBufferBuilder.class.getSimpleName());
setThreadPoolSize(Config.Client.Advanced.Threading.numberOfBufferBuilderThreads.get());
}
}
public static void setThreadPoolSize(int threadPoolSize)
{
bufferBuilderThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, "BufferBuilder");
maxNumberOfConcurrentCalls = threadPoolSize * MAX_NUMBER_OF_CONCURRENT_CALLS_PER_THREAD;
}
/**
* Stops any executing tasks and destroys the executor. <br>
* Does nothing if the executor isn't running.
*/
public static void shutdownExecutorService()
{
if (bufferBuilderThreadPool != null)
{
LOGGER.info("Stopping "+ColumnRenderBufferBuilder.class.getSimpleName());
bufferBuilderThreadPool.shutdownNow();
}
}
//=========//
// getters //
//=========//
@@ -363,10 +409,10 @@ public class ColumnRenderBufferBuilder
// TODO move static methods to their own class to avoid confusion
private static long getCurrentJobsCount()
{
long jobs = ((ThreadPoolExecutor) BUFFER_BUILDER_THREADS).getQueue().stream().filter(runnable -> !((Future<?>) runnable).isDone()).count();
jobs += ((ThreadPoolExecutor) BUFFER_UPLOADER).getQueue().stream().filter(runnable -> !((Future<?>) runnable).isDone()).count();
long jobs = ((ThreadPoolExecutor) bufferBuilderThreadPool).getQueue().stream().filter(runnable -> !((Future<?>) runnable).isDone()).count();
jobs += ((ThreadPoolExecutor) bufferUploaderThreadPool).getQueue().stream().filter(runnable -> !((Future<?>) runnable).isDone()).count();
return jobs;
}
public static boolean isBusy() { return getCurrentJobsCount() > MAX_CONCURRENT_CALL; }
public static boolean isBusy() { return getCurrentJobsCount() > maxNumberOfConcurrentCalls; }
}
@@ -1,10 +1,12 @@
package com.seibel.lod.core.dataObjects.transformers;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
import com.seibel.lod.core.dataObjects.render.ColumnRenderLoader;
import com.seibel.lod.core.dataObjects.render.ColumnRenderSource;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.file.fullDatafile.FullDataFileHandler;
import com.seibel.lod.core.level.IDhClientLevel;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.util.ThreadUtil;
@@ -20,7 +22,8 @@ public class DataRenderTransformer
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static ExecutorService transformerThreads = null;
private static ExecutorService transformerThreadPool = null;
private static ConfigChangeListener<Integer> configListener;
@@ -30,12 +33,12 @@ public class DataRenderTransformer
public static CompletableFuture<ColumnRenderSource> transformDataSourceAsync(IFullDataSource fullDataSource, IDhClientLevel level)
{
return CompletableFuture.supplyAsync(() -> transform(fullDataSource, level), transformerThreads);
return CompletableFuture.supplyAsync(() -> transform(fullDataSource, level), transformerThreadPool);
}
public static CompletableFuture<ColumnRenderSource> transformDataSourceAsync(CompletableFuture<IFullDataSource> fullDataSourceFuture, IDhClientLevel level)
{
return fullDataSourceFuture.thenApplyAsync((fullDataSource) -> transform(fullDataSource, level), transformerThreads);
return fullDataSourceFuture.thenApplyAsync((fullDataSource) -> transform(fullDataSource, level), transformerThreadPool);
}
private static ColumnRenderSource transform(IFullDataSource fullDataSource, IDhClientLevel level)
@@ -72,13 +75,20 @@ public class DataRenderTransformer
*/
public static void setupExecutorService()
{
if (transformerThreads == null || transformerThreads.isTerminated())
// static setup
if (configListener == null)
{
configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfDataConverterThreads, (threadCount) -> { setThreadPoolSize(threadCount); });
}
if (transformerThreadPool == null || transformerThreadPool.isTerminated())
{
LOGGER.info("Starting "+DataRenderTransformer.class.getSimpleName());
// TODO change when the config is modified
transformerThreads = ThreadUtil.makeThreadPool(Config.Client.Advanced.Threading.numberOfDataConverterThreads.get(), "Data/Render Transformer");
setThreadPoolSize(Config.Client.Advanced.Threading.numberOfDataConverterThreads.get());
}
}
public static void setThreadPoolSize(int threadPoolSize) { transformerThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, "Data/Render Transformer"); }
/**
* Stops any executing tasks and destroys the executor. <br>
@@ -86,10 +96,10 @@ public class DataRenderTransformer
*/
public static void shutdownExecutorService()
{
if (transformerThreads != null)
if (transformerThreadPool != null)
{
LOGGER.info("Stopping "+DataRenderTransformer.class.getSimpleName());
transformerThreads.shutdownNow();
transformerThreadPool.shutdownNow();
}
}
@@ -9,6 +9,7 @@ import com.seibel.lod.core.dataObjects.fullData.sources.*;
import com.seibel.lod.core.dataObjects.fullData.sources.CompleteFullDataSource;
import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource;
import com.seibel.lod.core.dataObjects.transformers.DataRenderTransformer;
import com.seibel.lod.core.util.FileUtil;
import com.seibel.lod.core.file.metaData.BaseMetaData;
import com.seibel.lod.core.level.IDhLevel;
@@ -34,8 +35,8 @@ public class FullDataFileHandler implements IFullDataSourceProvider
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
protected ExecutorService fileHandlerThreadPool;
protected final ConfigChangeListener<Integer> configListener;
protected static ExecutorService fileHandlerThreadPool;
protected static ConfigChangeListener<Integer> configListener;
protected final ConcurrentHashMap<DhSectionPos, FullDataMetaFile> fileBySectionPos = new ConcurrentHashMap<>();
protected final IDhLevel level;
@@ -47,11 +48,6 @@ public class FullDataFileHandler implements IFullDataSourceProvider
public FullDataFileHandler(IDhLevel level, File saveRootDir)
{
configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfFileHandlerThreads, (threadCount) -> { this.setThreadPoolSize(threadCount); });
int threadPoolSize = Config.Client.Advanced.Threading.numberOfFileHandlerThreads.get();
this.setThreadPoolSize(threadPoolSize);
this.saveDir = saveRootDir;
this.level = level;
}
@@ -433,7 +429,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
@Override
public CompletableFuture<IFullDataSource> onDataFileRefresh(IFullDataSource source, BaseMetaData metaData, Function<IFullDataSource, Boolean> updater, Consumer<IFullDataSource> onUpdated)
{
if (this.fileHandlerThreadPool.isTerminated())
if (fileHandlerThreadPool.isTerminated())
{
return CompletableFuture.completedFuture(source);
}
@@ -462,26 +458,65 @@ public class FullDataFileHandler implements IFullDataSourceProvider
onUpdated.accept(sourceLocal);
}
return sourceLocal;
}, this.fileHandlerThreadPool);
}, fileHandlerThreadPool);
}
@Override
public File computeDataFilePath(DhSectionPos pos) { return new File(this.saveDir, pos.serialize() + ".lod"); }
@Override
public ExecutorService getIOExecutor() { return this.fileHandlerThreadPool; }
public void setThreadPoolSize(int threadPoolSize) { fileHandlerThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, FullDataFileHandler.class.getSimpleName()+"Thread"); }
//==========================//
// executor handler methods //
//==========================//
/**
* Creates a new executor. <br>
* Does nothing if an executor already exists.
*/
public static void setupExecutorService()
{
// static setup
if (configListener == null)
{
configListener = new ConfigChangeListener<>(Config.Client.Advanced.Threading.numberOfFileHandlerThreads, (threadCount) -> { setThreadPoolSize(threadCount); });
}
if (fileHandlerThreadPool == null || fileHandlerThreadPool.isTerminated())
{
LOGGER.info("Starting "+FullDataFileHandler.class.getSimpleName());
setThreadPoolSize(Config.Client.Advanced.Threading.numberOfFileHandlerThreads.get());
}
}
public static void setThreadPoolSize(int threadPoolSize) { fileHandlerThreadPool = ThreadUtil.makeThreadPool(threadPoolSize, FullDataFileHandler.class.getSimpleName()+"Thread"); }
/**
* Stops any executing tasks and destroys the executor. <br>
* Does nothing if the executor isn't running.
*/
public static void shutdownExecutorService()
{
if (fileHandlerThreadPool != null)
{
LOGGER.info("Stopping "+ FullDataFileHandler.class.getSimpleName());
fileHandlerThreadPool.shutdownNow();
}
}
@Override
public ExecutorService getIOExecutor() { return fileHandlerThreadPool; }
//=========//
// cleanup //
//=========//
@Override
public void close()
{
FullDataMetaFile.debugPhantomLifeCycleCheck();
configListener.close();
// stop any existing file tasks
this.fileHandlerThreadPool.shutdownNow();
}
}