perf(producer): cache transfer-converted hdr image buffers per render job#384
perf(producer): cache transfer-converted hdr image buffers per render job#384vanceingalls wants to merge 1 commit intovance/logger-level-gatingfrom
Conversation
38cae8b to
723c98b
Compare
98daa12 to
21c0314
Compare
723c98b to
2f5ecdc
Compare
21c0314 to
5fe390c
Compare
2f5ecdc to
57abd3a
Compare
5fe390c to
42ab080
Compare
57abd3a to
c0d1d4e
Compare
42ab080 to
6d73ff8
Compare
092e9ba to
fdbbfd2
Compare
2365f04 to
442f167
Compare
fdbbfd2 to
3f90688
Compare
442f167 to
a746bb2
Compare
|
Thanks for the careful review @jrusso1020 — confirming each point you raised landed in the merged commit: 1. Per-render-job scoping (no cross-job collisions). The cache is constructed once per render job inside the orchestrator and goes out of scope on job exit: // Per-job LRU cache for transfer-converted HDR image buffers. Static HDR
// images that need PQ↔HLG conversion are converted exactly once per
// (imageId, targetTransfer) and then reused for every subsequent frame
// instead of paying a fresh `Buffer.from` + `convertTransfer` on every
// composite. The cache is local to this render job so concurrent renders
// do not share state.
const hdrImageTransferCache = createHdrImageTransferCache();
const hdrCompositeCtx: HdrCompositeContext = {
...
hdrImageTransferCache,
...
};The 2. Same-transfer zero-copy. When 3. Source-buffer immutability.
The full 15-test suite also covers hit/miss, distinct keys per On metrics emission for hit/miss/eviction (non-blocking observation): Agreed it's worth having when we wire up benchmark observability more broadly — leaving as a future follow-up alongside the existing |
|
Hi, createHdrImageTransferCache defaults to maxEntries=16, which can retain very large rgb48le buffers at higher resolutions (e.g., 4K ~53MB per entry → ~850MB worst-case), increasing peak RSS and OOM risk unless callers tune maxEntries. Severity: remediation recommended | Category: performance How to fix: Make cache bound configurable Agent prompt to fix - you can give this to your LLM of choice:
Found by Qodo code review. FYI, Qodo is free for open-source. |
3f90688 to
bd86b42
Compare
a746bb2 to
15eed9b
Compare
bd86b42 to
a549e46
Compare
08c2296 to
8b63af3
Compare
a549e46 to
8d9641b
Compare
8b63af3 to
69af136
Compare
3fcaa60 to
e675bd9
Compare
69af136 to
c72eb7f
Compare
e675bd9 to
f73328c
Compare
54c8e1f to
b71cf6f
Compare
55a41a8 to
349f0f6
Compare
b71cf6f to
3c4754f
Compare
349f0f6 to
cd65ab0
Compare
e49a01f to
a801330
Compare
5409b1a to
c6a8280
Compare
a801330 to
2af81de
Compare
c6a8280 to
2ce89a5
Compare
… job Static HDR image layers whose source transfer differs from the render's effective transfer (PQ↔HLG) were re-running `Buffer.from` + `convertTransfer` on every composited frame, even though the converted buffer is identical for the entire job. Added `HdrImageTransferCache` — a per-render-job bounded LRU keyed by `(imageId, targetTransfer)` that converts once and reuses on every subsequent frame, while leaving same-transfer requests as a zero-copy passthrough. Wired into `renderOrchestrator.ts` via `HdrCompositeContext.hdrImageTransferCache`, instantiated once per job and consumed by `blitHdrImageLayer` on both the main composite path and the transition path. Covered by `hdrImageTransferCache.test.ts` (hit/miss, distinct keys per image and per target transfer, LRU eviction + promotion, `maxEntries=0` passthrough, source-buffer immutability for cached entries, invalid options). Made-with: Cursor
2af81de to
a3d4984
Compare

Summary
Add
HdrImageTransferCache— a per-render-job bounded LRU keyed by(imageId, targetTransfer)— so static HDR image layers whose source transfer differs from the render's effective transfer (PQ↔HLG) are converted once per job instead of once per composited frame.Why
Chunk 8Bofplans/hdr-followups.md.blitHdrImageLayerwas runningBuffer.from+convertTransferon every composited frame, even though the converted buffer is identical for the entire job. For a multi-second comp at 30 fps this is hundreds of redundant transfer conversions on the hot path.What changed
packages/producer/src/services/hdrImageTransferCache.ts— bounded LRU keyed by(imageId, targetTransfer)that owns the converted HDR rgb48 buffer for static HDR image layers:Buffer.from+convertTransferon first miss, reuse the cached copy on every subsequent frame.renderOrchestrator.tsviaHdrCompositeContext.hdrImageTransferCache, instantiated once per render job, and consumed byblitHdrImageLayeron both the main composite path and the transition path.Test plan
packages/producer/src/services/hdrImageTransferCache.test.ts— 12 tests:maxEntries=0passthroughhdr-regressionfixture (which has cross-transfer image layers) the cache hits 100% after the first frame; for HDR fixtures without cross-transfer images the same-transfer passthrough is a no-op.Stack
Chunk 8B of
plans/hdr-followups.md. Sits on top of Chunk 8C (logger gating) and Chunk 8A (benchmark harness) so the win is measurable.