From 29b6132e91e1a3453f4274db5a62aaa042de37ad Mon Sep 17 00:00:00 2001 From: Johan de Ruiter Date: Thu, 9 Jul 2026 23:08:56 +0000 Subject: [PATCH] ltx23: cap PyAV libx264 encode threads at 12 (rename scenecut patch -> x264-tuning) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PyAV single-pass save path (the one we actually run on B200 — no ffmpeg on PATH) set no `threads` option, so libx264 auto-detected all ~288 node cores and thrashed. PR #8's -threads cap only ever applied to the dead ffmpeg-pipe path. Isolated encode-only sweep (di-slc-46 B200, 121f 1080p, conversion excluded, 6 reps median): threads=1 1.020s threads=10 0.419s <- sweet spot threads=4 0.530s threads=12 0.445s threads=8 0.439s threads=16 0.637s <- worse past here threads=default(288) 1.65s total (thrash) threads=32 0.674s More threads do NOT help: x264 slice-threading on a single 1080p stream saturates ~10-12, then slice/sync overhead makes it slower. 12 = fastest AND well under a fair share (no noisy-neighbor tradeoff). Extends the existing PyAV scenecut patch (renamed pyav-scenecut -> pyav-x264-tuning since it now does both). Env-configurable via FASTVIDEO_X264_THREADS_PYAV (no rebuild to change). Verified: applies --fuzz=0 to pristine fastvideo source. Deploys with the next image rebuild. Co-Authored-By: Claude Opus 4.8 (1M context) --- examples/diffusers/Dockerfile.dreamverse | 4 ++-- .../{pyav-scenecut.patch => pyav-x264-tuning.patch} | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) rename examples/diffusers/patches/{pyav-scenecut.patch => pyav-x264-tuning.patch} (58%) diff --git a/examples/diffusers/Dockerfile.dreamverse b/examples/diffusers/Dockerfile.dreamverse index 55495245a219..68c274771f9a 100644 --- a/examples/diffusers/Dockerfile.dreamverse +++ b/examples/diffusers/Dockerfile.dreamverse @@ -54,7 +54,7 @@ RUN . /opt/venv/bin/activate \ # the exact commit these patches were authored against, so they apply clean. COPY patches/ltx23_gpu_worker_megacache.patch /tmp/megacache.patch COPY patches/x264-threads-cap.patch /tmp/x264-threads-cap.patch -COPY patches/pyav-scenecut.patch /tmp/pyav-scenecut.patch +COPY patches/pyav-x264-tuning.patch /tmp/pyav-x264-tuning.patch COPY patches/flash-attn-cute-fa4-tuple-fix.patch /tmp/flash-attn-cute-fa4-tuple-fix.patch # NOTE: verify by grepping the patched source, NOT by importing fastvideo -- # importing pulls in triton, which fails to init its driver in a GPU-less build @@ -62,7 +62,7 @@ COPY patches/flash-attn-cute-fa4-tuple-fix.patch /tmp/flash-attn-cute-fa4-tuple- RUN SP=/opt/venv/lib/python3.12/site-packages \ && patch -p1 -d "$SP" --forward --fuzz=0 < /tmp/megacache.patch \ && patch -p1 -d "$SP" --forward --fuzz=0 < /tmp/x264-threads-cap.patch \ - && patch -p1 -d "$SP" --forward --fuzz=0 < /tmp/pyav-scenecut.patch \ + && patch -p1 -d "$SP" --forward --fuzz=0 < /tmp/pyav-x264-tuning.patch \ && patch -p1 -d "$SP" --forward --fuzz=0 < /tmp/flash-attn-cute-fa4-tuple-fix.patch \ && grep -q 'torch.compiler.load_cache_artifacts' "$SP/fastvideo/worker/gpu_worker.py" \ && grep -q 'FASTVIDEO_X264_THREADS' "$SP/fastvideo/entrypoints/video_generator.py" \ diff --git a/examples/diffusers/patches/pyav-scenecut.patch b/examples/diffusers/patches/pyav-x264-tuning.patch similarity index 58% rename from examples/diffusers/patches/pyav-scenecut.patch rename to examples/diffusers/patches/pyav-x264-tuning.patch index 79d003e5d7ab..b2fd35ef6bc3 100644 --- a/examples/diffusers/patches/pyav-scenecut.patch +++ b/examples/diffusers/patches/pyav-x264-tuning.patch @@ -2,7 +2,7 @@ diff --git a/fastvideo/entrypoints/video_generator.py b/fastvideo/entrypoints/vi index bfc1633..ef4f213 100644 --- a/fastvideo/entrypoints/video_generator.py +++ b/fastvideo/entrypoints/video_generator.py -@@ -1010,6 +1010,12 @@ class VideoGenerator: +@@ -1010,6 +1010,20 @@ class VideoGenerator: video_stream.options = { "preset": "ultrafast", "tune": "zerolatency", @@ -12,6 +12,14 @@ index bfc1633..ef4f213 100644 + # FASTVIDEO_X264_PRESET below) so it's opt-out per model without + # a rebuild. Measured ~50-100ms/clip (deepinfra, 2026-07-07). + "x264-params": f"scenecut={os.getenv('FASTVIDEO_X264_SCENECUT', '0')}", ++ # Cap x264 threads. B200 has no NVENC so this is CPU libx264; ++ # unbounded, x264 auto-detects all node cores (~288) -> thread ++ # thrash. Isolated encode-only sweep (deepinfra 2026-07-09, 121f ++ # 1080p) bottoms out ~10-12 threads (~0.42s) and gets WORSE past ++ # 16 (0.64s+); 12 = sweet spot AND well under a fair share. The ++ # ffmpeg-pipe path caps at 32 but is dead on B200 (no ffmpeg on ++ # PATH). Env-configurable, no rebuild to change. ++ "threads": os.getenv("FASTVIDEO_X264_THREADS_PYAV", "12"), } audio_stream = output.add_stream("aac", rate=sample_rate, layout=layout)