Add native SM120 and SM121 TopK with PyTorch stable ABI - #2
lucifer1004 wants to merge 4 commits into
Conversation
Compile the host API once and isolate SM100-family and native SM12 CUDA source groups before linking one ABI3 DSO with one operator registration. Keep the PyTorch 2.10 stable ABI, default SM100a/SM103a targets, explicit SM120/SM121 selection, optional PTX, and mandatory artifact spill checks. Add exact native radix selection, streaming K512 selection, and segmented selection with original-index tie breaking and current-stream scratch. Validate device, storage, padding, output strides, aliases, and scalar bounds for both the wrapper and direct operator. Preserve NaN behavior and bound output stores to logical elements. Disable CUB outer-scan memoization to remove generic-sort spills without changing precision or ordering. This changes register/shared-memory trade-offs; no performance speedup or zero-regression claim is made. Carry the cluster gather completion-barrier address repair from deepseek-ai#16, mapping destinations and barriers to CTA0. That upstream PR remains independent; native SM12 does not use the cluster path. Validation of the final full mixed wheel: - 348 kernel instances, all with zero STACK and LOCAL. - SM120: 2763 passed, 198 expected skips, including 104 isolated trap cases and 12 cross-device/device-guard cases. - SM103/B300: 393 shared-contract passes, 4 multi-device skips, plus 180 original-target cases and 48 CPU-oracle cluster calls. - Unfiltered cluster memcheck and racecheck: all 48 calls passed with zero errors, hazards, or warnings; normal CPU-oracle/canary checks passed 10 cases with 2 unsupported BF16-sorted skips under each mode. - SM120 risk-based sanitizer coverage: 19 cases passed each sanitizer, with zero errors, hazards, or warnings; not full-suite sanitizer coverage. - The same wheel ran without rebuilding on Python 3.10 / PyTorch 2.10: 24 CPU checks, 52 exact SM120 CUDA checks, and 31 validation checks, including current streams and changed-input graph replay. Runtime used the final extracted wheel, not an installed/source shadow. Only the README fork/dev clone URL changed afterward; wheel payloads contain no README and compiled code and tests are unchanged. SM121 is compiled and resource-checked, not hardware-qualified. SM100 compilation is not SM100 hardware qualification. vLLM engine consumer integration and matched SM12 performance measurements remain separate. Signed-off-by: Zihua Wu <13583761+lucifer1004@users.noreply.github.com>
16dee33 to
89e9e64
Compare
Signed-off-by: Zihua Wu <13583761+lucifer1004@users.noreply.github.com>
Signed-off-by: Zihua Wu <13583761+lucifer1004@users.noreply.github.com>
Use upstream fast-math and explicit FTZ=false for both kernel families, leaving only gencode selection in the per-family build flags. Restore README byte-for-byte to dev to avoid needless sync conflicts. SM120/121 resources and normalized SASS match the prior build. Actual checker-on wheel build, 15 build tests, 2763 SM120 cases and selected 19-case memcheck/racecheck runs passed. README-only source drift did not change the tested artifact. Signed-off-by: Zihua Wu <13583761+lucifer1004@users.noreply.github.com>
SM120 performance comparison with PyTorch — all 54 casesDeepSelect was faster in 15/54 cases and slower in 39/54. Core BF16 mode A won 4/20, core BF16 mode B 8/20, and the primary FP32 sampling group 0/3. Generic cases contributed the remaining 3 wins out of 6; the boundary case and all 4 supplementary-distribution cases were slower. No cases were discarded. These results do not establish a universal or aggregate speedup. Important slowdowns versus Torch:
Environment and scopeNVIDIA RTX PRO 6000 Blackwell Server Edition, SM120, 188 SMs; Python 3.12.13; PyTorch 2.13.0+cu130, PyTorch CUDA runtime 13.0; installed CUDA toolkit 13.2 (nvcc 13.2.86); NVIDIA driver 595.58.03. Clocks were not forced. PR source revision: This is a DeepSelect-versus-Torch comparison, not a before/after test of the CUB memoization change. It measures finite-input, warm, fixed-input steady-state GPU pipeline latency, not allocation/host overhead or serving throughput. It provides no SM121 hardware performance evidence. DeepSelect's always-on NaN checks remain enabled; this is not equal instruction work. Output contracts and timing
Each CUDA graph contains 20 calls with separate retained outputs. There are 6 newly captured paired rounds in the same process, alternating DeepSelect/Torch then Torch/DeepSelect order. Each implementation has 5 eager warmups and 3 graph warmups per round, followed by 10 CUDA-event samples; each sample is one graph replay's elapsed GPU time divided by 20. Both implementations allocate their outputs during capture and retain those graph-private outputs through replay. Capture, allocation, Python/CPU overhead and correctness checks are excluded from timing. Inputs are fixed across warmups and replays, not a cold-cache workload. Latency columns are the median of the six per-round medians. Speedup is Torch / DeepSelect, summarized as the median of six paired per-round ratios, with their minimum–maximum in parentheses. Above 1× means DeepSelect is faster; below 1× means slower. The ratio of the two displayed latency medians need not equal the reported median paired ratio. All values are rounded to three decimals; narrow ranges can therefore display equal endpoints. These are same-process observations, not independent process trials; the min–max ranges are not confidence intervals. 54/54 pre-timing correctness checks passed. These checked valid, unique indices, gathered-value bit equality when values were returned, sorted order when requested, and exact equality of selected-value multisets against Torch. Ties need not produce identical indices. This does not mean every timed graph replay was revalidated. Primary inputs are normal-distributed; ascending and tie-heavy inputs are separately identified supplementary cases. Complete results
Core A — BF16, normal, unsorted values + int64 indices (20 cases; 4 faster, 16 slower)
Core B — BF16, normal, unsorted int32 indices only (20 cases; 8 faster, 12 slower)
Primary sampling — FP32, normal, sorted values + int64 indices (3 cases; 0 faster, 3 slower)
Generic K coverage — normal, B=4, N=8192 (6 cases; 3 faster, 3 slower)A is unsorted; sampling is sorted. Both return values and int64 indices.
Batch boundary — mode B, BF16, normal (1 case; slower)The B=16 counterpart is already included in core B, not duplicated here.
Supplementary distributions — mode B, BF16, N=65536 (4 cases; 0 faster, 4 slower)
|
Summary
Add native SM120 and SM121 TopK support to the vLLM DeepSelect fork's
devbranch, preserving its PyTorch stable ABI and existing SM100/SM103 backend. This is a DeepSelect library PR, not the vLLM engine integration.torch.ops.deep_select.topk, PyTorch 2.10 stable ABI, CPython ABI3, andTORCH_EXTENSION_NAME-derived initialization for downstream consumers.12.0/12.1and mixed builds, with real optional PTX emission. Default targets remain SM100a/SM103a.Related upstream fix
This PR carries the cluster gather completion-barrier fix from deepseek-ai/DeepSelect#16, which is not yet in the current
devbase. It maps both gather destinations and completion barriers to CTA0. The native SM12 backend does not use this cluster path. The upstream PR is independent and is not closed by this cross-reference.Validation
Standard wheel builds use the existing artifact checker without disabling or weakening its thresholds. Tested builds include SM120-only, SM121-only, SM12 mixed, default SM100/103, and full SM100/103/120/121 mixed. The final full mixed build contains 348 kernel instances, all with zero STACK and LOCAL reported by the checker. An earlier source snapshot was also independently rebuilt from its sdist; that packaging test predates the final cluster-address and zero-width-contract corrections and is not presented as a final-snapshot sdist rebuild.
The wheel remains a single
cp310-abi3extension, with no unexpected undefined ATen/c10/torch C++ imports. Validation loads the actual extracted wheel rather than a source-tree shadow.Final mixed-wheel validation (CUDA toolkit 13.2, driver 595.58.03, PyTorch 2.13.0+cu130, Compute Sanitizer 2026.1.1.0):
Follow-up build cleanup restores upstream setup style and the common
--use_fast_math --ftz=falseflags, leaving only gencode flags architecture-specific. A fresh SM120/SM121 wheel passed the checker (36 kernel instances, zero STACK/LOCAL), all 15 build-plan tests, the 2,763-pass/198-skip SM120 suite and the same 19-case unfiltered memcheck/racecheck selections. SM120/SM121 normalized SASS and resource tables are identical to the preceding no-fast-math build. The earlier full-mixed and minimum-runtime results above retain their original artifact scope; they are not claimed as fresh runs of this follow-up wheel. README now matches the targetdevversion byte-for-byte to minimize future upstream-sync conflicts; it is not part of the wheel payload.SM120 performance versus torch.topk
Complete 54-row results and methodology. Measured on RTX PRO 6000 Blackwell Server Edition (188 SMs), PyTorch 2.13.0+cu130. All 54 pre-timing correctness checks passed. DeepSelect was faster in 15 rows and slower in 39; this does not establish a general speedup.
Speedup below means Torch pipeline latency / DeepSelect latency (>1 favors DeepSelect):
The remaining 11 rows cover generic K1024/4096, the B16→B17 segmented-dispatch boundary, and ascending/tie-heavy distributions. In the boundary case (BF16, width65536, K512, index-only), DeepSelect latency rises from 38.676 µs at B16 to 98.545 µs at B17; the corresponding Torch pipelines take 34.956 and 33.905 µs. Long-row int64 and FP32 sorted paths are also slower and need further optimization.
Timing uses 20 calls per warmed CUDA graph, six alternating paired rounds within one process, and ten CUDA-event samples per round. Reported latencies are medians of round medians; speedups are medians of paired ratios. Allocation during capture, graph construction, CPU validation and input preparation are excluded. Observed ranges are not confidence intervals. Clocks were not forced. This is steady-state GPU pipeline timing, not eager/serving latency or a before/after measurement of the CUB memoization change.
Scope and remaining limitations
Attribution
The input-device/current-stream and vector-boundary safety work builds on upstream #4 and #6 by @morluto. Existing SM100/SM103 algorithms and the fork's stable ABI work are retained.