package net.minecraft.server.packs.resources; import com.google.common.base.Stopwatch; import com.mojang.logging.LogUtils; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import net.minecraft.Util; import net.minecraft.util.Unit; import net.minecraft.util.profiling.Profiler; import net.minecraft.util.profiling.ProfilerFiller; import org.slf4j.Logger; public class ProfiledReloadInstance extends SimpleReloadInstance { private static final Logger LOGGER = LogUtils.getLogger(); private final Stopwatch total = Stopwatch.createUnstarted(); public static ReloadInstance of( ResourceManager resourceManager, List listeners, Executor backgroundExecutor, Executor gameExecutor, CompletableFuture alsoWaitedFor ) { ProfiledReloadInstance profiledReloadInstance = new ProfiledReloadInstance(listeners); profiledReloadInstance.startTasks( backgroundExecutor, gameExecutor, resourceManager, listeners, (preparationBarrier, resourceManagerx, preparableReloadListener, executor2, executor3) -> { AtomicLong atomicLong = new AtomicLong(); AtomicLong atomicLong2 = new AtomicLong(); AtomicLong atomicLong3 = new AtomicLong(); AtomicLong atomicLong4 = new AtomicLong(); CompletableFuture completableFuture = preparableReloadListener.reload( preparationBarrier, resourceManagerx, profiledExecutor(executor2, atomicLong, atomicLong2, preparableReloadListener.getName()), profiledExecutor(executor3, atomicLong3, atomicLong4, preparableReloadListener.getName()) ); return completableFuture.thenApplyAsync(void_ -> { LOGGER.debug("Finished reloading {}", preparableReloadListener.getName()); return new ProfiledReloadInstance.State(preparableReloadListener.getName(), atomicLong, atomicLong2, atomicLong3, atomicLong4); }, gameExecutor); }, alsoWaitedFor ); return profiledReloadInstance; } private ProfiledReloadInstance(List listeners) { super(listeners); this.total.start(); } @Override protected CompletableFuture> prepareTasks( Executor backgroundExecutor, Executor gameExectutor, ResourceManager resourceManager, List listeners, SimpleReloadInstance.StateFactory stateFactory, CompletableFuture alsoWaitedFor ) { return super.prepareTasks(backgroundExecutor, gameExectutor, resourceManager, listeners, stateFactory, alsoWaitedFor) .thenApplyAsync(this::finish, gameExectutor); } private static Executor profiledExecutor(Executor executor, AtomicLong timeTaken, AtomicLong timesRun, String name) { return runnable -> executor.execute(() -> { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push(name); long l = Util.getNanos(); runnable.run(); timeTaken.addAndGet(Util.getNanos() - l); timesRun.incrementAndGet(); profilerFiller.pop(); }); } private List finish(List datapoints) { this.total.stop(); long l = 0L; LOGGER.info("Resource reload finished after {} ms", this.total.elapsed(TimeUnit.MILLISECONDS)); for (ProfiledReloadInstance.State state : datapoints) { long m = TimeUnit.NANOSECONDS.toMillis(state.preparationNanos.get()); long n = state.preparationCount.get(); long o = TimeUnit.NANOSECONDS.toMillis(state.reloadNanos.get()); long p = state.reloadCount.get(); long q = m + o; long r = n + p; String string = state.name; LOGGER.info("{} took approximately {} tasks/{} ms ({} tasks/{} ms preparing, {} tasks/{} ms applying)", string, r, q, n, m, p, o); l += o; } LOGGER.info("Total blocking time: {} ms", l); return datapoints; } public record State(String name, AtomicLong preparationNanos, AtomicLong preparationCount, AtomicLong reloadNanos, AtomicLong reloadCount) { } }