Skip to content

perf(editor): decode imported music with bounded parallelism - #3258

Merged
richiemcilroy merged 2 commits into
CapSoftware:mainfrom
vedanth-jadhav:perf/imported-music-playback-baseline
Oct 25, 2026
Merged

richiemcilroy merged 2 commits into
CapSoftware:mainfrom
vedanth-jadhav:perf/imported-music-playback-baseline

Conversation

@vedanth-jadhav

@vedanth-jadhav vedanth-jadhav commented Oct 25, 2026 •

Copy link
Copy Markdown

Starting playback after adding multiple uncached music files currently decodes their requested source ranges serially. This overlaps independent decodes with at most two threads in load_music_tracks, used by editor preload/playback and uncached export. Zero/one miss stays serial; cached Arcs are reused. A scoped worker owns its per-file decoder/resampler and joins before return; thread creation failure falls back to serial decoding.

Measured on Linux, 2 CPU affinity slots, FFmpeg 7.1.5, Rust 1.88, root shipping release profile, headless audio and software Vulkan (Lavapipe, two threads). Synthetic long-form fixture: two independent one-hour 48 kHz stereo AAC sources, with 1200-second requested ranges, and a 320×180 1 fps H.264 display source. Five independent processes per version and track count (20 total), alternating order, no overlapping builds, warm filesystem/shader caches. Baseline source is main 85057d0; the earlier saved baseline has identical relevant editor/audio sources.

Median workflow measurement Serial Bounded
Two-track delayed-cold playback start return 1.291 s 0.691 s
Two-track delayed-cold first nonzero audio 1.322 s 0.721 s (45.45% lower)
Two-track delayed-cold first frame 1.312 s 0.715 s
Single-track delayed-cold first audio control 0.680 s 0.658 s
Single-track warm first audio 30.18 ms 35.72 ms
Two-track warm first audio 24.82 ms 30.41 ms
Two-track whole-process peak RSS 1,150,052 KiB 1,158,276 KiB (+0.72%)

Timers begin immediately before the production playback call and include cache-miss decoding and output startup. The delayed-cold phase opens without music, waits 250 ms, adds music, waits 250 ms, then starts playback; open and these waits are excluded from that timer. Warm playback seeks to frame 900 (60 s). All observed first frames matched requested frame 0/900. The benchmark reports open separately; it does not claim a seek-only or export improvement. Warm first frames regressed by 1.43/2.87 ms (one/two tracks). Single-track whole-process peak RSS was 718,456 → 676,900 KiB. These process-level values include renderer/audio allocations, not decoder-only memory. Small controls vary between runs; no causal or statistically significant control gain is claimed. No physical GPU, physical audio device, native GPUI UI, or macOS performance claim.

Correctness: independent serial per-file reference versus parallel three-file mixing compares exact output sample bits with trims/fades. Tests cover warm Arc identity, partial caches with one/two misses, corrupt plus valid sources, failed range replacement and reuse of retained entries. Existing range/cache coverage remains. Normal decoder errors still warn and skip each failed file. Cancellation retains the existing noncancellable spawn_blocking behavior. Unexpected Rust decoder panics still unwind the request; successful inserts from that failed call can now be lost because inserts follow the joined batch, so retry may decode them again. Previously retained cache entries remain intact. OS thread creation fallback was inspected, not fault-injected. Parallelism is bounded per invocation, not globally.

Validation on the submitted production/test sources: cargo fmt --all, cargo check -j2 -p cap-editor --locked, cargo test -j2 -p cap-editor --lib --locked (216 passed, 3 ignored), cargo clippy -j2 -p cap-editor --all-targets --no-deps --locked -- -D warnings, and git diff --check. The only change after measurement was expanded differential test coverage. No raw measurements or decoder probe are included.

Reproduce with the included imported-music-playback-benchmark example on a disposable fixture directory (it writes project metadata). Generate the equivalent long-form synthetic workload with FFmpeg:

mkdir -p /tmp/cap-music-playback
ffmpeg -v error -f lavfi -i color=c=blue:s=320x180:r=1 -t 3600 -c:v libx264 -threads 2 -preset ultrafast -pix_fmt yuv420p /tmp/cap-music-playback/display.mp4
ffmpeg -v error -f lavfi -i sine=frequency=440:sample_rate=48000:duration=3600 -ac 2 -c:a aac -threads 2 -b:a 128k /tmp/cap-music-playback/music-a.m4a
ffmpeg -v error -f lavfi -i sine=frequency=660:sample_rate=48000:duration=3600 -ac 2 -c:a aac -threads 2 -b:a 128k /tmp/cap-music-playback/music-b.m4a
cargo build -j2 -p cap-editor --release --example imported-music-playback-benchmark --locked
CAP_RENDER_FORCE_SOFTWARE_ADAPTER=1 LP_NUM_THREADS=2 taskset -c 0,1 target/release/examples/imported-music-playback-benchmark /tmp/cap-music-playback 2 delayed-cold

The documented generation commands were also run from scratch and the saved candidate completed both phases with exact frame 0/900 provenance. This separate equivalent-fixture smoke is not another paired performance comparison (first audio 0.991 s cold, 30.67 ms warm).

Use the repository native FFmpeg setup and a valid Vulkan ICD/XDG runtime on headless Linux. Repeat with track count 1 for the control and alternate separately saved baseline/candidate binaries.

Current main and active work checked before publication. #2308 also touches this loader to add video-source handling, but retains serial playback decoding; its bounded waveform workers are a separate path. This change may require textual conflict resolution with that feature. #2848/#2847/#2845 cover music drag/drop, lane naming and audio scrubbing; #3254 changes Studio Sound short-cut processing. None supplies this cache-miss concurrency.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no actionable issues were found.

Summary

load_music_tracks now decodes cache misses with at most two concurrent decodes per call.

  • Imported music files decode in parallel when playback needs several cache misses.

Acknowledged by vedanth-jadhav: cancellation remains noncancellable during blocking work; the bound is per call, not global; a decoder panic can discard successful inserts from that call and cause another decode on retry. Thread creation fallback was inspected rather than fault-injected. Performance claims are limited to the described headless Linux setup.

Review checks were source-based; no builds, tests, or benchmarks were run during this review.

Reviews (1) · Last reviewed commit: "perf(editor): bound parallel imported mu..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Someone is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

@richiemcilroy
richiemcilroy merged commit cb3d339 into CapSoftware:main Oct 25, 2026
45 of 47 checks passed
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.

2 participants