package net.minecraft.server; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongList; import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongMaps; import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import java.time.Duration; import java.util.List; import java.util.Map; import java.util.function.IntSupplier; import javax.annotation.Nullable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.util.Supplier; public class MethodProfiler implements GameProfilerFillerActive { private static final long a = Duration.ofMillis(100L).toNanos(); private static final Logger LOGGER = LogManager.getLogger(); private final List<String> c = Lists.newArrayList(); private final LongList d = new LongArrayList(); private final Map<String, MethodProfiler.a> e = Maps.newHashMap(); private final IntSupplier f; private final long g; private final int h; private String i = ""; private boolean j; @Nullable private MethodProfiler.a k; private final boolean l; public MethodProfiler(long i, IntSupplier intsupplier, boolean flag) { this.g = i; this.h = intsupplier.getAsInt(); this.f = intsupplier; this.l = flag; } @Override public void a() { if (this.j) { MethodProfiler.LOGGER.error("Profiler tick already started - missing endTick()?"); } else { this.j = true; this.i = ""; this.c.clear(); this.enter("root"); } } @Override public void b() { if (!this.j) { MethodProfiler.LOGGER.error("Profiler tick already ended - missing startTick()?"); } else { this.exit(); this.j = false; if (!this.i.isEmpty()) { MethodProfiler.LOGGER.error("Profiler tick ended before path was fully popped (remainder: '{}'). Mismatched push/pop?", new Supplier[]{() -> { return MethodProfilerResults.b(this.i); }}); } } } @Override public void enter(String s) { if (!this.j) { MethodProfiler.LOGGER.error("Cannot push '{}' to profiler if profiler tick hasn't started - missing startTick()?", s); } else { if (!this.i.isEmpty()) { this.i = this.i + '\u001e'; } this.i = this.i + s; this.c.add(this.i); this.d.add(SystemUtils.getMonotonicNanos()); this.k = null; } } @Override public void a(java.util.function.Supplier<String> java_util_function_supplier) { this.enter((String) java_util_function_supplier.get()); } @Override public void exit() { if (!this.j) { MethodProfiler.LOGGER.error("Cannot pop from profiler if profiler tick hasn't started - missing startTick()?"); } else if (this.d.isEmpty()) { MethodProfiler.LOGGER.error("Tried to pop one too many times! Mismatched push() and pop()?"); } else { long i = SystemUtils.getMonotonicNanos(); long j = this.d.removeLong(this.d.size() - 1); this.c.remove(this.c.size() - 1); long k = i - j; MethodProfiler.a methodprofiler_a = this.e(); methodprofiler_a.a = methodprofiler_a.a + k; methodprofiler_a.b = methodprofiler_a.b + 1L; if (this.l && k > MethodProfiler.a) { MethodProfiler.LOGGER.warn("Something's taking too long! '{}' took aprox {} ms", new Supplier[]{() -> { return MethodProfilerResults.b(this.i); }, () -> { return (double) k / 1000000.0D; }}); } this.i = this.c.isEmpty() ? "" : (String) this.c.get(this.c.size() - 1); this.k = null; } } @Override public void exitEnter(String s) { this.exit(); this.enter(s); } private MethodProfiler.a e() { if (this.k == null) { this.k = (MethodProfiler.a) this.e.computeIfAbsent(this.i, (s) -> { return new MethodProfiler.a(); }); } return this.k; } @Override public void c(String s) { this.e().c.addTo(s, 1L); } @Override public void c(java.util.function.Supplier<String> java_util_function_supplier) { this.e().c.addTo(java_util_function_supplier.get(), 1L); } @Override public MethodProfilerResults d() { return new MethodProfilerResultsFilled(this.e, this.g, this.h, SystemUtils.getMonotonicNanos(), this.f.getAsInt()); } static class a implements MethodProfilerResult { private long a; private long b; private Object2LongOpenHashMap<String> c; private a() { this.c = new Object2LongOpenHashMap(); } @Override public long a() { return this.a; } @Override public long b() { return this.b; } @Override public Object2LongMap<String> c() { return Object2LongMaps.unmodifiable(this.c); } } }