From 3e703982673106ddd5f7e112edbc08aba880de77 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Fri, 17 Jul 2026 20:13:31 +0200 Subject: [PATCH 1/2] Pre-load crash report and data fixers off-ain Saves about a second of startup time combined on Windows --- paper-server/build.gradle.kts | 1 + ...re-load-data-off-main-during-startup.patch | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch diff --git a/paper-server/build.gradle.kts b/paper-server/build.gradle.kts index 9af5bd44bf85..d052a1418ea9 100644 --- a/paper-server/build.gradle.kts +++ b/paper-server/build.gradle.kts @@ -291,6 +291,7 @@ fun TaskContainer.registerRunTask( systemProperty("io.papermc.paper.suppress.sout.nags", true) systemProperty("paper.maxChatCommandInputSize", 32767) systemProperty("paper.disableMigrationDelay", true) + systemProperty("paper.updatingMinecraft", providers.gradleProperty("updatingMinecraft").getOrElse("false").toBoolean()) val memoryGb = providers.gradleProperty("paper.runMemoryGb").getOrElse("2") minHeapSize = "${memoryGb}G" diff --git a/paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch b/paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch new file mode 100644 index 000000000000..d1d116e41291 --- /dev/null +++ b/paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Fri, 17 Jul 2026 16:15:46 +0200 +Subject: [PATCH] Pre-load data off-main during startup + + +diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java +index a4d608d64b7d3477c9144d93547fd3b4f39a1b02..953a6b2c21f831cfba5bcf5be435640113f5edca 100644 +--- a/net/minecraft/server/Main.java ++++ b/net/minecraft/server/Main.java +@@ -102,7 +102,10 @@ public class Main { + writePidFile(pidFilePath); + } + +- CrashReport.preload(); ++ // Paper start - Perf: Run CrashReport preload asynchronously ++ // The actual result is discarded/irrelevant, but hardware and software info is memoized ++ offload(CrashReport::preload, "CrashReport preload thread"); ++ // Paper end - Perf: Run CrashReport preload asynchronously + if (options.has("jfrProfile")) { // CraftBukkit + JvmProfiler.INSTANCE.start(Environment.SERVER); + } +@@ -110,6 +113,12 @@ public class Main { + io.papermc.paper.plugin.PluginInitializerManager.load(options); // Paper + Bootstrap.bootStrap(); + Bootstrap.validate(); ++ // Paper start - Perf: Init DataConverter asynchronously ++ // Init for both of these are fairly expensive class-loading wise. Both are called again below/in MinecraftServer.spin, ++ // so failure during class init will become visible there. ++ offload(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry::init, "DataConverter MCTypeRegistry init thread"); ++ offload(DataFixers::getDataFixer, "DataFixers init thread"); ++ // Paper end - Perf: Init DataConverter asynchronously + Util.startTimerHackThread(); + Path settingsFile = Paths.get("server.properties"); + DedicatedServerSettings settings = new DedicatedServerSettings(options); // CraftBukkit - CLI argument support +@@ -362,6 +371,14 @@ public class Main { + } + } + ++ // Paper start ++ private static void offload(final Runnable runnable, final String name) { ++ final Thread thread = new Thread(runnable, name); ++ thread.setDaemon(true); ++ thread.start(); ++ } ++ // Paper end ++ + public static WorldLoader.DataLoadOutput createNewWorldData( // Paper - public + final DedicatedServerSettings settings, + final WorldLoader.DataLoadContext context, +diff --git a/net/minecraft/world/level/block/Blocks.java b/net/minecraft/world/level/block/Blocks.java +index 3ee7f5c578e4721fd95390d76105d6f8976747a1..f94f8049572c860652c97c10ecd888ef2c338262 100644 +--- a/net/minecraft/world/level/block/Blocks.java ++++ b/net/minecraft/world/level/block/Blocks.java +@@ -5996,11 +5996,23 @@ public class Blocks { + } + + static { ++ // Paper start - Perf: Optimize block state cache initialization ++ // initCache of the first state of every block runs directly (to make sure Blocks is always called here) before the rest are put off-thread ++ final java.util.List statesToInit = new java.util.ArrayList<>(); + for (Block block : BuiltInRegistries.BLOCK) { ++ boolean first = true; + for (BlockState state : block.getStateDefinition().getPossibleStates()) { + Block.BLOCK_STATE_REGISTRY.add(state); +- state.initCache(); ++ if (first) { ++ first = false; ++ state.initCache(); ++ } else { ++ statesToInit.add(state); ++ } + } + } ++ // Make sure this stays as a method reference, else the synthetic lambda method makes this blow up ++ statesToInit.parallelStream().forEach(BlockBehaviour.BlockStateBase::initCache); ++ // Paper end - Perf: Optimize block state cache initialization + } + } From dfab689645324e6052d1325430dd746d9154f50e Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Fri, 17 Jul 2026 21:54:53 +0200 Subject: [PATCH 2/2] Use Thread builder --- ...re-load-data-off-main-during-startup.patch | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch b/paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch index d1d116e41291..254626ad1c84 100644 --- a/paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch +++ b/paper-server/patches/features/0034-Pre-load-data-off-main-during-startup.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Pre-load data off-main during startup diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index a4d608d64b7d3477c9144d93547fd3b4f39a1b02..953a6b2c21f831cfba5bcf5be435640113f5edca 100644 +index a4d608d64b7d3477c9144d93547fd3b4f39a1b02..e2939cc39a8c103e4c4d7b01d39b5546486e4fbc 100644 --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java @@ -102,7 +102,10 @@ public class Main { @@ -15,7 +15,7 @@ index a4d608d64b7d3477c9144d93547fd3b4f39a1b02..953a6b2c21f831cfba5bcf5be4356401 - CrashReport.preload(); + // Paper start - Perf: Run CrashReport preload asynchronously + // The actual result is discarded/irrelevant, but hardware and software info is memoized -+ offload(CrashReport::preload, "CrashReport preload thread"); ++ Thread.ofPlatform().daemon().name("CrashReport preload thread").start(CrashReport::preload); + // Paper end - Perf: Run CrashReport preload asynchronously if (options.has("jfrProfile")) { // CraftBukkit JvmProfiler.INSTANCE.start(Environment.SERVER); @@ -27,27 +27,12 @@ index a4d608d64b7d3477c9144d93547fd3b4f39a1b02..953a6b2c21f831cfba5bcf5be4356401 + // Paper start - Perf: Init DataConverter asynchronously + // Init for both of these are fairly expensive class-loading wise. Both are called again below/in MinecraftServer.spin, + // so failure during class init will become visible there. -+ offload(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry::init, "DataConverter MCTypeRegistry init thread"); -+ offload(DataFixers::getDataFixer, "DataFixers init thread"); ++ Thread.ofPlatform().daemon().name("DataConverter MCTypeRegistry init thread").start(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry::init); ++ Thread.ofPlatform().daemon().name("DataFixers init thread").start(DataFixers::getDataFixer); + // Paper end - Perf: Init DataConverter asynchronously Util.startTimerHackThread(); Path settingsFile = Paths.get("server.properties"); DedicatedServerSettings settings = new DedicatedServerSettings(options); // CraftBukkit - CLI argument support -@@ -362,6 +371,14 @@ public class Main { - } - } - -+ // Paper start -+ private static void offload(final Runnable runnable, final String name) { -+ final Thread thread = new Thread(runnable, name); -+ thread.setDaemon(true); -+ thread.start(); -+ } -+ // Paper end -+ - public static WorldLoader.DataLoadOutput createNewWorldData( // Paper - public - final DedicatedServerSettings settings, - final WorldLoader.DataLoadContext context, diff --git a/net/minecraft/world/level/block/Blocks.java b/net/minecraft/world/level/block/Blocks.java index 3ee7f5c578e4721fd95390d76105d6f8976747a1..f94f8049572c860652c97c10ecd888ef2c338262 100644 --- a/net/minecraft/world/level/block/Blocks.java