Graphics & Engine•Study date: July 31, 2026•Printable brief ↗Measurement Audit

Published by Sean Carr

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.

Executive Brief

At a Glance

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 TableScroll table →
Telemetry MetricMeasured ValueContext & Observability
Maintenance vs cull, live scene47.9xLive 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 items64.4x100,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 boxes0.104 msCull 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% moving44.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 oracle0.04%Correctness: false negatives vs oracle 0; false positives 1 (0.04%); hot-path allocations 0 over 500 frames.
Bare visit loop, no memo0.1032 msA 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 moving3082.4516 ms100,000 items, all moving, palm-class meshes: 3082.4516 ms for one frame.
Live memo hit rate97.8%Live memo hit rate on the shipped executable: at least 97.8% (derived bound, not a direct count).

Executive Summary & Core Finding

We published an internal verification annex showing the CPU frustum culler handles 100,000 bounding boxes in 0.104 ms. The same day, a residency stress test showed the per-frame bounds-maintenance pass that must run alongside the cull costs 47.9x the cull on the live scene and 64.4x at 100,000 objects. Every number was correctly measured; the error was that the timer boundary was not part of the record.

Method

1

Data collected Jul 31, 2026; written up October 2026.

2

All measurements on July 31, 2026, on a development workstation (AMD Ryzen 7 9800X3D, 96 MB L3, DDR5).

3

The cull kernel was timed with median-of-500 passes under a cold-cache protocol (a 128 MB write sweep before each pass, outside the timed region), checked against an independent brute-force oracle.

4

The system-scope figures came from a separate stress harness reporting median-of-200 frames (median-of-100 or -60 for the heaviest variants), with maintenance timed on a transcription of the shipped resolver rather than the shipped backend.

5

Results were not reproduced on the low-end validation PC.

Empirical Telemetry

What We Measured

Cull kernel timing versus per-frame system cost

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).

Interpretation & Working Hypotheses

What We Think It Suggests

  • 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.

Detailed Analysis & Field Observations

We published an internal verification annex showing the CPU frustum culler handles 100,000 bounding boxes in 0.104 ms. The same day, a residency stress test showed the per-frame bounds-maintenance pass that must run alongside the cull costs 47.9x the cull on the live scene and 64.4x at 100,000 objects. Every number was correctly measured; the error was that the timer boundary was not part of the record.

Data collected Jul 31, 2026; written up October 2026.