3.3 KiB
Simulation scaling baseline 02
This is the reviewed comparison after introducing one reusable per-tick
SimulationPopulationView. The view indexes all, living, and starving NPCs by
stable ID, is refreshed as each NPC advances, and is shared by relationship and
action-selection queries. It is transient derived state and is not serialized.
The machine-readable samples are in
simulation_scaling_baseline_02.json.
The workload, seed, host, exclusions, warmup, and three-sample median contract
match baseline 01.
Results
| Case | NPCs | Seeded history | Median us/tick | Ticks/s | Simulated realtime | Arrival share | End JSON |
|---|---|---|---|---|---|---|---|
| Population 6 | 6 | 0 | 63.85 | 15,662.93 | 18,795.5x | 4.5% | 0.06 MiB |
| Population 60 | 60 | 0 | 662.62 | 1,509.17 | 1,811.0x | 5.7% | 0.56 MiB |
| Population 600 | 600 | 0 | 11,654.10 | 85.81 | 103.0x | 18.0% | 5.67 MiB |
| History 600 | 60 | 600 | 722.60 | 1,383.90 | 1,660.7x | 5.2% | 0.71 MiB |
| History 6,000 | 60 | 6,000 | 1,430.65 | 698.98 | 838.8x | 2.6% | 2.04 MiB |
All samples within each case were deterministic. More importantly, every final checksum exactly matches the corresponding baseline-01 checksum, so the optimization preserves selection, interleaved NPC updates, event growth, and serialized continuation state.
Comparison
| Case | Baseline 01 us/tick | Baseline 02 us/tick | Change |
|---|---|---|---|
| Population 6 | 55.74 | 63.85 | 14.6% slower |
| Population 60 | 621.87 | 662.62 | 6.6% slower |
| Population 600 | 15,187.74 | 11,654.10 | 23.3% faster |
| History 600 | 677.12 | 722.60 | 6.7% slower |
| History 6,000 | 1,421.19 | 1,430.65 | 0.7% slower |
The shared dictionaries add a small fixed per-tick cost, visible in tiny fixtures and normal local timing noise. At the measured population knee they remove repeated all-NPC lookup construction and improve the 600-NPC case from 65.84 to 85.81 ticks per second. The local 50-ticks-per-second reference target remains comfortably met without introducing simulation LOD.
Decision and next measurement
Keep the population view. It has a real relationship/action consumer, improves the measured pressure point, and preserves exact state. Do not add batching or active/abstract NPC modes merely to improve this data-only number.
That next bounded scale slice is now complete. The measured workload justified
a resource-specific horizontal grid owned by ActiveWorldAdapter; exact
expanding queries preserve every linear selected-target checksum and reduce the
1,800-anchor case from 6,448.00 to 46.94 microseconds. See
Loaded Resource Discovery 01.
Terrain3D-instanced visual trees and grass are not automatically authoritative
resources. Intentional harvest anchors must continue to bind simulation-owned
ResourceStateRecord data by stable ID; large decorative populations can stay
presentation-only until a gameplay rule needs them.
Capture command
/Applications/Godot.app/Contents/MacOS/Godot \
--headless --path "$PWD" \
--script res://tools/benchmark_simulation_scaling.gd -- \
--host-label=Apple_M1_Max_64_GB \
--output=res://docs/benchmarks/simulation_scaling_baseline_02.json