--- a/net/minecraft/Util.java +++ b/net/minecraft/Util.java @@ -92,9 +_,26 @@ private static final int DEFAULT_MAX_THREADS = 255; private static final int DEFAULT_SAFE_FILE_OPERATION_RETRIES = 10; private static final String MAX_THREADS_SYSTEM_PROPERTY = "max.bg.threads"; - private static final TracingExecutor BACKGROUND_EXECUTOR = makeExecutor("Main"); + private static final TracingExecutor BACKGROUND_EXECUTOR = makeExecutor("Main", -1); // Paper - Perf: add priority private static final TracingExecutor IO_POOL = makeIoExecutor("IO-Worker-", false); + public static final TracingExecutor DIMENSION_DATA_IO_POOL = makeExtraIoExecutor("Dimension-Data-IO-Worker-"); // Paper - Separate dimension data IO pool private static final TracingExecutor DOWNLOAD_POOL = makeIoExecutor("Download-", true); + // Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread + public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() { + + private final AtomicInteger count = new AtomicInteger(); + + @Override + public Thread newThread(Runnable run) { + Thread ret = new Thread(run); + ret.setName("Profile Lookup Executor #" + this.count.getAndIncrement()); + ret.setUncaughtExceptionHandler((Thread thread, Throwable throwable) -> { + LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); + }); + return ret; + } + }); + // Paper end - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT); public static final int LINEAR_LOOKUP_THRESHOLD = 8; private static final Set ALLOWED_UNTRUSTED_LINK_PROTOCOLS = Set.of("http", "https"); @@ -113,6 +_,7 @@ .findFirst() .orElseThrow(() -> new IllegalStateException("No jar file system provider found")); private static Consumer thePauser = string -> {}; + public static final double COLLISION_EPSILON = 1.0E-7; // Paper - Check distance in entity interactions public static Collector, ?, Map> toMap() { return Collectors.toMap(Entry::getKey, Entry::getValue); @@ -135,7 +_,7 @@ } public static long getNanos() { - return timeSource.getAsLong(); + return System.nanoTime(); // Paper } public static long getEpochMillis() { @@ -146,9 +_,10 @@ return FILENAME_DATE_TIME_FORMATTER.format(ZonedDateTime.now()); } - private static TracingExecutor makeExecutor(String name) { + private static TracingExecutor makeExecutor(String name, final int priorityModifier) { // Paper - Perf: add priority int i = maxAllowedExecutorThreads(); - ExecutorService directExecutorService; + // Paper start - Perf: use simpler thread pool that allows 1 thread and reduce worldgen thread worker count for low core count CPUs + final ExecutorService directExecutorService; if (i <= 0) { directExecutorService = MoreExecutors.newDirectExecutorService(); } else { @@ -173,16 +_,30 @@ super.onTermination(throwOnTermination); } }; + forkJoinWorkerThread.setPriority(Thread.NORM_PRIORITY + priorityModifier); // Paper - Deprioritize over main forkJoinWorkerThread.setName(string); return forkJoinWorkerThread; - }, Util::onThreadException, true); + }, Util::onThreadException, true, 0, Integer.MAX_VALUE, 1, null, 365, TimeUnit.DAYS); // Paper - do not expire threads } return new TracingExecutor(directExecutorService); } public static int maxAllowedExecutorThreads() { - return Mth.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, getMaxThreads()); + // Paper start - Perf: use simpler thread pool that allows 1 thread and reduce worldgen thread worker count for low core count CPUs + final int cpus = Runtime.getRuntime().availableProcessors() / 2; + int maxExecutorThreads; + if (cpus <= 4) { + maxExecutorThreads = cpus <= 2 ? 1 : 2; + } else if (cpus <= 8) { + // [5, 8] + maxExecutorThreads = Math.max(3, cpus - 2); + } else { + maxExecutorThreads = cpus * 2 / 3; + } + maxExecutorThreads = Math.min(8, maxExecutorThreads); + return Integer.getInteger("Paper.WorkerThreadCount", maxExecutorThreads); + // Paper end - Perf: use simpler thread pool that allows 1 thread and reduce worldgen thread worker count for low core count CPUs } private static int getMaxThreads() { @@ -233,6 +_,21 @@ })); } + // Paper start - Separate dimension data IO pool + private static TracingExecutor makeExtraIoExecutor(String namePrefix) { + AtomicInteger atomicInteger = new AtomicInteger(1); + return new TracingExecutor(Executors.newFixedThreadPool(4, runnable -> { + Thread thread = new Thread(runnable); + String string2 = namePrefix + atomicInteger.getAndIncrement(); + TracyClient.setThreadName(string2, namePrefix.hashCode()); + thread.setName(string2); + thread.setDaemon(false); + thread.setUncaughtExceptionHandler(Util::onThreadException); + return thread; + })); + } + // Paper end - Separate dimension data IO pool + public static void throwAsRuntime(Throwable throwable) { throw throwable instanceof RuntimeException ? (RuntimeException)throwable : new RuntimeException(throwable); } @@ -1075,16 +_,7 @@ } public void openUri(URI uri) { - try { - Process process = AccessController.doPrivileged( - (PrivilegedExceptionAction)(() -> Runtime.getRuntime().exec(this.getOpenUriArguments(uri))) - ); - process.getInputStream().close(); - process.getErrorStream().close(); - process.getOutputStream().close(); - } catch (IOException | PrivilegedActionException var3) { - Util.LOGGER.error("Couldn't open location '{}'", uri, var3); - } + throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code } public void openFile(File file) {