Skip to content

[perf]: route SP all-to-all NCCL on a dedicated comm stream - #1395

Open
Mister-Raggs wants to merge 2 commits into
hao-ai-lab:mainfrom
Mister-Raggs:perf/nccl-comm-stream
Open

[perf]: route SP all-to-all NCCL on a dedicated comm stream#1395
Mister-Raggs wants to merge 2 commits into
hao-ai-lab:mainfrom
Mister-Raggs:perf/nccl-comm-stream

Conversation

@Mister-Raggs

@Mister-Raggs Mister-Raggs commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Routes the SP all-to-all NCCL collective onto a dedicated comm stream so it no longer serializes with compute on the default stream. Lays the infrastructure for future overlap-based work (e.g. Hybrid Ulysses-Ring rotation) without itself claiming an e2e perf delta on PCIe-bound topologies.

Scope (intentionally narrow)

Wraps only AllToAll4D — the two dist.all_to_all_single calls inside _all_to_all_4D_forward. Other NCCL collectives (AllReduce, AllGather, Slice.backward) are left untouched. Per @rich7420's NCCL optimization status doc, SendRecv from all_to_all_4D is 97.7% of NCCL time on the 4× L40S Wan T2V SP=4 baseline; the others are <3% combined. Wrapping them would add noise without measurable benefit.

Mechanism

A per-device stream cache on DistributedAutograd (lazily created on first use, avoids touching CUDA before device selection; thread-safe via a lock). The two dist.all_to_all_single call sites inside the SP forward path are bracketed with the standard cross-stream discipline:

comm = DistributedAutograd._get_comm_stream(input_.device)
curr = torch.cuda.current_stream(device=input_.device)
comm.wait_stream(curr)                      # comm waits for compute side
with torch.cuda.stream(comm):
    dist.all_to_all_single(output, input_, group=group)
curr.wait_stream(comm)                      # compute side waits for comm

Also extracts the forward shape-munging into a static _all_to_all_4D_forward helper so the inference path can bypass autograd.Function.apply dispatch overhead when grad is off (DeviceCommunicatorBase.all_to_all_4D branches on torch.is_grad_enabled()).

Two design choices worth flagging

No record_stream. Modern PyTorch defaults TORCH_NCCL_AVOID_RECORD_STREAMS=1 (deprecation warning visible in worker logs); the NCCL backend tracks cross-stream tensor lifetime itself. Explicit record_stream() on collective inputs/outputs would force the deprecated slow path and inflate caching-allocator per-collective bookkeeping ~2×. wait_stream ordering alone is sufficient. (Earlier internal design notes prescribed record_stream; that was wrong, corrected in this PR.)

AllToAll4D-only scope (vs all 5 NCCL sites). Per the SendRecv-97.7%-of-NCCL number above. The _functional_collectives alternative path was already tried in @rich7420's exploration and rolled back (+~1% wall regression from AsyncCollectiveTensor wrapper overhead).

A/B validation — 4× L40S sp=4 PCIe (Wan T2V 1.3B)

Thanks to @rich7420 for the Modal A/B run. Harness: fastvideo/tests/modal/nccl_stream_ab.py (single-container overlay-swap pattern, generic for validating single-file PRs). Baseline = bc5ea6bf^ (commit-parent) so the delta isolates this one-file change. 5 prompts × Wan T2V 1.3B 720×1280 / 77 frames / 30 steps, seed-pinned, same Modal container (no cross-host variance).

metric baseline (bc5ea6b^) + nccl-comm-stream Δ
gen_only wall (avg) 153.405 s 153.344 s −0.040 %
full wall (incl load) 209.771 s 209.442 s −0.156 %
SSIM mean-of-means 1.000000 (worst 1.000000)
LPIPS mean-of-means 0.000000 (worst 0.000000)

Reading: bit-exact output (NCCL is deterministic across streams for the same nranks / topology / algorithm). Wall delta inside run-to-run noise — exactly matches the PR thesis that a dedicated stream is necessary-but-not-sufficient for overlap on bandwidth-bound PCIe. No regression on quality or wall; lands cleanly as infrastructure.

Peak-memory was deliberately not re-measured: this patch touches only stream scheduling (no record_stream, tensor lifetimes unchanged) — a null hypothesis there. Easy to add if a reviewer asks.

(A/B reflects the original bc5ea6bf tip. The review-feedback fixes at 29c752f5 are scheduling/lifecycle only — per-device stream cache, CPU-path guard, ValueError, thread-safe init — and do not change collective semantics or output. Happy to re-run Kuan's harness against the new tip if maintainers want a refreshed table.)

Review-feedback fixes (29c752f5 on top of bc5ea6bf)

Addresses the four open review comments on base_device_communicator.py:

  1. Per-device stream cache (gemini-high + Copilot-high). CUDA streams are device-bound, so the single global _comm_stream would crash any multi-GPU / single-process multi-device context. Replaced with _comm_streams: dict[torch.device, Stream], lazily populated under with torch.cuda.device(device):.
  2. CPU-path guard (gemini-high). use_cuda = input_.is_cuda; stream wait/wrap only on CUDA, plain dist.all_to_all_single fallback for CPU paths used by some unit tests.
  3. assertValueError (Copilot-medium). Asserts strip under python -O; ValueError is the correct runtime validation.
  4. Thread-safe lazy init (Copilot-medium). threading.Lock + double-checked locking around dict insertion.

Correctness

The diff is stream-scheduling-only. dist.all_to_all_single(output, input_, group=group) is called with identical arguments to before; only the stream context differs. comm.wait_stream(curr) / curr.wait_stream(comm) ensures cross-stream ordering. No tensor math changes; no NCCL arguments change. SSIM 1.000000 / LPIPS 0.000000 in the A/B above confirms bit-exactness.

Files

  • fastvideo/distributed/device_communicators/base_device_communicator.py — per-device _comm_streams dict + thread-safe _get_comm_stream(device) on DistributedAutograd; _all_to_all_4D_forward static helper extracted; wait_stream discipline at the two dist.all_to_all_single sites, gated on input_.is_cuda with a CPU fallback; DeviceCommunicatorBase.all_to_all_4D adds the inference fast-path.

Credit

Patch authored by @rich7420 on his inference-profile branch (the corrections re: record_stream deprecation + AllToAll4D-only scope are entirely his). This PR is the clean-extraction-+-PR-shepherding of his draft. A/B validation on Modal 4× L40S also by @rich7420.

Adds a lazy class-level `_comm_stream` on `DistributedAutograd` and
routes the two `dist.all_to_all_single` calls inside the SP
`AllToAll4D.forward` collective onto it via the standard
`wait_stream` discipline. Extracts the forward shape-munging into a
static `_all_to_all_4D_forward` helper so the inference path can
bypass `autograd.Function.apply` dispatch overhead when grad is off.

**Scope (intentionally narrow).** Only `AllToAll4D` is wrapped, not
the other NCCL collectives (`AllReduce`, `AllGather`,
`Slice.backward`). Per the profiling work in
[`nccl-optimization-status.md`](https://github.com/rich7420/fastvideo/blob/inference-profile/nccl-optimization-status.md),
SendRecv from `all_to_all_4D` is 97.7% of NCCL on the 4×L40S Wan
T2V baseline; the other collectives are negligible. Wrapping them
adds noise without measurable benefit.

**No `record_stream`.** Modern PyTorch defaults
`TORCH_NCCL_AVOID_RECORD_STREAMS=1` (deprecation warning visible in
worker logs); the NCCL backend tracks cross-stream lifetime itself.
Explicit `record_stream()` on collective inputs/outputs would force
the deprecated slow path and inflate the caching allocator's
per-collective bookkeeping ~2×. `wait_stream` ordering alone is
sufficient — see the docstring on `_comm_stream` for detail.

**No e2e perf claim on this PR.** The dedicated stream is necessary
but not sufficient for comm/compute overlap on PCIe (per
`nccl-optimization-status.md`: NCCL on L40S is bandwidth-bound, not
stream-bound; software stream rearrangement alone doesn't move the
needle). This change lands the infrastructure that future
overlap-based work (e.g. Hybrid Ulysses-Ring rotation) needs in
place. The `_functional_collectives` alternative was already tried
and rolled back (+1% wall regression from AsyncCollectiveTensor
wrapper overhead) — see status doc.

**Inference fast-path.** `DeviceCommunicatorBase.all_to_all_4D` now
calls `_all_to_all_4D_forward` directly when `torch.is_grad_enabled()`
is False, skipping the `autograd.Function.apply` machinery. Small
per-call dispatch saving (the SP all-to-all is on every attention
call inside the denoising loop); cumulative effect to be measured
in a follow-up if signal worth chasing.

Co-Authored-By: KUAN-HAO HUANG <rich7420@gmail.com>
Copilot AI review requested due to automatic review settings May 26, 2026 16:23

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a dedicated CUDA stream for 4D all-to-all collectives to prevent serialization with the default compute stream, and optimizes inference by bypassing the autograd dispatch overhead when gradients are disabled. The reviewer provided valuable feedback pointing out that reusing a single stream across multiple devices can cause runtime errors, suggesting a device-mapped dictionary of streams instead. Additionally, the reviewer recommended guarding CUDA stream operations to prevent failures when processing CPU-only tensors.

Comment on lines +20 to +36
# Dedicated stream for SP all-to-all collectives. Lazily created on first
# use to avoid touching CUDA before the device is selected. NCCL kernels
# issued on this stream no longer serialize with compute on the default
# stream, freeing GPU launch queue pressure.
#
# NOTE: we intentionally do NOT call .record_stream() on the input/output
# tensors. PyTorch's NCCL backend now defaults TORCH_NCCL_AVOID_RECORD_STREAMS=1
# and handles cross-stream lifetime via its own mechanism — calling
# record_stream() explicitly forces the deprecated slow path and inflates
# caching-allocator bookkeeping by 2× per collective.
_comm_stream: "torch.cuda.Stream | None" = None

@staticmethod
def _get_comm_stream() -> "torch.cuda.Stream":
if DistributedAutograd._comm_stream is None:
DistributedAutograd._comm_stream = torch.cuda.Stream()
return DistributedAutograd._comm_stream

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Reusing a single torch.cuda.Stream across different devices (e.g., in multi-GPU testing or single-process multi-device environments) will cause runtime errors or silent correctness issues because a stream is bound to a specific device.

To fix this, we should store a dictionary of streams mapped by device, and lazily create them on the correct device context.

Suggested change
# Dedicated stream for SP all-to-all collectives. Lazily created on first
# use to avoid touching CUDA before the device is selected. NCCL kernels
# issued on this stream no longer serialize with compute on the default
# stream, freeing GPU launch queue pressure.
#
# NOTE: we intentionally do NOT call .record_stream() on the input/output
# tensors. PyTorch's NCCL backend now defaults TORCH_NCCL_AVOID_RECORD_STREAMS=1
# and handles cross-stream lifetime via its own mechanism — calling
# record_stream() explicitly forces the deprecated slow path and inflates
# caching-allocator bookkeeping by 2× per collective.
_comm_stream: "torch.cuda.Stream | None" = None
@staticmethod
def _get_comm_stream() -> "torch.cuda.Stream":
if DistributedAutograd._comm_stream is None:
DistributedAutograd._comm_stream = torch.cuda.Stream()
return DistributedAutograd._comm_stream
# Dedicated streams for SP all-to-all collectives, mapped by device.
# Lazily created on first use to avoid touching CUDA before the device is selected.
# NCCL kernels issued on these streams no longer serialize with compute on the default
# stream, freeing GPU launch queue pressure.
#
# NOTE: we intentionally do NOT call .record_stream() on the input/output
# tensors. PyTorch's NCCL backend now defaults TORCH_NCCL_AVOID_RECORD_STREAMS=1
# and handles cross-stream lifetime via its own mechanism — calling
# record_stream() explicitly forces the deprecated slow path and inflates
# caching-allocator bookkeeping by 2× per collective.
_comm_streams: dict[torch.device, "torch.cuda.Stream"] = {}
@staticmethod
def _get_comm_stream(device: torch.device) -> "torch.cuda.Stream":
if device not in DistributedAutograd._comm_streams:
with torch.cuda.device(device):
DistributedAutograd._comm_streams[device] = torch.cuda.Stream(device=device)
return DistributedAutograd._comm_streams[device]

Comment on lines +141 to +198
@staticmethod
def _all_to_all_4D_forward(group: ProcessGroup, input_: Tensor, world_size: int, scatter_dim: int,
gather_dim: int) -> Tensor:
"""Pure forward logic for 4D all-to-all. Used by both the autograd
Function and the inference fast-path that bypasses autograd."""
if world_size == 1:
return input_

if world_size == 1:
return input_
assert input_.dim() == 4, f"input must be 4D tensor, got {input_.dim()} and shape {input_.shape}"

assert input_.dim() == 4, f"input must be 4D tensor, got {input_.dim()} and shape {input_.shape}"
comm = DistributedAutograd._get_comm_stream()
curr = torch.cuda.current_stream()

if scatter_dim == 2 and gather_dim == 1:
bs, shard_seqlen, hn, hd = input_.shape
seqlen = shard_seqlen * world_size
shard_hn = hn // world_size
if scatter_dim == 2 and gather_dim == 1:
bs, shard_seqlen, hn, hd = input_.shape
shard_hn = hn // world_size

input_ = input_.transpose(0, 2).contiguous() # hn, shard_seqlen, bs, hd
output = torch.empty_like(input_)
input_ = input_.transpose(0, 2).contiguous() # hn, shard_seqlen, bs, hd
output = torch.empty_like(input_)

# Issue NCCL on the dedicated comm stream so it doesn't serialize
# with compute on the default stream. No record_stream — see the
# _comm_stream class docstring for why.
comm.wait_stream(curr)
with torch.cuda.stream(comm):
dist.all_to_all_single(output, input_, group=group) # hn, shard_seqlen, bs, hd
curr.wait_stream(comm)

output = torch.cat(output.split(shard_hn), dim=1) # sharded hn, seqlen, bs, hd
output = torch.cat(output.split(shard_hn), dim=1) # sharded hn, seqlen, bs, hd

output = output.transpose(0, 2).contiguous() # bs, seqlen, sharded_hn, hd
output = output.transpose(0, 2).contiguous() # bs, seqlen, sharded_hn, hd

return output
elif scatter_dim == 1 and gather_dim == 2:
bs, seqlen, shard_hn, hd = input_.shape
hn = shard_hn * world_size
shard_seqlen = seqlen // world_size
return output
elif scatter_dim == 1 and gather_dim == 2:
bs, seqlen, shard_hn, hd = input_.shape
shard_seqlen = seqlen // world_size

input_ = input_.transpose(0, 2).contiguous() # shard_hn, seqlen, bs, hd
input_ = input_.transpose(0, 2).contiguous() # shard_hn, seqlen, bs, hd

input_ = input_.reshape(shard_hn, world_size, shard_seqlen, bs,
hd).transpose(0, 1).reshape(shard_hn * world_size, shard_seqlen, bs,
hd).contiguous()
input_ = input_.reshape(shard_hn, world_size, shard_seqlen, bs,
hd).transpose(0, 1).reshape(shard_hn * world_size, shard_seqlen, bs,
hd).contiguous()

output = torch.empty_like(input_)
output = torch.empty_like(input_)

comm.wait_stream(curr)
with torch.cuda.stream(comm):
dist.all_to_all_single(output, input_, group=group)
curr.wait_stream(comm)

output = output.transpose(0, 2).contiguous() # bs, seqlen, sharded_hn, hd
output = output.transpose(0, 2).contiguous() # bs, seqlen, sharded_hn, hd

return output
else:
raise RuntimeError(
f"Invalid scatter_dim={scatter_dim}, gather_dim={gather_dim}. "
f"Only (scatter_dim=2, gather_dim=1) and (scatter_dim=1, gather_dim=2) are supported.")
return output
else:
raise RuntimeError(
f"Invalid scatter_dim={scatter_dim}, gather_dim={gather_dim}. "
f"Only (scatter_dim=2, gather_dim=1) and (scatter_dim=1, gather_dim=2) are supported.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the input tensor is on CPU (e.g., during CPU-only testing or execution), calling torch.cuda.Stream() or torch.cuda.current_stream() will raise a RuntimeError or AssertionError because CUDA is not available or not used.

We should guard the stream creation and synchronization so that they are only executed when the input tensor is on a CUDA device. Additionally, we should pass the input tensor's device to _get_comm_stream and torch.cuda.current_stream to ensure the correct device context is used.

    @staticmethod
    def _all_to_all_4D_forward(group: ProcessGroup, input_: Tensor, world_size: int, scatter_dim: int,
                               gather_dim: int) -> Tensor:
        """Pure forward logic for 4D all-to-all. Used by both the autograd
        Function and the inference fast-path that bypasses autograd."""
        if world_size == 1:
            return input_

        assert input_.dim() == 4, f"input must be 4D tensor, got {input_.dim()} and shape {input_.shape}"

        use_cuda = input_.is_cuda
        if use_cuda:
            comm = DistributedAutograd._get_comm_stream(input_.device)
            curr = torch.cuda.current_stream(device=input_.device)

        if scatter_dim == 2 and gather_dim == 1:
            bs, shard_seqlen, hn, hd = input_.shape
            shard_hn = hn // world_size

            input_ = input_.transpose(0, 2).contiguous()  # hn, shard_seqlen, bs, hd
            output = torch.empty_like(input_)

            # Issue NCCL on the dedicated comm stream so it doesn't serialize
            # with compute on the default stream. No record_stream — see the
            # _comm_stream class docstring for why.
            if use_cuda:
                comm.wait_stream(curr)
                with torch.cuda.stream(comm):
                    dist.all_to_all_single(output, input_, group=group)  # hn, shard_seqlen, bs, hd
                curr.wait_stream(comm)
            else:
                dist.all_to_all_single(output, input_, group=group)

            output = torch.cat(output.split(shard_hn), dim=1)  # sharded hn, seqlen, bs, hd

            output = output.transpose(0, 2).contiguous()  # bs, seqlen, sharded_hn, hd

            return output
        elif scatter_dim == 1 and gather_dim == 2:
            bs, seqlen, shard_hn, hd = input_.shape
            shard_seqlen = seqlen // world_size

            input_ = input_.transpose(0, 2).contiguous()  # shard_hn, seqlen, bs, hd

            input_ = input_.reshape(shard_hn, world_size, shard_seqlen, bs,
                                    hd).transpose(0, 1).reshape(shard_hn * world_size, shard_seqlen, bs,
                                                                hd).contiguous()

            output = torch.empty_like(input_)

            if use_cuda:
                comm.wait_stream(curr)
                with torch.cuda.stream(comm):
                    dist.all_to_all_single(output, input_, group=group)
                curr.wait_stream(comm)
            else:
                dist.all_to_all_single(output, input_, group=group)

            output = output.transpose(0, 2).contiguous()  # bs, seqlen, sharded_hn, hd

            return output
        else:
            raise RuntimeError(
                f"Invalid scatter_dim={scatter_dim}, gather_dim={gather_dim}. "
                f"Only (scatter_dim=2, gather_dim=1) and (scatter_dim=1, gather_dim=2) are supported.")

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR refactors the 4D all-to-all implementation to reduce inference overhead and improve GPU scheduling by moving NCCL collectives onto a dedicated CUDA stream and adding an autograd-bypass fast path when gradients are disabled.

Changes:

  • Added a lazily-initialized dedicated CUDA communication stream for SP all-to-all collectives.
  • Extracted 4D all-to-all forward logic into a shared helper used by both autograd and inference paths.
  • Updated all_to_all_4D to bypass autograd.Function dispatch when torch.is_grad_enabled() is false.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +30 to +37
_comm_stream: "torch.cuda.Stream | None" = None

@staticmethod
def _get_comm_stream() -> "torch.cuda.Stream":
if DistributedAutograd._comm_stream is None:
DistributedAutograd._comm_stream = torch.cuda.Stream()
return DistributedAutograd._comm_stream

Comment on lines +151 to +152
comm = DistributedAutograd._get_comm_stream()
curr = torch.cuda.current_stream()

if world_size == 1:
return input_
assert input_.dim() == 4, f"input must be 4D tensor, got {input_.dim()} and shape {input_.shape}"
Comment on lines +32 to +36
@staticmethod
def _get_comm_stream() -> "torch.cuda.Stream":
if DistributedAutograd._comm_stream is None:
DistributedAutograd._comm_stream = torch.cuda.Stream()
return DistributedAutograd._comm_stream
@mergify mergify Bot added type: perf Performance improvement scope: distributed SP, FSDP, USP, multi-node labels May 26, 2026
@mergify

mergify Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🔴 1 of 1 protections blocking · waiting on 👀 reviews and 🤖 CI

Protection Waiting on
🔴 PR merge requirements 👀 reviews and 🤖 CI

🔴 PR merge requirements

Waiting for

  • #approved-reviews-by>=1
  • check-success=full-suite-passed
  • check-success~=pre-commit
This rule is failing.
  • #approved-reviews-by>=1
  • check-success=full-suite-passed
  • check-success~=pre-commit
  • check-success=fastcheck-passed
  • title~=(?i)^\[(feat|feature|bugfix|fix|refactor|perf|ci|doc|docs|misc|chore|kernel|new.?model|skill|skills|infra)\]

Four reviewer findings on bc5ea6b, all in
base_device_communicator.py:

1. Per-device stream cache (gemini-high + Copilot-high).
   CUDA streams are device-bound; the single global
   _comm_stream would crash any multi-GPU / single-process
   multi-device context. Replaced with
   _comm_streams: dict[torch.device, Stream], lazily
   populated under `with torch.cuda.device(device):`.

2. CPU-path guard (gemini-high). use_cuda = input_.is_cuda;
   stream wait/wrap only when CUDA, plain
   dist.all_to_all_single fallback for CPU paths used by
   some unit tests.

3. assert -> ValueError (Copilot-medium). Asserts strip
   under python -O; ValueError is the correct runtime
   validation here.

4. Thread-safe lazy init (Copilot-medium). threading.Lock
   + double-checked locking around dict insertion to
   handle concurrent first-access.

Scheduling/lifecycle only — no change to collective
semantics or output. Kuan's A/B numbers on bc5ea6b
(SSIM 1.000000, wall delta inside noise) remain valid in
spirit; happy to re-run on the new tip if a maintainer
asks.
Mister-Raggs added a commit to Mister-Raggs/FastVideo that referenced this pull request May 30, 2026
Single-container two-pass A/B harness modeled on Kuan's
nccl_stream_ab.py pattern (used to validate hao-ai-lab#1395). Runs the same
seed-pinned prompts twice through the same VideoGenerator (once
sequential, once batched), computes pairwise SSIM via pytorch_msssim
(matches fastvideo/tests/utils.py:compute_video_ssim_torchvision),
prints a per-prompt + total wall/SSIM table.

Architecture: the harness ferries pass config + records over JSON
files and subprocesses the inner script via /opt/venv/bin/python.
Modal's main function process runs in its own add_python="3.12"
layer where FastVideo isn't importable; the venv subprocess works
around that. Same reason ssim_test.py runs pytest as a subprocess.

Features:
- Mode tag in output dirs ({eager,compile}[-{dit_precision}]) so
  multiple legs don't clobber each other in the hf-model-weights
  Volume.
- Recovery function reads existing mp4s by mtime and recomputes SSIM,
  for post-run gap-fill if the in-run SSIM step missed.
- Prebuilt FA3 wheel install on Hopper (autodetected from gpu kwarg)
  via mjun0812/flash-attention-prebuild-wheels v0.9.4 — the same
  release that supplies the FA2 wheel already baked into the
  fastvideo-dev image. ~30s install vs Kuan's hao-ai-lab#1389 ~90min cold
  source build.
- Modal Secret integration for HF token (no token-on-the-wire).
- --enable-compile, --dit-precision, --num-prompts flags for
  flexible legs (eager/compile, bf16/fp16/fp32, short diagnostic
  runs vs full 5-prompt validation).

Reproducible by reviewers — see PR body for exact commands.
Mister-Raggs added a commit to Mister-Raggs/FastVideo that referenced this pull request May 31, 2026
Single-container two-pass A/B harness modeled on Kuan's
nccl_stream_ab.py pattern (used to validate hao-ai-lab#1395). Runs the same
seed-pinned prompts twice through the same VideoGenerator (once
sequential, once batched), computes pairwise SSIM via pytorch_msssim
(matches fastvideo/tests/utils.py:compute_video_ssim_torchvision),
prints a per-prompt + total wall/SSIM table.

Architecture: the harness ferries pass config + records over JSON
files and subprocesses the inner script via /opt/venv/bin/python.
Modal's main function process runs in its own add_python="3.12"
layer where FastVideo isn't importable; the venv subprocess works
around that. Same reason ssim_test.py runs pytest as a subprocess.

Features:
- Mode tag in output dirs ({eager,compile}[-{dit_precision}]) so
  multiple legs don't clobber each other in the hf-model-weights
  Volume.
- Recovery function reads existing mp4s by mtime and recomputes SSIM,
  for post-run gap-fill if the in-run SSIM step missed.
- Prebuilt FA3 wheel install on Hopper (autodetected from gpu kwarg)
  via mjun0812/flash-attention-prebuild-wheels v0.9.4 — the same
  release that supplies the FA2 wheel already baked into the
  fastvideo-dev image. ~30s install vs Kuan's hao-ai-lab#1389 ~90min cold
  source build.
- Modal Secret integration for HF token (no token-on-the-wire).
- --enable-compile, --dit-precision, --num-prompts flags for
  flexible legs (eager/compile, bf16/fp16/fp32, short diagnostic
  runs vs full 5-prompt validation).

Reproducible by reviewers — see PR body for exact commands.
Mister-Raggs added a commit to Mister-Raggs/FastVideo that referenced this pull request May 31, 2026
Single-container two-pass A/B harness modeled on Kuan's
nccl_stream_ab.py pattern (used to validate hao-ai-lab#1395). Runs the same
seed-pinned prompts twice through the same VideoGenerator (once
sequential, once batched), computes pairwise SSIM via pytorch_msssim
(matches fastvideo/tests/utils.py:compute_video_ssim_torchvision),
prints a per-prompt + total wall/SSIM table.

Architecture: the harness ferries pass config + records over JSON
files and subprocesses the inner script via /opt/venv/bin/python.
Modal's main function process runs in its own add_python="3.12"
layer where FastVideo isn't importable; the venv subprocess works
around that. Same reason ssim_test.py runs pytest as a subprocess.

Features:
- Mode tag in output dirs ({eager,compile}[-{dit_precision}]) so
  multiple legs don't clobber each other in the hf-model-weights
  Volume.
- Recovery function reads existing mp4s by mtime and recomputes SSIM,
  for post-run gap-fill if the in-run SSIM step missed.
- Prebuilt FA3 wheel install on Hopper (autodetected from gpu kwarg)
  via mjun0812/flash-attention-prebuild-wheels v0.9.4 — the same
  release that supplies the FA2 wheel already baked into the
  fastvideo-dev image. ~30s install vs Kuan's hao-ai-lab#1389 ~90min cold
  source build.
- Modal Secret integration for HF token (no token-on-the-wire).
- --enable-compile, --dit-precision, --num-prompts flags for
  flexible legs (eager/compile, bf16/fp16/fp32, short diagnostic
  runs vs full 5-prompt validation).

Reproducible by reviewers — see PR body for exact commands.
Mister-Raggs added a commit to Mister-Raggs/FastVideo that referenced this pull request May 31, 2026
Single-container two-pass A/B harness modeled on Kuan's
nccl_stream_ab.py pattern (used to validate hao-ai-lab#1395). Runs the same
seed-pinned prompts twice through the same VideoGenerator (once
sequential, once batched), computes pairwise SSIM via pytorch_msssim
(matches fastvideo/tests/utils.py:compute_video_ssim_torchvision),
prints a per-prompt + total wall/SSIM table.

Architecture: the harness ferries pass config + records over JSON
files and subprocesses the inner script via /opt/venv/bin/python.
Modal's main function process runs in its own add_python="3.12"
layer where FastVideo isn't importable; the venv subprocess works
around that. Same reason ssim_test.py runs pytest as a subprocess.

Features:
- Mode tag in output dirs ({eager,compile}[-{dit_precision}]) so
  multiple legs don't clobber each other in the hf-model-weights
  Volume.
- Recovery function reads existing mp4s by mtime and recomputes SSIM,
  for post-run gap-fill if the in-run SSIM step missed.
- Prebuilt FA3 wheel install on Hopper (autodetected from gpu kwarg)
  via mjun0812/flash-attention-prebuild-wheels v0.9.4 — the same
  release that supplies the FA2 wheel already baked into the
  fastvideo-dev image. ~30s install vs Kuan's hao-ai-lab#1389 ~90min cold
  source build.
- Modal Secret integration for HF token (no token-on-the-wire).
- --enable-compile, --dit-precision, --num-prompts flags for
  flexible legs (eager/compile, bf16/fp16/fp32, short diagnostic
  runs vs full 5-prompt validation).

Reproducible by reviewers — see PR body for exact commands.
Mister-Raggs added a commit to Mister-Raggs/FastVideo that referenced this pull request Jun 1, 2026
Single-container two-pass A/B harness modeled on Kuan's
nccl_stream_ab.py pattern (used to validate hao-ai-lab#1395). Runs the same
seed-pinned prompts twice through the same VideoGenerator (once
sequential, once batched), computes pairwise SSIM via pytorch_msssim
(matches fastvideo/tests/utils.py:compute_video_ssim_torchvision),
prints a per-prompt + total wall/SSIM table.

Architecture: the harness ferries pass config + records over JSON
files and subprocesses the inner script via /opt/venv/bin/python.
Modal's main function process runs in its own add_python="3.12"
layer where FastVideo isn't importable; the venv subprocess works
around that. Same reason ssim_test.py runs pytest as a subprocess.

Features:
- Mode-tagged output dirs ({eager,compile}) so multiple legs don't
  clobber each other in the hf-model-weights Volume.
- Recovery function reads existing mp4s by mtime and recomputes SSIM
  for post-run gap-fill if the in-run SSIM step missed.
- Prebuilt FA3 wheel install on Hopper (autodetected from gpu kwarg)
  via mjun0812/flash-attention-prebuild-wheels v0.9.4 — the same
  release that supplies the FA2 wheel already baked into the
  fastvideo-dev image. ~30s install vs Kuan's hao-ai-lab#1389 ~90min cold
  source build.
- Modal Secret integration for HF token (no token-on-the-wire).
- --enable-compile + --num-prompts flags for flexible legs.

Reproducible by reviewers — see PR body for exact commands.
Mister-Raggs added a commit to Mister-Raggs/FastVideo that referenced this pull request Jul 12, 2026
Single-container two-pass A/B harness modeled on Kuan's
nccl_stream_ab.py pattern (used to validate hao-ai-lab#1395). Runs the same
seed-pinned prompts twice through the same VideoGenerator (once
sequential, once batched), computes pairwise SSIM via pytorch_msssim
(matches fastvideo/tests/utils.py:compute_video_ssim_torchvision),
prints a per-prompt + total wall/SSIM table.

Architecture: the harness ferries pass config + records over JSON
files and subprocesses the inner script via /opt/venv/bin/python.
Modal's main function process runs in its own add_python="3.12"
layer where FastVideo isn't importable; the venv subprocess works
around that. Same reason ssim_test.py runs pytest as a subprocess.

Features:
- Mode-tagged output dirs ({eager,compile}) so multiple legs don't
  clobber each other in the hf-model-weights Volume.
- Recovery function reads existing mp4s by mtime and recomputes SSIM
  for post-run gap-fill if the in-run SSIM step missed.
- Prebuilt FA3 wheel install on Hopper (autodetected from gpu kwarg)
  via mjun0812/flash-attention-prebuild-wheels v0.9.4 — the same
  release that supplies the FA2 wheel already baked into the
  fastvideo-dev image. ~30s install vs Kuan's hao-ai-lab#1389 ~90min cold
  source build.
- Modal Secret integration for HF token (no token-on-the-wire).
- --enable-compile + --num-prompts flags for flexible legs.

Reproducible by reviewers — see PR body for exact commands.
Mister-Raggs added a commit to Mister-Raggs/FastVideo that referenced this pull request Jul 17, 2026
Single-container two-pass A/B harness modeled on Kuan's
nccl_stream_ab.py pattern (used to validate hao-ai-lab#1395). Runs the same
seed-pinned prompts twice through the same VideoGenerator (once
sequential, once batched), computes pairwise SSIM via pytorch_msssim
(matches fastvideo/tests/utils.py:compute_video_ssim_torchvision),
prints a per-prompt + total wall/SSIM table.

Architecture: the harness ferries pass config + records over JSON
files and subprocesses the inner script via /opt/venv/bin/python.
Modal's main function process runs in its own add_python="3.12"
layer where FastVideo isn't importable; the venv subprocess works
around that. Same reason ssim_test.py runs pytest as a subprocess.

Features:
- Mode-tagged output dirs ({eager,compile}) so multiple legs don't
  clobber each other in the hf-model-weights Volume.
- Recovery function reads existing mp4s by mtime and recomputes SSIM
  for post-run gap-fill if the in-run SSIM step missed.
- Prebuilt FA3 wheel install on Hopper (autodetected from gpu kwarg)
  via mjun0812/flash-attention-prebuild-wheels v0.9.4 — the same
  release that supplies the FA2 wheel already baked into the
  fastvideo-dev image. ~30s install vs Kuan's hao-ai-lab#1389 ~90min cold
  source build.
- Modal Secret integration for HF token (no token-on-the-wire).
- --enable-compile + --num-prompts flags for flexible legs.

Reproducible by reviewers — see PR body for exact commands.
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had any activity within 60 days. It will be automatically closed if no further activity occurs within 14 days. Leave a comment if you feel this pull request should remain open. Thank you!

@github-actions github-actions Bot added the stale Inactive — will auto-close soon label Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: distributed SP, FSDP, USP, multi-node stale Inactive — will auto-close soon type: perf Performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants