[TRITON][GLUON][GFX950][DSV4] Paged Sparse Attention Gluon Kernel#4382
Draft
cagrikymk wants to merge 12 commits into
Draft
[TRITON][GLUON][GFX950][DSV4] Paged Sparse Attention Gluon Kernel#4382cagrikymk wants to merge 12 commits into
cagrikymk wants to merge 12 commits into
Conversation
Gluon (gfx950/CDNA4) DeepSeek-V4 sparse-MLA decode. One kernel serves three KV formats (packed fp8_ds_mla, uniform fp8 pool + kv_scales, bf16) via a UNIFORM constexpr. On gfx950 pa_decode_sparse routes the OCP-fp8 / bf16 uniform pool here; fnuz-fp8 and advanced overrides fall through to triton. The gfx1250 path is unchanged. A cache past buffer_load's 2 GB (int32) offset cap gathers via 64-bit gl.load; smaller caches keep the fast buffer_load path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge the two gfx950 launchers into one private _pa_decode_sparse_gfx950_gluon (cache.ndim dispatch: 3D packed fp8_ds_mla / bf16 block cache, 2D uniform pool; fp8/bf16 from dtype + kv_scales; tuned config inlined). pa_decode_sparse is now the single gfx950 gluon entry for all formats and honors kv_splits and skip_reduce. New keyword-only extra_* args (packed SWA+top-k two-loop) default None and are asserted None off the gfx950 route. The vLLM-compat packed entry stays as a thin shim over the merged driver. The reduce now stores/consumes m in the base-2 exponent domain (row-max * softmax_scale * log2e), matching the triton reduce, so skip_reduce returns partials numerically interchangeable with the triton path (acc/l identical, m same scale). Perf-neutral. Triton/gfx1250 path is byte-identical (verified by diff). All three formats + two-loop + skip_reduce round-trip + kv_splits + >2GB pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
|
Wire it as a literal in _cache_load (buffer_load cache=".cg" / gl.load
cache_modifier=".cg") instead of a gl.constexpr arg. Older gluon (triton 3.6)
fails to lower the constexpr-string form ('str' object has no attribute 'type');
the literal lowers cleanly and keeps the ~1.05-1.30x streaming-load win.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines
+19
to
46
| import math | ||
|
|
||
| import torch | ||
| import triton | ||
|
|
||
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | ||
| _pa_decode_sparse as gluon_pa_decode_sparse, | ||
| ) | ||
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | ||
| _pa_decode_sparse_reduce as gluon_pa_decode_sparse_reduce, | ||
| ) | ||
| from aiter.ops.triton._gluon_kernels.gfx950.attention.pa_decode_sparse import ( | ||
| _pa_decode_sparse as _pa_decode_sparse_gfx950, | ||
| ) | ||
| from aiter.ops.triton._gluon_kernels.gfx950.attention.pa_decode_sparse import ( | ||
| _pa_decode_sparse_reduce as _pa_decode_sparse_reduce_gfx950, | ||
| ) | ||
| from aiter.ops.triton._triton_kernels.attention.pa_decode_sparse import ( | ||
| _pa_decode_sparse as triton_pa_decode_sparse, | ||
| ) | ||
| from aiter.ops.triton._triton_kernels.attention.pa_decode_sparse import ( | ||
| _pa_decode_sparse_reduce as triton_pa_decode_sparse_reduce, | ||
| ) | ||
| from aiter.ops.triton.utils._triton import arch_info | ||
| from aiter.ops.triton.utils.device_info import get_num_sms | ||
| from aiter.ops.triton.utils.logger import AiterTritonLogger | ||
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | ||
| _pa_decode_sparse as gluon_pa_decode_sparse, | ||
| _pa_decode_sparse_reduce as gluon_pa_decode_sparse_reduce, | ||
| ) | ||
|
|
||
| DEVICE_ARCH = arch_info.get_arch() |
Contributor
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
Suggested change
| import math | |
| import torch | |
| import triton | |
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse as gluon_pa_decode_sparse, | |
| ) | |
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse_reduce as gluon_pa_decode_sparse_reduce, | |
| ) | |
| from aiter.ops.triton._gluon_kernels.gfx950.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse as _pa_decode_sparse_gfx950, | |
| ) | |
| from aiter.ops.triton._gluon_kernels.gfx950.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse_reduce as _pa_decode_sparse_reduce_gfx950, | |
| ) | |
| from aiter.ops.triton._triton_kernels.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse as triton_pa_decode_sparse, | |
| ) | |
| from aiter.ops.triton._triton_kernels.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse_reduce as triton_pa_decode_sparse_reduce, | |
| ) | |
| from aiter.ops.triton.utils._triton import arch_info | |
| from aiter.ops.triton.utils.device_info import get_num_sms | |
| from aiter.ops.triton.utils.logger import AiterTritonLogger | |
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse as gluon_pa_decode_sparse, | |
| _pa_decode_sparse_reduce as gluon_pa_decode_sparse_reduce, | |
| ) | |
| DEVICE_ARCH = arch_info.get_arch() | |
| import math | |
| import torch | |
| import triton | |
| from aiter.ops.triton._gluon_kernels.gfx950.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse as _pa_decode_sparse_gfx950, | |
| ) | |
| from aiter.ops.triton._gluon_kernels.gfx950.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse_reduce as _pa_decode_sparse_reduce_gfx950, | |
| ) | |
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse as gluon_pa_decode_sparse, | |
| ) | |
| from aiter.ops.triton._gluon_kernels.gfx1250.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse_reduce as gluon_pa_decode_sparse_reduce, | |
| ) | |
| from aiter.ops.triton._triton_kernels.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse as triton_pa_decode_sparse, | |
| ) | |
| from aiter.ops.triton._triton_kernels.attention.pa_decode_sparse import ( | |
| _pa_decode_sparse_reduce as triton_pa_decode_sparse_reduce, | |
| ) | |
| from aiter.ops.triton.utils._triton import arch_info | |
| from aiter.ops.triton.utils.device_info import get_num_sms | |
| from aiter.ops.triton.utils.logger import AiterTritonLogger | |
| DEVICE_ARCH = arch_info.get_arch() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
gfx950 Paged Sparse Attention for DSV4
fp8 flavors: OCP =
float8_e4m3fn(bias 7, native gfx950 cvt); fnuz =float8_e4m3fnuz(bias 8, no native gfx950 cvt).Gluon supports both on the uniform pool, fnuz is dequanted via bf16 (
float8e4b8 → bf16 → f32, exact and cheap on gfx950; the direct fnuz→f32 path lowers to a software unpack that spills). The triton fallback dequant is dtype-driven.Supported formats & dtypes
pa_decode_sparsepicks the backend from arch + inputs: gfx950 withblock_h=None→ the gluon kernel; otherwise → the shared fallback (the triton kernel, or the gfx1250 gluon kernel on gfx1250). q is bf16/fp16; output is bf16.Since VLLM uses separated SWA and topk storage, the new gluon supports this format as well.
Also, there are 2 different fp8 storage format supported. The uniform path that stores everything in selected fp8 with fp32 scales. While packed format stores rope in bf16, rest in fp8 and has uint8 scales.
main+ top-kextra_*, the vLLM DSv4 layout) is gfx950-gluon + packed only; everything else is single-loop (the gfx950 uniform pool ignoresextra_*; the fallback paths assert itNone).[pages, D/64]fp32kv_scales; packedfp8_ds_mlaembeds a UE8M0 exponent per 64 NoPE channels. DSv4: D=512 (NoPE 448 + RoPE 64), block=256.In detail:
Uniform fp8 pool - 2D
Packed fp8 "fp8_ds_mla" -3D
1. Gluon vs aiter Triton fallback (2D uniform pool) on GFX950
DSv4-Pro config: SWA window 128,
index_topk1024. Cases (tokens/query = SWA + top-k =min(ctx/compress_ratio, 1024)):2. Gluon: format × loop × dtype (fp8 = OCP)
This section shows performance difference between different dtypes and storage formats.
{uniform, packed} × {1-loop, 2-loop} × {fp8, bf16}. 1-loop = SWA+top-k merged into one index/cache; 2-loop = separate SWA (main) + top-k (extra) caches. fp8: uniform = OCP e4m3 + separate fp32 scales; packed = fp8_ds_mla (embedded UE8M0 + RoPE bf16, always OCP).