Compare commits

...

4 Commits

Author SHA1 Message Date
stormboomer 1956f4d5ef
Merge ed9d469bd0 into ea24554033 2024-01-23 09:27:14 -06:00
mikeprimm ea24554033
Merge pull request #4056 from JurgenKuyper/patch-2
Update DynmapBlockState.java
2024-01-23 09:26:06 -06:00
JurgenKuyper b9144e3609
Update DynmapBlockState.java
also hide nether_quartz_ore if hideores is true
2024-01-22 21:11:43 +01:00
stormboomer ed9d469bd0 Improves Render speed of Zoom tiles by using "free" capacity of the Render Threads.
Works by checking the amount of active Threads processing tiles. If the amount of Active Threads is less than parallelrendercnt we can use the "spare" capacity for zoom processing.
We are using a seperate ThreadPoolExecutor to achive this.
Also adds one more cancellation check to process cancellations for large zoom out renders (when many tiles needs to be processed)
2023-08-30 12:28:00 +02:00
3 changed files with 114 additions and 9 deletions

View File

@ -21,6 +21,7 @@ import org.dynmap.utils.Polygon;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.*;
public abstract class DynmapWorld {
public List<MapType> maps = new ArrayList<MapType>();
@ -55,6 +56,9 @@ public abstract class DynmapWorld {
public int worldheight; // really maxY+1
public int minY;
public int sealevel;
/* used for storing the amount of tiles processed with last zoom render */
private long lastZoomRenderTileCount = 0;
protected void updateWorldHeights(int worldheight, int minY, int sealevel) {
this.worldheight = worldheight;
@ -104,22 +108,121 @@ public abstract class DynmapWorld {
mts.setZoomOutInv(tile.x, tile.y, tile.zoom);
}
}
public void freshenZoomOutFiles() {
/**
* Constructs a thread pool executor that can be used for zoom out processing
* @return a new thread pool executor
*/
private ThreadPoolExecutor getZoomThreadPool(int capacity){
ThreadPoolExecutor executor = new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(capacity)
);
executor.setThreadFactory(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setPriority(Thread.MIN_PRIORITY);
t.setName("Dynmap Zoom Render Thread");
return t;
});
//if the queue is full, we try to put it into it again, until queue is at a level where it can take the request
//This ensures that we will not load too many zoom tiles to memory
executor.setRejectedExecutionHandler((r, internalExecutor) -> {
try {
internalExecutor.getQueue().put( r );
} catch (InterruptedException e) {
e.printStackTrace();
}
});
return executor;
}
/**
* Calculates the maximum parallel Zoom Render threads that are allowed to run. Minimum is 1
* Calculates based on mapmanagers Active Render Thread Count and Parallelrender count
* @param maxParallel the maximum allowed parallel zoom render threads
* @return the number of Zoom render Threads that are allowed to be running
*/
private int getZoomThreadCount(int maxParallel){
int maxThreadCount;
int currentActive = MapManager.mapman.getActivePoolThreadCount();
maxThreadCount = maxParallel - currentActive;
if(maxThreadCount < 1){
maxThreadCount = 1;
}
return maxThreadCount;
}
/**
* Adjusts the Maximum Threads for a Threadpool Executor
* @param executor the Executor to change
* @param maxParallel
*/
private void adjustZoomThreadCount(ThreadPoolExecutor executor, int maxParallel){
int newMaxPool = getZoomThreadCount(maxParallel);
if(executor.getMaximumPoolSize() != newMaxPool){
//we adjust the thread count for zoom rendering based on unused render threads
//the more render threads are not doing anything - the more zoom out rendering we get
executor.setMaximumPoolSize(newMaxPool);
}
}
public void freshenZoomOutFiles(int maxParallel) {
if(maxParallel < 1){
maxParallel = 1; //ensure that we have at least 1 thread for zoom rendering
}
int maxQueueSize = 2*maxParallel;
ThreadPoolExecutor executor = getZoomThreadPool(maxQueueSize);
MapTypeState.ZoomOutCoord c = new MapTypeState.ZoomOutCoord();
long start1 = System.currentTimeMillis();
long tileCounter = 0;
for (MapTypeState mts : mapstate) {
if (cancelled) return;
if (cancelled) {
break;
}
MapType mt = mts.type;
MapType.ImageVariant var[] = mt.getVariants();
mts.startZoomOutIter(); // Start iterator
while (mts.nextZoomOutInv(c)) {
if(cancelled) return;
if (cancelled) {
break;
}
for (int varIdx = 0; varIdx < var.length; varIdx++) {
if (cancelled) {
break;
}
tileCounter++;
MapStorageTile tile = storage.getTile(this, mt, c.x, c.y, c.zoomlevel, var[varIdx]);
processZoomFile(mts, tile, varIdx == 0);
final MapTypeState finalMts = mts;
final MapStorageTile finalTile = tile;
final int finalVarIdx = varIdx;
adjustZoomThreadCount(executor, maxParallel);
executor.execute(() -> {
processZoomFile(finalMts, finalTile, finalVarIdx == 0);
});
}
}
}
long end1 = System.currentTimeMillis();
long duration = end1-start1;
double perTile = (double) duration / (double) tileCounter;
executor.shutdown();
if(tileCounter > 0 ){
Log.info(String.format("Zoom Processing %s - %d tiles (%.2f msec/tile, %.2fs per render)", getName(), tileCounter, perTile, (double) duration / 1000));
}else if(tileCounter == 0 && lastZoomRenderTileCount > 0){
Log.info(String.format("Zoom Processing %s - Completed", getName()));
}
lastZoomRenderTileCount = tileCounter;
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
Log.severe(e);
}
}
public void cancelZoomOutFreshen() {

View File

@ -517,7 +517,7 @@ public class MapManager {
}, new MapStorageTileSearchEndCB() {
@Override
public void searchEnded() {
}
});
sendMessage(String.format("Scan complete - starting render"));
@ -940,14 +940,16 @@ public class MapManager {
scheduleDelayedJob(this, 5000);
}
}
public int getActivePoolThreadCount(){
return render_pool.getActiveCount();
}
private class DoZoomOutProcessing implements Runnable {
public void run() {
if (!tpspausezoomout) {
Debug.debug("DoZoomOutProcessing started");
ArrayList<DynmapWorld> wl = new ArrayList<DynmapWorld>(worlds);
for(DynmapWorld w : wl) {
w.freshenZoomOutFiles();
w.freshenZoomOutFiles(parallelrendercnt);
}
Debug.debug("DoZoomOutProcessing finished");
scheduleDelayedJob(this, zoomout_period*1000);

View File

@ -70,7 +70,7 @@ public class DynmapBlockState {
public static String REDSTONE_ORE_BLOCK = "minecraft:redstone_ore";
public static String LIT_REDSTONE_ORE_BLOCK = "minecraft:lit_redstone_ore";
public static String EMERALD_ORE_BLOCK = "minecraft:emerald_ore";
public static String QUARTZ_ORE_BLOCK = "minecraft:quartz_ore";
public static String QUARTZ_ORE_BLOCK = "minecraft:nether_quartz_ore";
public static String NETHER_GOLD_ORE_BLOCK = "minecraft:nether_gold_ore";
public static String DEEPSLATE_GOLD_ORE_BLOCK = "minecraft:deepslate_gold_ore";
public static String DEEPSLATE_IRON_ORE_BLOCK = "minecraft:deepslate_iron_ore";