#!/usr/bin/env python3 """Verify the single-image broadcast fast path vs the pad-to-max all_gather: bitwise equivalence + timing, on real NCCL over 8 ranks. Mirrors what run_dp_sharded_mrope_vision_model does for a single image (one owner rank holds the embedding, the rest are empty). torchrun --nproc_per_node=8.""" import time import torch import torch.distributed as dist def main(): dist.init_process_group("nccl") rank, world = dist.get_rank(), dist.get_world_size() torch.cuda.set_device(rank) dev = f"cuda:{rank}" owner = 3 # arbitrary non-zero owner, as LB would pick n_tok, hidden = 5476, 4096 # ~2048^2 image, typical tower output (~44MB bf16) # deterministic ground-truth owner embedding, known to every rank gen = torch.Generator(device=dev).manual_seed(12345) owner_truth = torch.randn( n_tok, hidden, dtype=torch.bfloat16, device=dev, generator=gen ) emb = ( owner_truth.clone() if rank == owner else torch.empty(0, hidden, dtype=torch.bfloat16, device=dev) ) max_len = n_tok # single image: max over ranks == owner's length def path_a(): # current: pad-to-max all_gather + reconstruct owner rows padded = torch.empty(max_len, hidden, dtype=torch.bfloat16, device=dev) if emb.shape[0] > 0: padded[: emb.shape[0]].copy_(emb) gathered = [ torch.empty(max_len, hidden, dtype=torch.bfloat16, device=dev) for _ in range(world) ] dist.all_gather(gathered, padded) return gathered[owner][:n_tok] def path_b(): # fast path: broadcast from owner buf = ( emb.contiguous() if rank == owner else torch.empty(n_tok, hidden, dtype=torch.bfloat16, device=dev) ) dist.broadcast(buf, src=owner) return buf out_a, out_b = path_a(), path_b() eq_truth = torch.equal(out_a, owner_truth) eq_ab = torch.equal(out_a, out_b) eq_b_truth = torch.equal(out_b, owner_truth) def timeit(fn, n=100): for _ in range(15): fn() torch.cuda.synchronize() dist.barrier() t0 = time.perf_counter() for _ in range(n): fn() torch.cuda.synchronize() dist.barrier() return (time.perf_counter() - t0) / n * 1000 ta, tb = timeit(path_a), timeit(path_b) # gather correctness flags from all ranks flags = torch.tensor( [eq_ab and eq_truth and eq_b_truth], device=dev, dtype=torch.int32 ) dist.all_reduce(flags, op=dist.ReduceOp.MIN) if rank == 0: print( f"world={world} owner={owner} shape=[{n_tok},{hidden}] " f"(~{n_tok * hidden * 2 / 1e6:.0f}MB) | all_ranks_bitwise_ok={bool(flags.item())} " f"(A==truth={eq_truth} A==B={eq_ab}) | all_gather {ta:.3f}ms " f"broadcast {tb:.3f}ms speedup {ta / tb:.2f}x", flush=True, ) dist.destroy_process_group() if __name__ == "__main__": main()