Skip to content

[jit_kernel] Move JIT kernels into namespace sglang - #33400

Merged
BBuf merged 1 commit into
sgl-project:mainfrom
DarkSharpness:jit-namespace-sglang
Aug 8, 2026
Merged

BBuf merged 1 commit into
sgl-project:mainfrom
DarkSharpness:jit-namespace-sglang

Conversation

@DarkSharpness

@DarkSharpness DarkSharpness commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Generated by Claude.

Motivation

Every JIT kernel used to sit in the global namespace (or an anonymous one), with a handful of files having already started on namespace sglang and reaching back out via using namespace sglang; / sglang::. This unifies that: all JIT C++ under python/sglang/kernels/jit/ now lives in namespace sglang, and no sglang:: qualification is needed anywhere inside it.

Modifications

  • namespace sglang everywhere — device kernels, traits and the host wrapper together, plus the shared include/sgl_kernel/ headers, so host:: / device:: resolve unqualified. 166 C++ files.
  • load_jit emits the export inside the namespace_make_sources wraps TVM_FFI_DLL_EXPORT_TYPED_FUNC in namespace sglang { ... }, so the Python-side kernel_name is written without a prefix (Add3Kernel<...>::launch, not sglang::Add3Kernel<...>::launch).
  • Dropped the reach-arounds — the 5 using namespace sglang; and every redundant sglang::. The sglang_<kernel> pseudo-namespaces under csrc/diffusion/ become real nesting (sglang::norm_scale_shift, sglang::usp_relayout, ...), with the Python wrapper names updated to match.
  • Removed 102 top-level anonymous namespacesnamespace sglang already scopes these names, symbols are not interposed across separately dlopened modules, and each header-only module compiles exactly one root source. One consequence needed handling: gemm/per_token_group_quant.cuh's file-local details became ambiguous with device::details once the anonymous namespace stopped isolating it, so it is now detail.
  • Fixed ::arrive_barrier in gemm/dsv3_fused_a_gemm.cuh — it resolved to global scope while the function moved into namespace sglang. See the note below on why this one was easy to miss.
  • Docs + add-jit-kernel skill note the namespace convention.

Deliberately left at global scope

Files Why
csrc/moe/tvm_ffi_utils.h near-verbatim FlashInfer port, no sgl_kernel dependency
csrc/fast-hadamard-transform/*.h vendored from Tri Dao / sgl-project fork, ditto
csrc/sparse_mla_q8kv8_prefill_sm90/* (7 files) kernel.cuh needs a global using namespace cute; before mid-file #includes of the dense_fp8 headers, which cannot survive wrapping. Only its entry.cuh host wrapper moved in.
csrc/attention/kda_prefill.cu builds via torch.utils.cpp_extension, not load_jit
csrc/moe/expert_specialization/* (4 files) not reachable from any load_jit call — the live path is the AOT twin in aot/csrc/expert_specialization/

Accuracy Tests

All 137 kernel test files were run on 8x B200, one test per GPU across 7 cards.

The sweep caught a real bug. ::arrive_barrier broke test_dsv3_fused_a_gemm (192 failed), and a header-include-only compile did not catch it: nvcc defers lookup of non-dependent names inside template bodies until instantiation. After the fix it is 192 passed. I then scanned every ::identifier in the tree — the rest are genuinely global (cuda*, atomicAdd, min/max/abs, TVMFFI*) or decltype(...)::value false hits.

Multi-GPU (via each file's own torchrun entry point, world sizes <= 6):

Test Result
test_custom_all_reduce --num-gpu 2,4 180 passed each
test_tp_qknorm --num-gpu 2,4 42 passed each
test_symm_mem_all_gather --num-gpu 4,6 48 passed (4-GPU self-skips by design)
kimi_k3/test_collectives --num-gpu 4 4 passed
test_dcp_lse_combine 21 passed

Remaining failures were each re-run against HEAD in a separate worktree and are pre-existing with identical failure sets: test_per_token_group_quant_8bit_v2 (66, JIT-vs-AOT bit-exactness on B200), test_qknorm_rope (1/1249 bf16 rounding), test_dsa_indexer (MockModelRunner missing an attribute), test_kernels_namespace (assert 'CLEAN' in 'DIRTY', local env), test_varlen_uspattn_equivalence (local flash_attn missing flash_attn_varlen_func), and the two CP parity tests (need multi-GPU).

Two pre-existing test failures fixed along the way

Both are B200-only, because the JIT kernel CI runs on H100/H200 and never exercises the Blackwell branch of kMaxVecBytes = SGL_ARCH_BLACKWELL_OR_GREATER ? 32 : 16:

  • test_activation — the (7, 16) / (3, 5, 16) shapes give hidden=8, which the kernel rejects outright when the fp16/bf16 vector is 16 elements wide. Dropped rather than made arch-conditional; every remaining shape is 16-aligned. 24 failed -> 451 passed (97 in CI mode).
  • test_fused_add_rmsnorm — bf16's 1 ulp is 2^-8 ~= 7.8e-3, so rtol=1e-2 expressed only 1.28 ulp while the fp32 reference (which rounds in a different order than the kernel) disagrees by up to 1.75 ulp. The fp32-reference path now uses rtol=1.5e-2, the tightest bound that clears the noise — it still catches a systematic 0.75% deviation, whereas 2e-2 would let 1% through. No cases removed: 2 failed / 558 passed -> 560 passed.

Checklist

  • pre-commit run clean on the diff (incl. pinned clang-format 20.1.7, CI-registry validation)
  • No non-ASCII introduced in C++ sources
  • Namespace braces verified programmatically to sit on the same #if branch in every file

CI States

Latest PR Test (Base): ❌ Run #30927242724
Latest PR Test (Extra): ❌ Run #30927233275

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@github-actions github-actions Bot added documentation Improvements or additions to documentation quant LLM Quantization lora hicache Hierarchical Caching for SGLang jit-kernel labels Aug 3, 2026
All JIT C++ under python/sglang/kernels/jit/ now lives in `namespace sglang`:
device kernels, traits and the host wrapper together, plus the shared
include/sgl_kernel/ headers, so `host::` / `device::` resolve unqualified.

- `load_jit` emits TVM_FFI_DLL_EXPORT_TYPED_FUNC inside the namespace, so the
  Python-side `kernel_name` is written without a `sglang::` prefix.
- Dropped the 5 `using namespace sglang;` and every redundant `sglang::`
  qualification. The `sglang_<kernel>` pseudo-namespaces in csrc/diffusion/
  become real nesting (`sglang::norm_scale_shift`, ...).
- Removed 102 now-redundant top-level anonymous namespaces: `namespace sglang`
  already scopes these names and each header-only module compiles exactly one
  root source.
- Fixed `::arrive_barrier` in gemm/dsv3_fused_a_gemm.cuh, which resolved to
  global scope. nvcc defers lookup of non-dependent names in template bodies
  to instantiation, so a header-include compile did not catch it.

Left at global scope on purpose: near-verbatim vendored ports with no
sgl_kernel dependency (moe/tvm_ffi_utils.h from FlashInfer,
fast-hadamard-transform/, sparse_mla_q8kv8_prefill_sm90/, which needs a global
`using namespace cute;` before mid-file includes), and attention/kda_prefill.cu,
which builds via torch.utils.cpp_extension rather than load_jit.

Two test fixes for pre-existing failures this sweep surfaced on B200:
activation drops the hidden=8 shapes the kernel rejects when kMaxVecBytes is 32,
and fused_add_rmsnorm's fp32-reference path gets rtol=1.5e-2, since bf16's
1 ulp is 2^-8 and rtol=1e-2 could only express 1.28 ulp.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@DarkSharpness

Copy link
Copy Markdown
Collaborator Author

/rerun-failed-ci

@BBuf BBuf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

@BBuf
BBuf merged commit 4ad5bb5 into sgl-project:main Aug 8, 2026
514 of 612 checks passed
b8zhong added a commit that referenced this pull request Aug 8, 2026
…aled-mm

Two upstream changes needed carrying into the JIT port:

- #33469 (scalar scale A support for fp8_gemm) landed in the AOT
  fp8_gemm_kernel.cu that this branch deletes. Ported into the JIT tree:
  JitGemmFp8RowwiseC3x gains a ScalarA parameter selecting
  Sm90ScalarBroadcast over Sm90ColBroadcast (one change here covers SM100
  and SM120, which upstream had to patch separately), the sm100/sm120
  dispatchers branch on scales_a.numel() == 1, SM90 goes back to
  Sm90ColOrScalarBroadcast with its runtime flag, and the entry point
  carries upstream's two validation checks. Its tests come along too.

- #33400 (move JIT kernels into namespace sglang) postdates these files,
  so the seven new fp8_per_tensor headers are now wrapped in
  namespace sglang; without it host:: no longer resolves.

Verified on SM103: 1024 passed, 1 skipped (SM89-only test).
@DarkSharpness
DarkSharpness deleted the jit-namespace-sglang branch August 8, 2026 13:51
Xia-Weiwen pushed a commit to Xia-Weiwen/sglang that referenced this pull request Aug 10, 2026
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
saturn-acc pushed a commit to saturn-acc/sglang that referenced this pull request Aug 16, 2026
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
jakki-amd pushed a commit to jakki-amd/sglang that referenced this pull request Sep 9, 2026
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Atituiset pushed a commit to Atituiset/sglang that referenced this pull request Sep 10, 2026
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation hicache Hierarchical Caching for SGLang jit-kernel lora quant LLM Quantization run-ci

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants