Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
26f56e0 to
9a5fe39
Compare
|
Dear Sir, This is the first author of LiteTopk, Ziqi Yin, I am further working on improve LiteTopk. You can add my wechat ntu_yinziqi or my email ziqi003@e.ntu.edu.sg for further discussion. Best |
9a5fe39 to
2c8cddc
Compare
|
Dear Luo Yuan, We have updated the code to the latest version in the GitHub (https://github.com/Heisenberg-Yin/LiteTopK) , including an updated implementation of LiteTopK and a newly proposed LiteDSA, which achieves a 1.34–1.4× end-to-end prefill speedup on GLM-5.2. The paper on GitHub has also been updated accordingly. The updated accelerate ratio is
Best Regards, |
e1e0cfe to
9016a91
Compare
9016a91 to
ea6e20d
Compare
@Fridge003 Thanks for reminding, I added @Heisenberg-Yin as co-author in all the commits and marked source of LiteTopK. |
ea6e20d to
153e681
Compare
|
Dear all, I’m very glad to have @yuan-luo helping me upstream this method into SGLang. Recently, I’ve been working with him to integrate support for DeepSeek v4 Flash. My latest implementation achieves a 1.4× speedup for GLM-5.2 1M prefill and a 1.25× speedup for DeepSeek v4 Flash on vLLM. Also thanks for your attention to my work and this pr. Best Regards, |
|
Dear all, I have tested the latest performance on sglang. Performance Results
It will be my great honor to work with @yuan-luo to integrate these techniques into SGLang. Best Regards, |
7538c14 to
408e802
Compare
408e802 to
c01a180
Compare
Signed-off-by: Ziqi Yin <ziqi003@e.ntu.edu.sg>
c01a180 to
727e4a0
Compare
Signed-off-by: Ziqi Yin <ziqi003@e.ntu.edu.sg>
Summary
This PR is adapted from vLLM PR vllm-project/vllm#48726.
Credit to Heisenberg-Yin
Adds LiteTopk as an opt-in DSA indexer top-k path for prefill (ragged extend): fp8 MQA scoring (tcgen05 UMMA) + an online bucketed gate + a compact exact top-k, fused into one pass over KV, so the
[num_q, seq_len]logits matrix is never materialized and the memory-budget chunk loop is skipped entirely.Recall is exact by construction. With the per-row affine$b(x) = \lfloor (x - o) \cdot \delta^{-1} \rfloor$ (code: $= o$ , $= \delta^{-1}$ ) over negated scores $x = -\text{score}$ (bucket 0 = best), the scan emits exactly ${, j : b(x_j) \le \text{th} ,}$ , and every refresh recomputes $\text{th}$ from counts of genuine row elements — so it only ever tightens while staying above $b(x_{(k)})$ , the bucket of the true k-th best score:
origininv_deltaA stale threshold therefore admits extra candidates but never drops one, and
selecttrims the superset exactly.In B200, GLM-5.2 tensors, Q=8192, topk=2048, 1.09–1.25× over dense logits + top-k at 256K–1M contexts, with 8–32 GB of transient logits memory removed.
It is opt-in (
SGLANG_ENABLE_DSA_LITETOPK=1), off by default, SM100 (Blackwell) only, GLM DSA shape only (H=32, D=128), and gated to configurations it can serve exactly (num_init_tokens == num_local_tokens == 0); everything else stays on the dense path unchanged, so it adds zero risk to existing deployments.Background: how LiteTopk replaces the dense top-k
The dense prefill path scores all KV into a
[num_q, seq_len]fp32 logits buffer (8–32 GB transient at 256K–1M, forcing a memory-budget chunk loop), then runs top-k over it. LiteTopk streams KV in tiles and keeps only plausible candidates:seed_prep(calibration) — per request, score a bounded KV prefix (min(8192, kv_len)) with the existing densefp8_mqa_logits, and derive per-row bucket-space parameters (origin,inv_delta) plus an initial gate threshold = the bucket of the k-th best sample score. A sample k-th value can only be worse than the true global k-th, so the initial threshold is a valid loose bound.scan— the fused kernel: UMMA-scores each KV tile, folds the per-row bucket affine into the register weights (scores accumulate directly in bucket units), and emits positions whose bucket passes the gate into a compact candidate buffer via warp-local queues. Two spare warps run a threshold-refresh daemon that walks the live bucket histogram and only tightens the gate as real counts accumulate.select— exact top-k over the compact candidates (radix on float bits in bucket space),-1-padded totopk.Modifications
New
python/sglang/jit_kernel/csrc/dsa_litetopk/dsa_indexer_kernels.cuh— the warp-specialized scan kernel (vendored 1:1 from vLLM PR #48726).python/sglang/jit_kernel/csrc/dsa_litetopk/dsa_indexer.cuh—seed_prep/selectkernels, TMA helpers, shape config (vendored).python/sglang/jit_kernel/csrc/dsa_litetopk/entry.cuh— the only sglang-facing layer (TVM-FFI launchers); mirrors the upstream launcher argument order so future syncs stay mechanical.python/sglang/jit_kernel/csrc/dsa_litetopk/vendor_deep_gemm/— minimal vendored DeepGEMM headers (tcgen05 / TMA / UMMA PTX), with the DeepSeek license preserved.python/sglang/jit_kernel/dsa/litetopk.py— Python orchestration: per-request calibration loop, scratch allocation, the three primitive calls.test/registered/jit/test_dsa_litetopk.py— recall tests vs an fp32 torch reference (details below).Modified
python/sglang/srt/layers/attention/dsa/dsa_indexer.py—use_dsa_litetopkgate inIndexer.__init__+_get_topk_ragged_litetopkbranch in_get_topk_ragged.python/sglang/srt/environ.py—SGLANG_ENABLE_DSA_LITETOPK(EnvBool, defaultFalse).sglang deviations
kv[:sample_len]prefix of the gathered buffer — in a multi-request ragged batch that samples positions a row can never attend, which can over-tighten the gate. Here each request samples its own KV prefix with per-row causalke, so thresholds are causally valid by construction.-1index padding (upstream pads0), matching the dense ragged transform contract (fast_topk_transform_ragged_fused) so downstream sparse attention sees the same invalid-slot marker. Output coordinates are identical to the dense path: gathered-KV absolute positions.NUM_SMSfor 1:1 vendoring).inv_deltaexplode, and cross-kernel fp32 accumulation-order noise then spans whole buckets — the gate dropped every candidate. Floor the span atseed_prepreads sample-logits rows with 16 Bfloat4loads; the per-request sample widthmin(sample_len, kv_len)is arbitrary, and any width not a multiple of 4 misaligns every odd row base — a device-side fault upstream never hits (its shared prefix has a fixed width). The wrapper pads the width to a multiple of 4 with-inf(already skipped by every pass'sisfiniteguard), and the entry layer fails loudly on misaligned widths instead of faulting.Implementation notes
selectis exact over the surviving candidates.blockIdx.x= q-block,blockIdx.y= KV window), which keeps all SMs busy on the small-Q chunks long-context prefill actually produces.sm_100aand vendors only the DeepGEMM headers the kernel needs; nothing is added to the AOTsgl-kernelwheel.Validation
Hardware: NVIDIA B200 (SM100), CUDA 13.
Correctness — recall vs an independent fp32 torch reference
test/registered/jit/test_dsa_litetopk.py, registered on the4-gpu-b200CI runner (base-b-kernel-unit). The reference recomputesin fp32 (with$s[j]$ the per-position dequant scale $\geq v_k - \varepsilon$ , and every index scoring $> v_k + \varepsilon$ must be selected (with $v_k$ the k-th best reference score, $\varepsilon = 10^{-3} \cdot \max(|v_k|, 1)$), plus count /
kv_scale); checks are tie-tolerant exactness: every selected index must score-1padding / no-duplicate / causal-validity assertions.[(32, 32768)] @ topk=2048— single long request.[(16, 8192), (16, 24576), (8, 4096)] @ topk=2048— multi-request ragged.[(32, 32768)] @ topk=512.[(8, 1024)] @ topk=2048— short rows: valid < topk →-1padding.[(9, 4099), (5, 1023)] @ topk=512— odd sample widths (float4 alignment regression) + ragged final q-block padding.[(8, 16384)], all-identical K rows): every position ties at the k-th value — worst case for the threshold-bucket boundary and candidate-buffer pressure. Caught the bucket-span bug fixed in the second commit (0 candidates selected pre-fix; count + validity + uniqueness green post-fix).Performance — upstream kernel-level measurement
From the vLLM PR #48726 evaluation (B200, GLM-5.2 tensors, Q=8192, topk=2048), LiteTopk vs dense
fp8_mqa_logits+ top-k: 1.09× / 1.17× / 1.25× at 256K / 512K / 1M context, with the 8–32 GB transient logits allocation removed. sglang-side e2e numbers will accompany the PR that turns the path on by default.Notes
cand_captopk(defaultIndexerboolean, nothing else.CI States
Latest PR Test (Base): ❌ Run #33949270684
Latest PR Test (Extra): ❌ Run #33949270583
Latest PR Test (AMD ROCm 7.2): ❌ Run #33949270696