NVIDIA / NVIDIA/cosmos-framework
[BUG] FA2 vs NATTEN on A100: 3.5–4.8× perf gap; what is the "flash2 varlen instability" in checks.py?
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 535
- Forks
- 148
- Avg merge
- 13h 37m
- Merged PRs (30d)
- 35
Description
Two related things on A100 (SM80):
1. NATTEN fallback is 3.5–4.8× slower than FA2 on A100
flash2/checks.py bans varlen ("banned due to instability"), so packed-sequence workloads (always varlen) silently fall back to NATTEN. On A100 that fallback lands on the legacy SM80 CUTLASS 2.X FMHA kernel, which is far slower than FA2 — and the gap grows with seq len:
| seq | natten fwd | fa2 fwd | gap | natten fwd+bwd | fa2 fwd+bwd | gap |
|---|---|---|---|---|---|---|
| 4K | 56 TF/s | 187 TF/s | 3.4× | 36 TF/s | 177 TF/s | 4.9× |
| 16K | 63 TF/s | 216 TF/s | 3.5× | 42 TF/s | 196 TF/s | 4.7× |
| 64K | 45 TF/s | 217 TF/s | 4.8× | 41 TF/s | 198 TF/s | 4.8× |
(single A100-80G, bf16, varlen, 32 q / 8 kv heads, head_dim 128; both backends agree numerically to 2e-3. NATTEN plateaus at ~20% of bf16 peak and regresses at long seq; FA2 holds ~70%.)
End-to-end this roughly halves training MFU for us on A100 at 16K packed seq. H100/B200 are unaffected (flash3 / modern NATTEN kernels), but on SM80 your own default order is ["flash2", "natten"], so the varlen ban effectively removes the intended fast path.
2. What does the "flash2 varlen instability" refer to?
Could you share what the instability specifically is (which flash-attn version / API / arch), and how to reproduce it?
Perf benchmark script (goes through cosmos_framework attention frontend with backend= forced)
import os
os.environ.setdefault("SKYROBOT_ALLOW_FLASH2_VARLEN", "1") # local env-gate lifting the ban; set before import
import torch
from cosmos_framework.model.attention.frontend import attention
DEV, DTYPE = "cuda:0", torch.bfloat16
QH, KVH, HD = 32, 8, 128
SEQS = [1024, 4096, 16384, 32768, 65536]
ITERS, WARMUP = 20, 5
cu = lambda n: torch.tensor([0, n], device=DEV, dtype=torch.int32)
def make(n, rg=False):
g = torch.Generator(device=DEV).manual_seed(0)
q = torch.randn(1, n, QH, HD, device=DEV, dtype=DTYPE, generator=g, requires_grad=rg)
g = torch.Generator(device=DEV).manual_seed(0)
q = torch.randn(1, n, QH, HD, device=DEV, dtype=DTYPE, generator=g, requires_grad=rg)
k = torch.randn(1, n, KVH, HD, device=DEV, dtype=DTYPE, generator=g, requires_grad=rg)
v = torch.randn(1, n, KVH, HD, device=DEV, dtype=DTYPE, generator=g, requires_grad=rg)
return q, k, v
def call(backend, q, k, v, n):
return attention(q, k, v, cumulative_seqlen_Q=cu(n), cumulative_seqlen_KV=cu(n),
max_seqlen_Q=n, max_seqlen_KV=n, backend=backend)
def bench(fn):
for _ in range(WARMUP): fn()
torch.cuda.synchronize(); ts = []
for _ in range(ITERS):
s, e = torch.cuda.Event(True), torch.cuda.Event(True)
s.record(); fn(); e.record(); torch.cuda.synchronize()
ts.append(s.elapsed_time(e))
return sorted(ts)[len(ts)//2]
for n in SEQS:
row = [f"{n:>6}"]
for backend in ("natten", "flash2"):
q, k, v = make(n)
with torch.no_grad():
ms = bench(lambda: call(backend, q, k, v, n))
tf = 4*n*n*QH*HD / (ms/1e3) / 1e12
qg, kg, vg = make(n, rg=True)
dout = torch.randn(1, n, QH, HD, device=DEV, dtype=DTYPE)
def fb():
out = call(backend, qg, kg, vg, n)
(out[0] if isinstance(out, tuple) else out).backward(dout)
qg.grad = kg.grad = vg.grad = None
msfb = bench(fb)
tffb = 4*n*n*QH*HD*3.5 / (msfb/1e3) / 1e12
row.append(f"{backend}: fwd {ms:.2f}ms/{tf:.0f}TF f+b {msfb:.2f}ms/{tffb:.0f}TF")
print(" | ".join(row), flush=True)
Env: A100-SXM4-80GB, Ubuntu 22.04, driver 575.57.08, CUDA 12.8, torch 2.10.0+cu128, flash-attn 2.7.4.post1, NATTEN 0.21.6.dev6, python 3.13.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with flash2/checks.py and run the supplied benchmark through cosmos_framework.model.attention.frontend.attention on the stated A100 environment, comparing forced natten and flash2 varlen paths. Trace the varlen ban to the relevant flash-attn version, API, and architecture, then document the specific instability and a reproducible test or explanation for the observed fallback.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- backend, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100