Skip to main content

fast-ulysses

Ulysses sequence-parallel all-to-all as a torch custom op, moved by the GPU copy engines over NVSHMEM symmetric memory.

License

English · 中文

Ulysses sequence parallelism shards a long sequence across GPUs: one all-to-all before attention trades the sequence shard for a head shard, a second trades it back. For long-sequence video DiT workloads those two collectives are the critical communication.

This ships that 4D all-to-all as torch.ops.fast_ulysses.all_to_all_single_4d. The transfer is pitched cudaMemcpy2D/3DAsync straight into peers' symmetric-heap addresses, so it uses no SMs and runs while compute kernels hold every slot, and the sequence/head relayout is expressed as copy strides instead of two separate permute kernels.

What it does

  • Zero-SM transfer. Remote copies are serialised on one stream; this rank's own share goes on the caller's stream.
  • Relayout for free. The addressing is a host-side plan (a2a_plan.cpp), testable without a GPU, so there is no launch config and no autotune.
  • Copy by default, borrow explicitly. all_to_all_single_4d returns a tensor the caller owns. all_to_all_single_4d_borrowed returns the symmetric window itself — one copy faster, valid only until the next call with that tag.
  • Async. Returns an AsyncCollectiveTensor; the first aten op on it waits by itself. barrier=False lets several borrowed calls (one layer's q/k/v) share one closing handshake.
  • Uneven shards. Per-rank seq_splits / head_splits, which is what lets a caller drop sequence padding. Even splits are the special case, not a separate path.
  • Reserve, then seal. reserve() pre-sizes every window the process will use; afterwards an undeclared call raises instead of allocating in the middle of a collective.

Limits: single node, world_size ∈ [1, 8] including odd sizes; float16 / bfloat16; d * elem_size 16-byte aligned; every pair of GPUs in a group must be P2P-mappable (fast-ulysses doctor prints the matrix, and an unreachable pair is refused at construction).

Fusion examples (QK RMSNorm + RoPE inside the scatter kernel) live on the examples/qk-norm-rope-fusion branch.

Results

8 GPUs, one exclusively allocated node per row, same container and the same .so for all four architectures. base is torch.distributed permute + all_to_all_single + permute; raw is all_to_all_single alone, without the relayout that makes its result usable. Wan 720p, bf16, ms.

GPU fabric base ours vs base transfer vs raw
A100-SXM4-80GB NVLink 2.865 1.670 1.72× 1.227 1.12×
H200 NVSwitch 1.575 0.855 1.84× 0.683 1.22×
B200 NVLink 1.193 0.554 2.15× 0.402 1.22×

Across three generations the shape is the same: 47–60% of the baseline is relayout that costs us nothing, and the transfer alone beats a bare all_to_all_single by 1.12–1.37×. The collective hides essentially completely under a concurrent GEMM chain (86% on B200, ~105% on A100). Dropping the sequence padding is free (1.00×); the baseline pays 5–8% for the same change.

Full stage-by-stage tables, five machines: docs/BENCHMARK.md.

Where it does not win

A group spanning two CPU sockets on a PCIe machine. Inside one socket the operator is 1.4–2.2×, as on NVLink. Across a socket boundary it is about 0.62× of torch.distributed — not because our transfer is slow, but because all_to_all_single does not use direct GPU P2P there. It routes around the socket boundary through the InfiniBand NICs or through host shared memory; we always write peer memory directly. Deny NCCL that bypass and we are 3.8–4.9× faster on the same path. fast-ulysses doctor reports when a group spans sockets; docs/BENCHMARK.md has the measurements.

If you have to run on both kinds of machine, make_group picks for you:

from fast_ulysses import make_group

group = make_group(process_group=dist.group.WORLD, initial_pool_bytes=1 << 30)
# group.fallback is True when it chose torch.distributed because the GPUs span sockets

It returns a TorchUlyssesGroup — the same four entry points on torch.distributed — when the group spans sockets, and UlyssesGroup otherwise. prefer="fast" / prefer="torch" force it. The two are bit-exact on every entry point and both shape families, so the caller keeps one code path; the fallback simply has no overlap to gain and no lifetime rule on its results.

Install

Requires PyTorch 2.10+, CUDA 12.8+ or 13, and sm80 / sm90 / sm100 / sm120. NVSHMEM 3.4.5+ comes from the nvidia-nvshmem-cu1x wheel torch already depends on, so there is nothing to install separately.

pip install fast-ulysses                                  # newest torch, from PyPI
pip install -e . --no-build-isolation                     # from source, all four arches
FAST_ULYSSES_CUDA_ARCH=90 pip install -e . --no-build-isolation   # one arch, much faster

Wheels for other torch versions, and what to do when the import fails: docs/INSTALL.md.

Quick start

torchrun --nproc_per_node=2 example.py:

import os

import torch
import torch.distributed as dist

from fast_ulysses import UlyssesGroup

dist.init_process_group("nccl")
rank, ws = dist.get_rank(), dist.get_world_size()
lr = int(os.environ.get("LOCAL_RANK", rank))
torch.cuda.set_device(lr)

group = UlyssesGroup(process_group=dist.group.WORLD, initial_pool_bytes=1 << 30)

# mode 0: (b, s_local, n_global, d) -> (b, s_global, n_local, d)
b, s_local, d = 2, 16, 128
x = torch.randn(b, s_local, 4 * ws, d, dtype=torch.bfloat16, device=f"cuda:{lr}")

# Every rank must issue the same (shape, mode, tag) sequence.
out = group.all_to_all_single_4d(x, mode=0, tag="demo")
assert out.shape == (b, s_local * ws, 4, d)

group.destroy()
dist.destroy_process_group()

API

API Summary
UlyssesGroup(process_group=None, device=None, initial_pool_bytes=2<<30) Collective: NVSHMEM init + symmetric-heap pool.
group.reserve(calls, *, allow_growth=False) Pre-size every window, then seal.
group.all_to_all_single_4d(x, *, mode=0, tag="", out=None) The default. Returns a tensor the caller owns.
group.all_to_all_single_4d_borrowed(x, *, mode=0, tag="") No copy-out; the result IS the window.
group.all_to_all_single_4d_async(...) The default op on a high-priority comm stream.
group.all_to_all_single_4d_borrowed_async(..., barrier=True) The borrowed op on that stream.
group.destroy() Release symmetric-heap resources (collective).
fast-ulysses doctor Build, devices, P2P matrix, socket layout.

Why the code is shaped this way, and what it rests on that is not guaranteed: docs/DESIGN.md.

Shapes, tag semantics, the barrier ordering contract, and the collective hard constraints — violating the rank-uniform call sequence hangs the group: docs/API.md.

Testing

pytest                                                            # auto-skips below 2 GPUs
torchrun --nproc_per_node=8 tests/distributed/a2a_correctness.py  # one worker directly

Development setup: docs/DEVELOP.md.

License

Apache-2.0. See LICENSE.

Metadata

Release files for fast-ulysses 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fast-ulysses 0.1.0
File Size Uploaded
fast_ulysses-0.1.0.tar.gz 86.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for fast-ulysses 0.1.0
File
fast_ulysses-0.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details
fast_ulysses-0.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 Details
fast_ulysses-0.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details
fast_ulysses-0.1.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details

Total release size: 1.2 MB

Release files / fast_ulysses-0.1.0.tar.gz

Download URL fast_ulysses-0.1.0.tar.gz
Size 86.8 kB
Tags Source
SHA-256 checksum
How to use checksums
b71802de269918b45fb10169e49cd185e8f32724af694c4a67689d3c4c030d27
BLAKE2b-256 checksum
How to use checksums
90db112d1ede21d8d2ac4d0d69b70222dcce81a8ac9f5dd642d8dd1ced54f3c4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release files / fast_ulysses-0.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL fast_ulysses-0.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 281.4 kB
Tags CPython 3.13 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
59ebb062513162f169c670aae395e3769d49706a3a7fd8ce14935e5cfc0e559c
BLAKE2b-256 checksum
How to use checksums
93d19132c172e0bdd36e42594d55989b4c0d69ed33e535404d4b99dfdc0ef39b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release files / fast_ulysses-0.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL fast_ulysses-0.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 281.3 kB
Tags CPython 3.12 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
8b4643cf8424e94673f814c1611b09f4384c87d7dcfab212e9392df70f0f32ff
BLAKE2b-256 checksum
How to use checksums
a41aa2ff274b0d95f0c374942c04e94f64330c9250402e6c902ab431f95561d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release files / fast_ulysses-0.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL fast_ulysses-0.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 280.6 kB
Tags CPython 3.11 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
8118fd9ae8408e69cf5ecd07eb3e6e5b6a95508c0928481e964c08ab2b763130
BLAKE2b-256 checksum
How to use checksums
6e02519419ed9691cbf773a485fef94fe5841ebd4819306cd0aa6018644b2ca1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release files / fast_ulysses-0.1.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL fast_ulysses-0.1.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 279.5 kB
Tags CPython 3.10 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
89489db719377d7e2145622d4057c200714b5fda2494bb81da0554f43469d595
BLAKE2b-256 checksum
How to use checksums
3914d59e6a04d11c9d2557552b2627f96a6a87b70099ce52f49d8c3be0270f82
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.1

5 release files

0.2.0

5 release files

This release

0.1.0 This release

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page