Skip to content

Add per-phase render profiling and scene statistics - #118

Merged
doubleailes merged 1 commit into
mainfrom
Add-profile
Jul 27, 2026
Merged

Add per-phase render profiling and scene statistics#118
doubleailes merged 1 commit into
mainfrom
Add-profile

Conversation

@doubleailes

Copy link
Copy Markdown
Owner

What

Adds --stats: a per-phase profile and scene-statistics report, so it is
possible to see which part of a render cost the time and the memory
rather than inferring it by subtracting wall-clock numbers.

Structure follows Guerilla Render's "Profiling And
Statistics"

— a statistics block, then the profile by execution tree, then by
time
.

Phases separated: Parse USD stage (→ open stage, traverse prims, load
assets, commit acceleration structure), Render, Write output.

Example — the complete, unmodified Moana island

Render Statistics
  resolution                   640x360
  samples per pixel            1
  max path depth               32
  geometries                   3 129 464
  top-level BVH primitives     3 129 485
    triangles                  42
    instances                  3 129 443
  primitives in memory         113 247 993
    triangles                  56 825 650
    cubic curve spans          17 216 644
    instances                  39 205 699
  lights                       23
  peak memory (RSS)            119.77 GiB
Profile by execution tree
  Parse USD stage                      10:09.2   75.3%
    Open stage                          8.609s    1.1%
    Traverse prims                     09:30.0   70.5%
    Load assets                        20.385s    2.5%
    Commit acceleration structure      10.184s    1.3%
  Render                               03:19.4   24.7%
  Write output                          0.057s    0.0%
  total                                13:28.6

Parsing is 75% of the runtime against rendering's 25% — not obvious
before, and the kind of thing this exists to surface.

Design notes

  • Measuring is free, printing is gated. One Instant per phase,
    never per ray, so nothing touches the integrator's inner loop.
    Collection is always on; only the report is behind --stats.
  • Two primitive views, because for an instanced scene they answer
    different questions. top-level is what the root BVH traverses;
    primitives in memory descends into instances counting each distinct
    prototype once (deduplicated by Arc pointer), so it tracks memory.
    Without it the interesting counts stay hidden behind "N instances" — on
    samples/curves.usda the top-level view shows only instances 3.
  • Collection in core, presentation as a Display the host chooses to
    print
    , consistent with crust-core's UI-free rule. The report goes to
    stdout rather than through tracing, so the log level cannot swallow it
    and it is not interleaved with per-prim messages.

Testing

  • 99 crust-core + 45 crust-rt tests pass (new: phase totals skip nested
    phases, both profile views list every phase, percentages, zero-count
    omission, and a kernel test pinning that a prototype shared by four
    placements is counted once).
  • scripts/test_simd_matrix.sh -p crust-rt bit-exact across all four
    codegen configurations.
  • clippy clean on the new code.
  • Verified end to end on samples/curves.usda, an instanced
    curve-heavy probe scene, and the full island.

Not included

Per-ray counters (Guerilla's Trace/Occlusion/Shading categories).
Those need plumbing into the integrator hot path; a shared atomic
incremented per ray would contend badly across 48 threads. Feasible via
per-work-unit accumulation — the Rayon loop already returns per-unit
tuples — but it is a separate change and did not belong bundled here.

🤖 Generated with Claude Code

A single wall-clock number hides which part of a render actually cost
anything. This separates the phases -- parse USD stage (open, traverse,
load assets, commit acceleration structure), render, write output -- and
reports them the way Guerilla Render's "Profiling And Statistics" does:
a statistics block, then the profile by execution tree, then by time.

Two primitive views are reported because for an instanced scene they
answer different questions. The top-level view is what the root BVH
traverses; the unique view descends into instances and counts each
distinct prototype once, so it is what actually occupies memory. Without
it the interesting counts stay hidden behind "N instances".

Collection is one Instant per phase and never per ray, so nothing touches
the integrator's inner loop and measuring costs the same whether or not
the report is printed; only printing is gated, behind --stats.

On the complete Moana island this reports 113M primitives resident
(56.8M triangles, 17.2M cubic curve spans) at 119.77 GiB, with parsing
at 75.3% of runtime against rendering's 24.7%.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@doubleailes
doubleailes merged commit 46e2968 into main Jul 27, 2026
2 checks passed
@doubleailes
doubleailes deleted the Add-profile branch July 27, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant