Files
Iris/docs/33 - Performance Tuning.md
T
Brian Neumann-Fopiano ebfe278b3b Docvks
2026-08-10 15:47:26 -04:00

9.9 KiB
Raw Blame History

33 - Performance Tuning

Iris throughput is dominated by generation threads, mantle residency, pregen in-flight limits, cache sizes, and optional SIMD kernels. All knobs below live in settings.json under the Iris data directory unless noted. Settings overview: 03 - Configuration.md. Pregen operations: 07 - Pregeneration.md. Determinism must stay intact after tuning — verify with GoldenHash (32 - Determinism & Goldenhash.md).

Tutorial: measure one tuning change

Choose the first knob from observed evidence, not from hardware size alone:

Observed limit First controlled change
Mantle backpressure or timeout warnings Lower pregen in-flight concurrency; then test a lower maxResidentTectonicPlates if heap pressure remains
High retained heap or long GC pauses Lower loader caches and resident plate cap; do not raise concurrency
Repeated object/resource loading with spare heap Raise only the cache that is missing (objectLoaderCacheSize or resourceLoaderCacheSize)
CPU-bound generation with stable heap Confirm the Vector API module and A/B simdKernels; benchmark engineSVC.parallelism only afterward
Region scheduler warnings or chunk-load timeouts Lower pregen concurrency or use serial/sync isolation before increasing timeout values
Studio memory growth during repeated edits A/B trimMantleInStudio in Studio only
  1. Freeze the Iris artifact, pack bytes, seed, center, radius, Java flags, and server population.
  2. Run one warmup, then record at least three baseline runs with chunk throughput, wall time, peak heap, GC behavior, failed chunks, and GoldenHash.
  3. Change one setting from the tables below and restart if that setting constructs a pool, cache, or SIMD kernel.
  4. Repeat the same warmup and three measured runs. Reject comparisons that used different generated areas or active plugins.
  5. Keep the change only when the median improves without a determinism mismatch, new failure, unacceptable memory growth, or worse tick latency.
  6. Restore the previous value before testing the next knob.

Use JProfiler for stalls, allocation pressure, scheduler behavior, or unexplained regressions. A faster pregen status line by itself is not enough evidence for a production tuning recommendation.

Where settings live

Platform Data directory Settings file
Bukkit-family plugins/Iris/ settings.json
Fabric / Forge / NeoForge loader config iris/ settings.json

Hotload behavior for settings follows 03 - Configuration.md. After changing SIMD or thread-pool related keys, restart if values are read once at kernel install / pool creation.

Performance section (performance)

Key Default Role
performance.simdKernels true When true and jdk.incubator.vector is available, use vector kernels; otherwise scalar fallbacks
performance.mantleKeepAlive 30 Mantle plate keep-alive window (seconds-scale residency control used by mantle lifecycle)
performance.mantleCleanupDelay 200 Delay before mantle cleanup work
performance.trimMantleInStudio false When true, studio worlds trim mantle more aggressively
performance.noiseCacheSize 1024 Noise sample cache capacity
performance.resourceLoaderCacheSize 1024 Pack resource loader cache capacity
performance.objectLoaderCacheSize 4096 Object (.iob) loader cache capacity
performance.engineSVC.useVirtualThreads true Engine service uses virtual threads when true
performance.engineSVC.forceMulticoreWrite false Force multicore write path
performance.engineSVC.priority Thread.NORM_PRIORITY Clamped to valid Java thread priorities
performance.engineSVC.parallelism -1 >0 caps at 2 * CPU; ≤0 uses ceil(sqrt(CPU))

Larger loader caches trade heap for fewer pack disk/JSON reloads during generation. Raise objectLoaderCacheSize when pregen is object-heavy and the pack is large; lower caches if heap pressure shows retained pack data.

Pregen section (pregen)

Key Default Role
pregen.runtimeSchedulerMode AUTO Bukkit pregen scheduler mode: AUTO, PAPER_LIKE, FOLIA (Folia runtime always resolves to Folia scheduling)
pregen.paperLikeBackendMode AUTO Paper-like backend: AUTO, TICKET, SERVICE
pregen.chunkLoadTimeoutSeconds 15 Clamped 5120
pregen.timeoutWarnIntervalMs 500 Minimum 250 ms between timeout warnings
pregen.saveIntervalMs 30000 Clamped 5_000900_000
pregen.maxResidentTectonicPlates 96 Soft cap (effective floor 16) on resident mantle tectonic plates
pregen.mantleBackpressureWaitMs 25 Clamped 51000; wait when mantle backpressure engages
pregen.mantleBackpressureTimeoutMs 60000 Clamped 5_000600_000
pregen.moddedPregenInFlight 0 0 = auto clamp(16, cpu*2, 48); positive values clamp to 1512

Effective resident plates also scale with world height and process heap: higher worlds and smaller heaps reduce the effective plate count (minimum 16). If pregen stalls with mantle pressure, lower concurrency first, then reduce maxResidentTectonicPlates, or raise heap so the byte budget allows more plates.

Related world flag: world.globalPregenCache (default false) — global pregen cache behavior; see 03 - Configuration.md / 07 - Pregeneration.md.

Concurrency helpers (concurrency)

IrisSettingsConcurrency exposes derived counts (not all are free-form JSON knobs with independent storage in every build path):

  • World-gen style parallelism floors at max(2, availableProcessors).
  • IO parallelism floors at max(2, availableProcessors / 2).

Prefer pregen in-flight limits and engineSVC.parallelism for production tuning rather than inventing extra thread pools outside settings.

SIMD

Note: Broader SIMD coverage (including full noise-kernel wiring through production worldgen) is actively being worked on. Array kernels used on some hot paths already honor performance.simdKernels when the incubator Vector API is available; treat noise SIMD as incomplete until that work lands.

Runtime selection (SimdSupport) today:

  1. If performance.simdKernels is false → scalar kernels.
  2. Else if module jdk.incubator.vector is present and vector kernel classes load → vector kernels for array ops used in some generation hot paths (for example roundToInt via ChunkedDoubleDataCache, carving paths via MantleCarvingComponent).
  3. Else → scalar kernels; startup log tells the operator to add --add-modules jdk.incubator.vector.

2D fractal noise vector kernels exist (VectorNoiseKernels2D) and are gated to CPUs where double vector width is profitable (≥ 4 lanes). That path is selected by SimdSupport.noiseKernels2D() but is not the primary wired worldgen path yet.

JVM flag (required for vector API incubator):

--add-modules jdk.incubator.vector

Server start scripts and Gradle run configs for Iris already pass this where Iris launches the JVM. Standalone microbench: tools/simd-bench/ (./run.sh or run.bat). That tool force-measures kernels even when Iris would gate noise SIMD off (for example Apple Silicon 2-lane NEON). Microbench speedups do not guarantee end-to-end pregen gains.

To A/B SIMD on a full server: set performance.simdKernels false, restart, measure pregen chunks/s, re-enable, restart, remeasure. Confirm GoldenHash unchanged (32 - Determinism & Goldenhash.md).

Operator pregen modes that affect load

Mode Platform Effect
Default pregen All Concurrent generation within platform scheduler limits
serial=true Bukkit Paper-compatible only Strict one-in-flight chunk pregen; rejected on non-Paper serial support
sync / in-flight flags Modded Synchronous or capped async pregen; see 07 - Pregeneration.md
moddedPregenInFlight Modded Caps concurrent pregen chunk work

For profiling and determinism isolation, prefer serial/sync one-in-flight runs. For production throughput, use default concurrency and raise heap before raising mantle plate caps.

Practical tuning order

  1. Heap and GC — give the process enough heap for pack caches + mantle plates (release smoke used 8 GiB heap on large pregens; size to hardware).
  2. Confirm SIMD module — check startup log for SIMD: vector kernels enabled vs scalar message.
  3. Pregen concurrency — use default; only lower in-flight / use serial when CPU saturated or region scheduling warns.
  4. Mantle residency — if backpressure timeouts appear, reduce maxResidentTectonicPlates or pregen speed; increase heap if plates thrash.
  5. Caches — raise object/resource caches when the same objects reload repeatedly; lower if heap retains too much after pregen.
  6. engineSVC.parallelism — set an explicit positive value only after measuring; -1 already scales with CPU via ceil(sqrt(n)).
  7. Never “tune” by changing pack content for performance without a GoldenHash re-baseline — pack edits change terrain.

Measurement checklist

Record for each experiment: pack identity, seed, radius, serial/sync flags, JVM version/flags, heap, CPU, settings.json performance/pregen excerpts, chunks/second, duration, failed chunks, peak heap, and GoldenHash combined value. Reject optimizations that change hashes unless the behavior change is intentional and documented. Larger release-style baselines (5k10k chunks, JProfiler) are tracked in 87 - Maintainer - Release Readiness.md.

Offline tools

Tool Command Use
Generation probe ./gradlew :probe:genProbe -PprobePack=… Headless engine generate; not a throughput benchmark
Classload probe ./gradlew :probe:run Purity/classload gate
SIMD microbench tools/simd-bench/./run.sh Kernel-only scalar vs vector timing

Smoke procedures that combine pregen and GoldenHash: 31 - Operator Runbooks & Smoke Tests.md.