Skip to content

Examples & benchmarks ​

Playable scenes in examples/ and the headless benchmark harness in tests/bench/ are integration references for the ECS.

Running ​

sh
godot --headless --path . res://examples/SpriteSwarm2D.tscn
godot --headless --path . res://examples/VerifyDemos.tscn
godot --headless --path . res://tests/bench/BenchRunner.tscn -- --bench=all --n=50000 --frames=600
godot --headless --path . res://tests/unit/UnitRunner.tscn

The benchmark runner warms up (120 frames by default) and records avg/p50/p95/min/max, FPS and per-frame GC delta to CSV under user://bench/.

Benchmark status: read the numbers correctly ​

The currently published measurements are mostly Debug headless with the dummy renderer. Release measurements are limited (for example, selected physics measurements via configuration/DLL swap). There is not yet a full Release export with a visible scene behind every render benchmark.

Consequently, dummy-driver render timings measure managed ECS/upload preparation, not real GPU/driver cost. They must not be presented as proof of final on-screen FPS or draw-call performance.

The old rule "always measure in Release" has been replaced by this distinction: use Release for production gates whenever a valid Release run exists, and label Debug/headless/dummy-driver measurements explicitly as preliminary engineering signals.

Current benchmark filters ​

Use the filters exposed by the current runner rather than the older combined names. Current suites include:

  • integrate_scalar, integrate_simd, integrate_parallel
  • jobs_scalar, jobs_pooled, jobs_dedicated
  • render3d_sync, render3d_upload, render3d_fallback
  • render2d_sync
  • physics_ecs, physics_arena
  • serialize_save, serialize_load

Consult docs/BENCHMARKS.md and docs/BENCHMARKS_RESULTS.md in the plugin repository for the exact command lines, environment and result tables.

Published gates ​

The gates below are engineering targets, not claims that every target has been met.

GateTargetCurrent status
Integrate 100k< 2 ms, parallel ≥ 4× scalarDebug signal meets the target; Release confirmation is still required.
50k 3D bulk render> 60 FPS, draw calls = groups, sync < 1 msNot validated as a real GPU/driver Release gate. Dummy-driver numbers are logic-only and can invert node-vs-bulk ratios.
50k 2D bulk render> 60 FPS, one MultiMesh per textureCurrent code performs one bulk MultimeshSetBuffer upload per group; final real-renderer gate still needs validation.
10k node-vs-bulk≥ 10× slower node pathThe 10k node control is excluded from the all headless queue because it is intentionally expensive; do not call this a measured 10× gate.
Physics 10kbroad+narrow < 1.5 msNot met. Current Release signal is about 11.7 ms in the dense stress case and 7.4–8.6 ms in the arena configuration. Deterministic parallelism is a major improvement, but the candidate-pair workload remains the bottleneck.
Serialize 100ksave/load < 200 ms, stable replay hashPublished Debug signal is comfortably under the time target; replay, round-trip and corrupt-stream tests pass. Release confirmation is still desirable.

The physics optimization direction is pair-count reduction rather than blindly optimizing the per-pair kernel: relative-velocity culling was tried and reverted, while the SIMD sphere kernel showed no end-to-end improvement because the narrowphase is memory-bound.

Demo coverage ​

The demos cover bulk 2D/3D rendering, culling/LOD, hybrid ECS/Godot physics, arcade physics, snapshot round-trips and headless verification. VerifyDemos should be treated as an integration smoke test, not as a substitute for real Release/GPU benchmarks.

GodotECS docs — version 0.2.0. All rights reserved until a license is added.