Our Culling Number Was Right and Still Misleading
A 0.104 ms frustum-cull figure timed the kernel only; the maintenance work that must run beside it was 48x to 64x larger.
Maintenance vs cull, live scene
47.9x
Live scene (2,388 items), static: maintenance 0.0863 ms vs cull 0.0018 ms; total 0.0882 ms. Maintenance-to-cull ratio 47.9x; total-to-cull 49.0x.
Maintenance vs cull, 100,000 items
64.4x
100,000 items: cull only 0.0824 ms; with the static maintenance path the engine actually runs, 5.3068 ms total (64.4x).
Cull kernel, 100,000 boxes
0.104 ms
Cull kernel, 100,000 boxes, cold cache: 0.3451 ms before a data-layout refactor to 0.104 ms after (about -69%), against a 0.50 ms budget line.
Live scene, 10% moving
44.0%
Live scene with 10% of objects moving (239 objects): 7.3314 ms total, 44.0% of a 16.67 ms frame.
Empirical Findings Table
Cull kernel timing versus per-frame system cost| Telemetry Metric | Measured Value | Context & Observability |
|---|---|---|
| Maintenance vs cull, live scene | 47.9x | Live scene (2,388 items), static: maintenance 0.0863 ms vs cull 0.0018 ms; total 0.0882 ms. Maintenance-to-cull ratio 47.9x; total-to-cull 49.0x. |
| Maintenance vs cull, 100,000 items | 64.4x | 100,000 items: cull only 0.0824 ms; with the static maintenance path the engine actually runs, 5.3068 ms total (64.4x). |
| Cull kernel, 100,000 boxes | 0.104 ms | Cull kernel, 100,000 boxes, cold cache: 0.3451 ms before a data-layout refactor to 0.104 ms after (about -69%), against a 0.50 ms budget line. |
| Live scene, 10% moving | 44.0% | Live scene with 10% of objects moving (239 objects): 7.3314 ms total, 44.0% of a 16.67 ms frame. |
| Hot-path working set | -56% | Hot-path working set: 5.436 MB to 2.384 MB (-56%). |
| Correctness vs oracle | 0.04% | Correctness: false negatives vs oracle 0; false positives 1 (0.04%); hot-path allocations 0 over 500 frames. |
| Bare visit loop, no memo | 0.1032 ms | A bare visit loop with no memo and a cheap early-out still cost 0.1032 ms, more than the 0.0824 ms cull it feeds. |
| 100,000 items, all moving | 3082.4516 ms | 100,000 items, all moving, palm-class meshes: 3082.4516 ms for one frame. |
| Live memo hit rate | 97.8% | Live memo hit rate on the shipped executable: at least 97.8% (derived bound, not a direct count). |
Engineering Action Directives
- A kernel benchmark and a per-frame system cost are different claims, and a complete measurement record (value, statistic, date, hardware, commit, run condition) can still mislead if it does not say where the timer starts and stops. We added scope, meaning what is inside and outside the timed region, as a required field.
- The data-layout refactor appears to have been a real win for the cull itself. The per-frame cost of visibility, though, was dominated by visiting every item to check whether its bounds were still valid, and that cost grows steeply once objects move.
Methodology Boundaries & Limits
- Single development-class machine with a very large L3 cache; the low-end validation fixture has not been measured, and the cold-cache penalty there is plausibly larger.
- The maintenance figures time a faithful transcription of the shipped resolver, not the shipped render backend, which is weaker evidence than the kernel figures.
- A later fix landed in the maintenance path after these measurements, so the system-scope numbers describe the code at that commit and are now stale.