Skip to content

perf(producer): phase-level render instrumentation#430

Closed
jrusso1020 wants to merge 1 commit intomainfrom
perf/producer-phase-instrumentation
Closed

perf(producer): phase-level render instrumentation#430
jrusso1020 wants to merge 1 commit intomainfrom
perf/producer-phase-instrumentation

Conversation

@jrusso1020
Copy link
Copy Markdown
Collaborator

What

Adds phase-level observability to the render pipeline — no behavior change, all additive fields.

  • ExtractionResult.phaseBreakdown: splits the existing durationMs into resolveMs, probeMs, hdrPreflightMs, vfrPreflightMs, extractMs, plus HDR/VFR preflight counts.
  • InjectorCacheStats: optional out-param on createVideoFrameInjector that counts LRU hits, misses, in-flight-coalesced reads, and peak entries.
  • RenderPerfSummary gets videoExtractBreakdown, injectorStats, and tmpPeakBytes.

Why

This is PR 1 of a 5-PR stack distilled from `hyperframes-notes/producer-render-architecture-review-2026-04-21.md`. The doc flags specific bottlenecks (HDR/VFR preflight cost, injector disk reads, /tmp pressure) but explicitly says every claim is a hypothesis until profiled on real compositions. Downstream PRs — segment-scoped HDR preflight, extraction cache, WebP unified format, gated hwaccel — need these numbers to validate they actually helped.

Concretely, after this lands the validation plan from the doc (§ Validation plan) becomes runnable: the three reference compositions (short SDR, medium alpha-mix, long 4K) each emit a structured `perfSummary` with per-phase timings that can be diffed across PRs.

How

  • Extractor (`videoFrameExtractor.ts`): adds a `phaseBreakdown` object populated in-place as each phase runs. HDR and VFR re-encodes are wrapped in try/finally so failed attempts still account for their wall-time. Phase 3 is timed as a single wall-clock span since it's already parallel across inputs.
  • Injector (`videoFrameInjector.ts`): the frame-dataURI LRU accepts an optional `InjectorCacheStats` that it mutates in-place. When absent, behavior is byte-for-byte identical to before (single sentinel check at each counter site). Exported `createEmptyInjectorCacheStats` and a test-only `__createFrameDataUriCacheForTests` so the LRU semantics can be verified without a running Chrome.
  • Orchestrator (`renderOrchestrator.ts`): creates one shared `injectorCacheStats` and threads it into the three sequential-capture injector constructions. Parallel-worker injectors (built via factory) run in separate worker processes and can't mutate the host stats object, so those paths leave `injectorStats` undefined. Samples `workDir` size just before cleanup as a lower bound on peak disk usage (by then the extracted-frame dir, captured-frame dir, and intermediate audio/video artifacts all coexist).

What's deliberately not in this PR

  • Browser launch timing (`browserLaunchMs`) and first-frame latency — would require threading timers through `executeParallelCapture`/worker boundaries. The existing `browserProbeMs` + `captureMs` stages cover this at lower resolution and are enough to sequence the downstream PRs.
  • Mid-render `/tmp` watermark polling — end-of-render sample is close enough to peak for the validation plan's purposes.

Test plan

  • Unit tests added/updated — 5 new `InjectorCacheStats` tests (hit/miss, in-flight coalescing, peakEntries, eviction, absent-stats regression) and a `phaseBreakdown` assertion on the existing VFR fixture that verifies the VFR preflight is counted and timed.
  • Full engine suite: 318 tests pass (was 312).
  • Typecheck clean in engine + producer.
  • Lint + format clean on all changed files.
  • Documentation updated — not applicable (internal instrumentation).

Follow-ups (PRs 2–5 in the stack)

Each of these will reference the numbers this PR emits to validate the improvement:

  1. Segment-scope `convertSdrToHdr` — mirror of fix(engine): auto-normalize VFR video inputs to CFR before frame extraction #360's VFR fix; watch `videoExtractBreakdown.hdrPreflightMs` drop.
  2. Extraction cache keyed by `(srcHash, windowStart, windowEnd, fps, hasAlpha)` — `extractMs` goes to ~0 on cache hit.
  3. WebP as the single extraction format — unifies the jpg/png split; `tmpPeakBytes` decreases on alpha compositions.
  4. Hardware-accelerated SDR decode, gated on `!hasAlpha` and segment-length floor — `extractMs` decreases on eligible inputs.

…jector

Adds observability hooks the architecture review at
hyperframes-notes/producer-render-architecture-review-2026-04-21.md flags
as a prerequisite: we need phase-level numbers from real compositions
before committing to any of the Tier A/B/C work, so the perf summary can
be validated against the doc's hypotheses (HDR preflight cost, VFR
preflight cost, injector LRU behavior, /tmp pressure).

No behavior change. All added fields are optional/additive.

- videoFrameExtractor: new ExtractionResult.phaseBreakdown splits the
  pre-existing durationMs into resolveMs, probeMs, hdrPreflightMs,
  vfrPreflightMs, extractMs plus HDR/VFR preflight counts. Uses
  try/finally around the HDR and VFR re-encodes so aborted attempts
  still get accounted for.

- videoFrameInjector: optional InjectorCacheStats out-param on the
  frame-dataURI LRU. Counts hits, misses, inFlight-coalesced concurrent
  reads, and peak entries. Callers that don't pass stats pay no cost.

- renderOrchestrator: threads the new stats through sequential-capture
  injector callsites (parallel workers live in separate processes and
  can't share a mutable stats object). Adds videoExtractBreakdown,
  injectorStats, and tmpPeakBytes to RenderPerfSummary. Samples workDir
  size just before cleanup as a lower bound on peak /tmp usage.

Tests: 5 new LRU-stats tests and a phaseBreakdown assertion on the
existing VFR fixture. 318 engine tests pass (was 312).

Sets up the rest of the proposed PR stack (segment-scoped HDR
preflight, extraction cache, WebP unified format, gated hwaccel) which
will each be validated against these metrics.
@jrusso1020
Copy link
Copy Markdown
Collaborator Author

Closed: rebuilt as #444 off current main (post Vance's HDR work #371/#373/#375). Scope narrowed to extractor-side instrumentation + tmpPeakBytes; the injector-stats plumbing that conflicted with upstream #371's lifecycle refactor was dropped. See hyperframes-notes/perf-stack-rebuild-plan-2026-04-23.md

@jrusso1020 jrusso1020 closed this Apr 23, 2026
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