Repository navigation
perf(studio-server): copy alpha cut-outs several pieces at a time - #6342
miguel-heygen wants to merge 1 commit into
Conversation
Edit accuracy: accurate 271 (base branch 271), smooth 149 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
dab2a59 to
f16eabf
Compare
There was a problem hiding this comment.
Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits · head f16eabf9
The piece cap applies to each copy, but two copies can run at once, so neither the third-of-RAM limit nor the free core holds. ↓ inline
Scope
Read proxyTranscoder.ts and the two new tests in full. Checked the abort path: a worker that starts a piece after stop.abort() hits signal.throwIfAborted() in spawnFfmpeg, and Promise.all waits for every worker, so no ffmpeg process is left behind. Checked that progress only goes up and that swapping variant === "vp8" for keepsAlpha changes nothing. I couldn't run the test file locally because the workspace packages weren't built. CI was still running at review time. No earlier reviews.
— Claude (Genesis)
f16eabf to
d5e785d
Compare
There was a problem hiding this comment.
Verdict: APPROVE — 1 resolved, 0 open, 0 new · f16eabf → d5e785d
Non-blocking: an alpha copy short enough to go in one pass (≤ 22.5 s) skips ALPHA_PIECE_GATE and still uses CORES threads. One such copy running next to a long one is one encode over the cap: on an 8 GB laptop, 3 × ~1.15 GB is about 43% of RAM. Taking a slot around the single-pass alpha encode would close this.
— Claude (Genesis)
What
Copying a long alpha cut-out to a browser-playable VP8 file now encodes several 15 s pieces at the same time, sharing the cores between them. How many: at most 4 pieces across ALL copies running together (one shared pool, not one per copy), one core always left free for the editor, and no more than one piece per 3 GB of RAM (each 4K piece holds about 1.2 GB). On a 4-core 30 GB box that is 3; an 8 GB laptop gets 2. The progress line counts the finished pieces plus every piece in flight. If one piece fails, the others are ended at once and that failure is the one reported. H.264 copies are unchanged: one piece at a time.
Why
libvpx scales badly across threads, so one 4-thread encode leaves cores idle and burns CPU on thread overhead. One 15 s piece of the 4K alpha clip: 4 threads used 106 s of CPU, 1 thread used 94 s. Four 1-thread encodes of 60 s of the clip took 95 s on both runs, against 186 s and 196 s for one piece at a time with 4 threads.
End to end
Generated 120 s 3840x2160 VP9-alpha clip,
check --prepare-media, 4-core Linux box shared with other jobs, cache cleared each run, sequential and this branch alternating (with the cap, 3 pieces at once):Faster in all three pairs, and the branch ran at the higher machine load each time. An earlier uncapped run (4 at once) gave 110/108/124 s against 160/130/130 s. The gain is smaller than the encode-only test because every piece also decodes its slice of the source.
Why the file is smaller (33 MB vs 41 MB)
Only
-threadschanged per piece, and that alone changes the bytes: the same 5 s of the clip is 5.30 MB at-threads 4and 3.09 MB at-threads 1with identical settings (crf 23). Quality does not drop with it (below).Quality against the serial path
First 40 s (1200 frames, covering the seams at 15 s and 30 s), both copies against the source scaled to the copy's size (2166x1218), PSNR over Y, U, V and alpha:
The two copies against each other: mean 49.8 dB, worst 36.9 dB, many frames bit-identical. Seams: the six frames around 15 s and around 30 s sit at 36.2 to 37.6 dB, the same as the rest of the clip, so there is no jump or dip at a piece boundary.
Memory and CPU
Measured per ffmpeg process on the 4K alpha clip: peak RSS 1.15 to 1.18 GB for a 1-thread piece and 1.17 GB for a 4-thread piece, so memory scales with the number of pieces at once (4 would be about 4.6 GB); that is why the cap divides total RAM by 3 GB. CPU per piece is lower with 1 thread (94 s vs 106 s).
Tests
Three new tests in
proxyTranscoder.test.ts: two long alpha copies started together never run more pieces than the cap (fails when each copy gets its own pool); pieces start side by side with the cores shared out and progress counts them together (fails with the pool forced to one worker), and a failing piece ends the pieces still running and reports its own error. All 57 in the file pass; lint and format clean.