Repository navigation
Conversation
libdav1d (FFmpeg's AV1 decoder, used for the AV1 clips of LeRobot v3 datasets) starts a thread pool sized to the host for every clip PyAV opens, because FFmpeg passes its automatic thread count (about one thread per CPU core). With DataLoader workers x ranks decoding concurrently, these pools oversubscribe the host and the GPUs wait for data. decode_video_frames now caps the libdav1d pool at 2 threads per clip; OPENWAM_VIDEO_DECODE_THREADS overrides the count (0 keeps FFmpeg's default). Other decoders keep PyAV's defaults. Decoded frames are identical. LIBERO, dual-system joint_self_attn, 7x H200, 32 samples/GPU: 1.940 -> 1.380 s/step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…video_frames decode_video_frames guarded container.seek with `except av.AVError`, a name PyAV removed in 14.0. With the pinned PyAV 17.1 a failing seek therefore raised AttributeError from the except clause itself, and the intended fallback to a sequential decode never ran. av.FFmpegError exists in PyAV 12-17 and is the base of every PyAV error. Also validate OPENWAM_VIDEO_DECODE_THREADS strictly (ASCII digits, at most libdav1d's 256 threads), so every bad value raises the documented ValueError, and skip the libdav1d cap test where AV1 is decoded by another library. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LeRobot v3 datasets store their clips in AV1, which FFmpeg decodes with libdav1d. For every clip PyAV opens, libdav1d starts a thread pool sized to the host, because FFmpeg passes its automatic thread count (about one thread per CPU core). With DataLoader workers × ranks decoding concurrently, these pools oversubscribe the machine and the GPUs wait for data. On LIBERO with 7×H200 and 8 workers per rank, the load average was about 150 on 160 cores.
decode_video_frames, the shared reader of everyLeRobotV3Reader, now caps the libdav1d pool at 2 threads per clip.OPENWAM_VIDEO_DECODE_THREADSoverrides the count;0keeps FFmpeg's default.Measurements
End to end. Same config back to back: LIBERO, dual-system
joint_self_attnfrom Wan2.2, 7×H200, 32 samples/GPU, 8 workers/rank,OPENWAM_SDPA_CUDNN=0.main1.940 s/step → this PR 1.380 s/step (−29 %), measured over steps 50–150.Decode throughput. 56 concurrent processes; each sample is 2 cameras × 9 frames of a 33-frame window; 3 interleaved repetitions.
mainFrame threading with 2 threads measured the same within noise, so the thread type is left unchanged. Decoded pixels are identical across all 2,240 clip decodes per setting (56 workers × 20 samples × 2 cameras).
Corrupted input. LIBERO AV1 clips with 200 scattered byte flips or 60 % truncation, decoded over 48 random windows. The outcomes are identical to
main: 15 decoded, 33InvalidDataError, no hangs.Why only libdav1d and only the thread count. An earlier revision enabled frame threading for all decoders. During review, a corrupted H.264 input then hung, where
mainraisesInvalidDataError: theav.loggingcallback that this module installs takes the GIL while frame-thread workers are being joined. The slice-encoded H.264 datasets also gained nothing from frame threading. libdav1d runs its own thread pool regardless of the FFmpeg thread type, so capping its size changes nothing but the pool size.Also fixed (found in review). The seek in
decode_video_frameswas guarded byexcept av.AVError, a name PyAV removed in 14.0. With the pinned PyAV 17.1, a failing seek therefore raisedAttributeErrorfrom theexceptclause itself, and the intended fallback to a sequential decode never ran. The guard now catchesav.FFmpegError, which exists in PyAV 12–17 and is the base of every PyAV error. The new test of this path fails onmain.Not addressed here, as a possible follow-up: in PyAV 17,
frame.to_image()builds a swscale context with an automatic thread count for every frame. This setting does not control those threads.Tests
tests/dataloader/test_video_io_threads.py:decode_video_framesopens for AV1, and not for MPEG-4. The AV1 case is skipped when libdav1d is not the available AV1 decoder.-m "not gpu"): 2147 passed, 1 failed; the failure,test_cosmos_predict25_build_with_bad_path_raises_clear_error, fails identically onmain.🤖 Generated with Claude Code