apply_jvm wrote instance.cfg and never restored it, so B5-B12a in run 1 ran on B4's last set (Shenandoah, 6 GB). Within-block verdicts hold (same JVM on both sides); B7's no-shader baseline is re-run in run 2. Also: B14 spawn-count automation (b14/: fresh seeded world per run, offline-located biome sites, datapack entity counts, journaled config variants) and RESULTS-proxy.md with run-1 verdicts.
B14: spawn-tuning measurement
b14.py automates SPAWN-TUNING.md §B14. It compares the upstream spawn defaults with the
shipped partial files (d80f85b, 8e8483d: alexsmobs-common.toml, fowlplay.json5,
crittersandcompanions-common.json5). Each comparison stands still for 10 minutes at a
river, a jungle and a warm ocean, and counts entities within 128 blocks.
It reuses ../bench.py as a module: launch, kill_client, LogTail, monitor, the
Journal / restore_pending crash-safe restore, apply_pins, apply_dh, and
zip_world_root. It needs nothing beyond the Python 3 standard library.
Loop
cd analysis/client-perf/harness
python3 b14/b14.py run --config defaults --dry-run # world, config plan, datapack
python3 b14/b14.py run --config defaults # ~32 min, all three biomes
python3 b14/b14.py run --config shipped
python3 b14/b14.py summary # SPAWN-TUNING §B14 verdict
--biome river,jungle,warm_ocean(defaultall) runs the sites in that order in one launch.--minutes 10(default) sets the stay at each site.- Repeating runs (for example two of each config, interleaved defaults → shipped → defaults → shipped) gives medians. The summary takes the median across runs.
- Results go to
~/onion-bench/results/b14.jsonl. Each count line is ab14_countrow, and each launch is ab14_sessionrow (outcome, config check, git/mods hash, sites, archived log atresults/logs/session-<sid>.log). b14.py restore(orbench.py restore, which uses the same journal) undoes a hard-killed run.b14.py parse LOGprints the count rows found in any archived log.
The script refuses to start in these cases:
- a restore journal is pending;
- a bench client is running;
- any
matrix.py run,bench.py sessionor otherb14.py runprocess exists. It shares the OnionBench instance with the matrix, so never run it while the matrix runs.
Design
Throwaway world saves/onionspawn, one per run
- It contains only the bench world's
level.dat(seedonionbench, gamerules, datapack list), theonion-benchdatapack (it has no load or tick tags) andserverconfig/. - It has no
region/,entities/ordata/(no forceloads, no DH database). Every chunk around a site is therefore generated during the run, under the config being measured. That covers both kinds of spawning: the initial creatures placed at world generation and natural spawning. - The seed is the same, so the terrain is identical between runs. The world is journaled
as a
treeentry and deleted on restore. The bench worldsaves/onionbenchis never touched.
Sites are pre-located offline (b14.py locate)
/locate biome can't be used from a datapack. Functions run with suppressed output, and
execute store only captures the distance, not the coordinates.
So locate parses the overworld region files in bench-world-v1.zip with a small NBT
reader (nbt.py):
- It reads each chunk's biome palette at the surface, using the
MOTION_BLOCKING_NO_LEAVESheightmap in full chunks andWORLD_SURFACE_WGin proto chunks. - For each target biome it picks the chunk whose 5×5 neighbourhood has the largest share of that biome.
- Sites must be at least 192 blocks from the world spawn and the saved player position (spawn chunks and the first-load area stay outside the 128-block count sphere), and at least 320 blocks from each other (the count spheres don't overlap).
Biomes depend only on the seed, so the coordinates are valid for any world with this seed
and mod set. They are committed in sites.json (from zip sha256
144caf5f…, seed −306676217):
| biome | x y z | biome at site | share in 5×5 chunks |
|---|---|---|---|
| river | 904 63 88 | minecraft:river | 0.37 |
| jungle | −8 107 −201 | minecraft:jungle | 0.52 |
| warm_ocean | −200 63 56 | minecraft:warm_ocean | 0.75 |
Every count line carries biome_ok, an in-game execute if biome check at the player's
feet (minecraft:river, #minecraft:is_jungle, minecraft:warm_ocean). If the
regenerated terrain doesn't match the offline lookup, the summary marks that biome
invalid instead of silently measuring the wrong place.
Config variants (journaled, bench instance only)
defaultsdeletes the three files. Each mod regenerates its upstream defaults on load (the same as "these three config files removed" in SPAWN-TUNING). They aren't inconfig/defaultoptions/extra/, so Default Options can't put them back.shippedwritesgit show <rev>:config/<file>(defaultHEAD), meaning the committed partials, not the working tree's boot re-saves.- After the run, and before the restore, the files the mods re-saved are read back and
checked against the expected values. A mismatch fails the run (
config_check.ok=false), and the summary ignores that run. The expected upstream defaults were verified from the jars:- Alex's Mobs: the
# Default:comments in its re-saved TOML: gazelle 40, capuchin 28, elephant 30, straddler 70, rocky roller 60, underminer 50, blobfish 30, mudskipper 28, caiman 29. - Fowl Play:
FPConfig.<init>bytecode: duck 4/max 6, goose 4/4, gull 5/8, sparrow 20/6. - Critters and Companions:
CACCommonConfig$SpawningConfig.<init>: sea bunny warm ocean 32 (max 4), other oceans 16; leaf insect jungle 14, forest 6; dragonfly lush 10.
- Alex's Mobs: the
Datapack (saves/onionspawn/datapacks/b14-autoplan, pack_format 48)
- Start-up: a load tag polls once a second until a player exists. Then it pins the
rules that matter for spawning:
gamemode creative(it counts for spawning and despawning, where spectators don't, and the player can't die);doMobSpawning true;- the daylight, weather, patrol, trader, insomnia and warden rules;
- time 6000 and clear weather.
- Per site:
- Teleport above the site.
- 5 s later: clear a 3×3×3 pocket, put a barrier at y−1 (a platform over water), and teleport onto it.
- Count at t=0 (+10 s), then every 60 s up to t=10. Each count re-asserts the barrier and the teleport, so the player never drifts.
- Each count runs
execute store result score #<alias> b14 if entity @e[type=<id>,distance=..128]as the player, for the 22 tuned species and 10 vanilla spot-check species. It also stores:total=@e[type=!player,distance=..128], as SPAWN-TUNING defines it;nonitem, which also excludes items and XP orbs;tuned, the sum of the tuned species.
- Output: a
tellrawprints one line, which the client logs as[System] [CHAT]:B14 <sid> <biome> t=<min> biome_ok=1 total=N nonitem=N tuned=N alexsmobs:gazelle=N .... - Errors:
Failed to load function b14:in the log (an unknown entity id makes the whole function unloadable) aborts the run asdatapack_error.
Entity ids
All are checked against the jars in the bench instance. Each has an entity.<mod>.<name>
lang key, and is either in the mod's registry class strings (CACEntities) or has a
loot_table/entities/<name>.json.
- Alex's Mobs (
alexsmobs-1.22.17):gazelle,capuchin_monkey,elephant,straddler,rocky_roller,underminer,blobfish,mudskipper,caiman. - Fowl Play (
fowlplay-1.2.3):duck,goose,gull,sparrow. - Critters and Companions (
crittersandcompanions 2.7.0):leaf_insect,sea_bunny,dragonfly,ladybug,stag_beetle,roly_poly,snail,stick_bug,weevil.
Verdict (summary, SPAWN-TUNING §B14)
- Per biome, using the final count (t = minutes):
- keep if the median
totaldrops under shipped and no tuned species that appeared at any minute under defaults is absent under shipped; - back off (listing the species) if one disappears;
- no drop otherwise.
- keep if the median
- Warnings:
rare_warnflags species whose shipped maximum is under 25 % of the defaults maximum (when defaults saw at least 4).vanilla_goneflags cows or sheep that vanished. - Overall:
keeponly if all three biomes keep. - Excluded runs: runs with a failed config check or a non-ok outcome are ignored. A
biome with
biome_ok != 1isinvalid.
Manual prep and limits
- Prep: nothing beyond what's committed.
sites.jsonis already generated. Re-runb14.py locate --out b14/sites.jsononly if the seed, the source zip or the biome-affecting mods (Terralith, Tectonic) change. - Thin biome coverage: the source world has only about 2300 chunks with final biomes, so the river and jungle patches are small (37 % and 52 % of the 5×5 neighbourhood). The 128-block count sphere also covers neighbouring biomes. This is the same for both configs, but it lowers the absolute counts.
- Better sites (optional): on
~/onion-bench/server-bench(seedonionbench), run/locate biome minecraft:river(and jungle, warm_ocean), check the share around each result, and put the coordinates intosites.jsonby hand. Theyvalue is the first free block above the surface or the water. - Jungle site from a proto chunk: its
yis the height before trees are placed. The 3×3×3 air pocket keeps a tree from burying the player, andbiome_okstill guards the biome. - Hostile mobs in
total: difficulty stays as inlevel.dat(normal), so hostiles from caves within 128 blocks count towardtotal.tunedandnonitemare recorded separately for reading the result. - Machine: this is proxy-machine data (singleplayer, simulation distance 8 pinned). Spawning is server logic, so the GPU doesn't matter, but CPU load does affect chunk generation speed.