Skip to content

[Quant] Add EXL3 Trellis backend for rank-sliced GLM/DeepSeek MoE - #139

Closed
brandonmmusic-max wants to merge 19 commits into
local-inference-lab:dev/gilded-gnosisfrom
brandonmmusic-max:exl3-backend
Closed

brandonmmusic-max wants to merge 19 commits into
local-inference-lab:dev/gilded-gnosisfrom
brandonmmusic-max:exl3-backend

Conversation

@brandonmmusic-max

@brandonmmusic-max brandonmmusic-max commented Jul 20, 2026

Copy link
Copy Markdown

Summary

Adds native EXL3 (exllamav3 Trellis) loading and execution to Gilded Gnosis
vLLM. The backend serves native rank-sliced checkpoints without reconstructing
or requantizing routed-expert weights at load time.

The implementation provides:

  • --quantization exl3 detection and tensor-storage parsing
  • dense linear and language-model-head support with a bit-faithful parity path
  • routed MoE execution through Sparkinfer's planned EXL3 Trellis API
  • TP-aware rank-sliced loaders for GLM/DeepSeek fused expert projections
  • CUDA graph compatible custom-op registration and fake implementations
  • per-shard fused/fallback selection with fail-closed validation
  • removal of an unnecessary routed-output copy on the production path

Release validation also exposed target/draft lifetime hazards in DCP speculative
execution. This branch now includes:

  • distinct target and draft PCIe graph channels and communicators
  • DCP-aware draft KV-cache metadata, global top-k mapping, and draft sharding
  • independent target/draft workspace pools with explicit ownership

The Sparkinfer kernel/API dependency is
local-inference-lab/b12x#49.

Rebase and release pins

  • base: dev/gilded-gnosis at 89b4a98d1ffebb2dda1e1ac5e55238e3a9cfbd58
  • PR head: 26c4bfdd3ff2be0433e6fe07e0c3be535f5bb318
  • Sparkinfer head: d4438d490691f79022fdfc8149e1c5f161d15445
  • CUDA 13.2, Torch 2.12, SM120a

The exact validated image is:

verdictai/glm52-exl3-sparkinfer:v26-gg-v20final-scopefix-archkey-vllm5517197-sibe0edca-cu132-sm120a@sha256:2bb9e804a283d1da3b7e3425ff87375121285141d0d0a40d3dc09d41bf881a10

What this rebase actually changed (please review on its merits)

This branch was force-pushed after a rebase onto dev/gilded-gnosis @ 89b4a98d
(previous head 2cb2e085 -> dc0286f). The PR's own diff is the same size
(16 files, +2452/-41) and all 14 commits replayed without conflicts, but this is
not a no-op rebase -- the branch now sits on 20 newer upstream commits, so
the code these edits apply to has moved. Concretely:

  • vllm/v1/attention/backends/mla/indexer.py was modified by both sides.
    Upstream changed it +31/-2 in that span (including the new
    _align_block_table_width), and this PR's use_flattening predicate change
    (and not use_b12x_sparse_indexer()) was auto-merged onto that newer file by
    git rather than re-authored
    . Git reported no conflict because the two hunks are
    ~20 lines apart, but the semantics of the merged result were not human-reviewed --
    this is the single highest-value thing to look at in this rebase.
  • Upstream also moved mla_attention.py, b12x_mla_sparse.py, b12x_attn.py and
    the DCP workspace tests in the same span. Those are not in this PR's diff, but the
    EXL3 Trellis MoE and indexer paths interact with them at runtime, so behavioural
    review of that boundary is welcome.
  • The other 15 files in this PR had no upstream movement in that span and replayed
    unchanged.

For traceability: the EXL3 delta carried by this branch is byte-identical to the
tree the validated v23 image was built from (verified per file against each base --
10 changed lines in deepseek_v2.py, 20 in indexer.py), so the validation results
below correspond to exactly this contribution.

Finalized Gilded Gnosis v20 common base (2026-07-25)

This branch is rebased onto its own base branch for review and merge. It has also
been built and validated as an EXL3 source layer on the finalized v20 common
base. Per the v20 release note the base packages no EXL3/Trellis loader or
kernels, so EXL3 is enabled by rebasing the EXL3 layer onto the pinned stack --
not by pointing the voipmonitor/vllm tag at an EXL3 checkpoint.

  • base image: voipmonitor/vllm:gilded-gnosis-v20-vllm5517197-sibe0edca-fi801d57a-cu132-20260725
  • EXL3 vLLM layer rebased onto vLLM 551719766029e78824a30d97ae6ac63917405b5f
  • EXL3 Sparkinfer layer rebased onto SparkInfer be0edcaae6f5d284bb29a82325aba7a0ead6960f
  • Of the 12 runtime overlay files, only models/deepseek_v2.py and
    v1/attention/backends/mla/indexer.py differ between the previous and the
    finalized v20 tree. Both were re-derived from the v20-final versions with the
    EXL3 edits replayed on top, so the new DCP/indexer/prefill work is preserved
    rather than overwritten by the overlay.

Validated image:

verdictai/glm52-exl3-sparkinfer:v26-gg-v20final-scopefix-archkey-vllm5517197-sibe0edca-cu132-sm120a@sha256:2bb9e804a283d1da3b7e3425ff87375121285141d0d0a40d3dc09d41bf881a10

Runtime validation, 4x RTX PRO 6000 Blackwell (SM120a), TP4/DCP4, MTP-3, NVFP4 DS-MLA KV:

  • engine reports v0.11.2.dev280+gilded.gnosis.v20.vllm5517197.sibe0edca.fi801d57a.cu132.20260725
  • vLLM is using nccl==2.30.4
  • EXL3 planned: Trellis m=1..32 block_m=8, prefill trellis block_m=64 arena=1054.2MiB capacity=3072 chunk=128 topk=8
  • v20 DCP prefill auto-policy resolved for TP4/DCP4 (DCP_*=auto): query split 1,
    full CKV gather 1, top-k owner merge 1, indexer shards 0, CKV prefetch depth 1,
    and DCP_PREFILL_WORKSPACE=1 (VLLM_DCP_PROJECT_BEFORE_MERGE=1 +
    VLLM_B12X_MLA_DCP_GATHER_IN_WORKSPACE=1)
  • Preallocated 30.8 MiB for 2 persistent CKV execution lane(s) and
    Using native CKV layer prefetch with depth=1 and 2 workspace slots
  • GPU KV cache 998,656 tokens (1.90x at 524,288 per request). This is ~1 GiB lower
    than the pre-fix image because the draft model now gets its own rank-sliced
    runtime arena instead of sharing the target's -- the intended cost of the
    target/draft scratch isolation.
  • Estonia c2 x5: 5/5 pass, 0 fail, correct rate 1.00
  • LAVD c5 x5: 3 EXACT / 2 NEAR / 0 FAIL, correct rate 1.00

Earlier images in this series measured LAVD at 2E/3N/0F (pre-fix) and, on one
5-run sample of the first scoped build, 2E/2N/1F; a second sample of that build
returned 2E/3N/0F. The single failure there was a wrong ledger total at 7,114
completion tokens against a 24,576 cap -- an answer-quality miss rather than
truncation, and within this profile's run-to-run spread. This build shows no
failures on either suite.

Note: the base's Loading safetensors using InstantTensor loader assertion does
not appear on this path -- the EXL3 checkpoint is loaded by the EXL3 rank-sliced
loader, not the base InstantTensor path. All other boot assertions hold.

Production validation

Validated on a 332.19 GB GLM-5.2 checkpoint with 256 routed experts and four
RTX PRO 6000 Blackwell 96 GB GPUs.

Validated serving configuration:

  • TP4 + DCP4 A2A
  • MTP1 greedy
  • asynchronous scheduling disabled
  • NVFP4 DeepSeek-MLA KV cache with calibrated outer scales
  • 524,288 logical KV tokens (2,048 blocks x 64 x DCP4)
  • full and piecewise CUDA graphs through concurrency 8
  • all 81 model shards loaded and EXL3 initialized

Correctness and quality:

  • workspace ownership tests: 3 passed
  • exact-image Sparkinfer Trellis tests: 10 passed
  • LAVD: 10/10 twice, 20/20 combined, zero cap hits
  • Estonia: 5/5, zero cap hits
  • five-run, 2,047-position DCP4 KLD:
    • NVFP4: mean 0.1124021, sample SD 0.0025948
    • FP8: mean 0.1036666, sample SD 0.0018374

Exact-image performance:

Test Result
8K / 64K / 128K cold prefill 1,502 / 1,249 / 1,182 tok/s
C1 / C2 / C3 / C4 sustained decode 48.9 / 112.9 / 154.0 / 188.2 aggregate tok/s
C5 / C6 / C7 / C8 sustained decode 218.2 / 239.4 / 253.9 / 266.8 aggregate tok/s

Release constraint

Asynchronous scheduling remains disabled in the published configuration. The
source-level target/draft isolation fixes are necessary, but hardware testing
still showed a quality regression when async retirement overlapped speculative
side-stream work and the module-global CKV gather state. The validated release
therefore uses synchronous scheduling, MTP1, DCP draft sharding enabled, global
top-k enabled, and VLLM_B12X_MLA_SPEC_EXTEND_AS_DECODE=0.

Notes and limits

  • Fused Trellis requires the MCG codebook and compatible K/N alignment;
    unsupported shards fail closed to the parity implementation.
  • The routed-MoE path is performance-validated on SM120a. Other architectures
    retain generic/parity behavior and are not claimed as performance targets.
  • The optional FlashInfer JIT cache step can be skipped when the target wheel
    does not expose a compatible cache builder.
  • The vLLM package banner retains the base build's g60c82d972 string. The
    image's ai.verdict.vllm.revision OCI label records the installed PR head.

CI status

CodeRabbit passes. The repository pre-run gate currently blocks the normal
pre-commit job because it requires a verified, ready, or
ready-run-all-tests label (or four prior merged PRs). None of those labels
exists in the repository, and the contributor token cannot create one, so a
maintainer label/configuration action is required to start that job.

AI assistance disclosure

Implementation, debugging, and documentation were developed with Codex and
Claude Code assistance. The author selected the design, reviewed the changes,
and ran the reported hardware validation.

Summary by CodeRabbit

  • New Features

    • Added EXL3 quantization support for dense, language-model head, and mixture-of-experts layers.
    • Added support for rank-sliced EXL3 checkpoints and compatible weight loading.
    • Docker builds can now optionally skip the FlashInfer JIT cache.
  • Bug Fixes

    • Improved structured-output handling during speculative decoding, including reasoning-marker detection and content trimming.
    • Corrected expert weight routing for quantized checkpoints.
    • Improved DeepSeek attention behavior and sparse-indexer compatibility.
    • Improved checkpoint loading for rank-sliced model weights.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

EXL3 quantization support is added for dense and routed-expert layers, including metadata handling, checkpoint loading, CUDA execution, Trellis dispatch, and tests. Structured-output speculative advancement, DeepSeek attention gating, MLA flattening, and optional Docker cache installation are also updated.

Changes

EXL3 quantization

Layer / File(s) Summary
Configuration and runtime primitives
vllm/model_executor/layers/quantization/exl3.py, vllm/model_executor/layers/quantization/__init__.py, vllm/config/model.py
EXL3 configuration hydration, method registration, metadata validation, lazy extension loading, and the exl3_gemm operator are added.
Linear weights and execution
vllm/model_executor/layers/quantization/exl3.py
Linear EXL3 tensors are registered, validated, sharded, and executed with packed-dimension handling.
Routed-expert execution
vllm/model_executor/layers/quantization/exl3.py
MoE tensors support slab allocation, tensor parallelism, Trellis planning, parity fallback, and explicit expert routing.
Checkpoint loading and MoE routing
vllm/model_executor/models/deepseek_v2.py, vllm/model_executor/models/glm4_moe.py, vllm/model_executor/layers/fused_moe/routed_experts.py
Rank-sliced names are normalized during model loading, and rank-3 per-expert tensors are no longer treated as fused weights.
Validation
tests/quantization/test_exl3.py, tests/quantization/test_exl3_prefill_plan.py
Tests cover EXL3 metadata, checkpoint normalization, expert storage, Trellis plans, environment overrides, and CUDA capture behavior.

Structured-output advancement

Layer / File(s) Summary
Token-aware reasoning advancement
vllm/v1/structured_output/__init__.py, vllm/v1/core/sched/scheduler.py
should_advance consumes generated token deltas and records speculative reasoning boundaries for same-step advancement.
Speculative structured-output tests
tests/v1/structured_output/test_reasoning_structured_output.py
Tests cover reasoning completion, explicit token deltas, and trimming content after the reasoning marker.

DeepSeek attention gating

Layer / File(s) Summary
Indexer and flattening conditions
vllm/models/deepseek_v32/nvidia/attention.py, vllm/v1/attention/backends/mla/indexer.py
Sparse indexer work now requires index_k, and B12X capability-120 execution changes flattening selection.

Build installation control

Layer / File(s) Summary
Optional FlashInfer cache installation
docker/Dockerfile
A build argument conditionally enables FlashInfer JIT cache installation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ModelLoader
  participant Exl3Config
  participant Exl3MoEMethod
  participant SparkinferTrellis
  participant exllamav3_ext
  ModelLoader->>Exl3Config: normalize rank-sliced checkpoint names
  Exl3Config->>Exl3MoEMethod: configure EXL3 MoE tensors
  Exl3MoEMethod->>SparkinferTrellis: plan rank-sliced dispatch
  SparkinferTrellis->>exllamav3_ext: execute Trellis or parity path
  exllamav3_ext-->>Exl3MoEMethod: return routed expert outputs
Loading

Possibly related PRs

Suggested reviewers: lukealonso

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding EXL3 Trellis backend support for rank-sliced GLM/DeepSeek MoE checkpoints.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@vllm/model_executor/layers/quantization/exl3.py`:
- Around line 464-472: The _moe_prefix_is_exl3 method currently hardcodes
projection names, so remapped MoE checkpoints are not detected. Update this
check to use the RoutedExperts layer’s ckpt_gate_proj_name, ckpt_up_proj_name,
and ckpt_down_proj_name values, matching the names consumed by
_validate_codebooks, and thread those names through the method as needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 87dd2ded-af12-4ca3-992c-dad738c0d7be

📥 Commits

Reviewing files that changed from the base of the PR and between 0d1e91b and a846c2d76ad7e5679166d3818abc9aab8ec4a21a.

📒 Files selected for processing (3)
  • vllm/model_executor/layers/fused_moe/routed_experts.py
  • vllm/model_executor/layers/quantization/__init__.py
  • vllm/model_executor/layers/quantization/exl3.py

Comment thread vllm/model_executor/layers/quantization/exl3.py Outdated
@brandonmmusic-max brandonmmusic-max changed the title [Quant] EXL3 (exllamav3 trellis) backend: fused b12x kernel primary, bit-faithful parity fallback [Quant] Add EXL3 Trellis backend for rank-sliced GLM/DeepSeek MoE Jul 22, 2026
@brandonmmusic-max
brandonmmusic-max changed the base branch from dev/fathomless-firmament to dev/gilded-gnosis July 22, 2026 00:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@vllm/v1/worker/workspace.py`:
- Around line 36-43: Update the use_workspace_lane() docstring with Google-style
Args: documentation for lane and a Raises: section documenting the ValueError
for negative lanes, while preserving the existing behavior and explanatory text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1692d79f-0266-4848-898d-b40a56b3e55b

📥 Commits

Reviewing files that changed from the base of the PR and between 207973e and 424f224.

📒 Files selected for processing (9)
  • tests/v1/structured_output/test_reasoning_structured_output.py
  • tests/v1/worker/test_workspace.py
  • vllm/models/deepseek_v32/nvidia/attention.py
  • vllm/v1/core/sched/scheduler.py
  • vllm/v1/structured_output/__init__.py
  • vllm/v1/worker/gpu/model_runner.py
  • vllm/v1/worker/gpu/warmup.py
  • vllm/v1/worker/gpu_worker.py
  • vllm/v1/worker/workspace.py

Comment thread vllm/v1/worker/workspace.py
davidsyoung pushed a commit to davidsyoung/vllm that referenced this pull request Jul 22, 2026
Builds on the rank-sliced EXL3 (ExLlamaV3 trellis) support added in
local-inference-lab#139 by @brandonmusic, paired with the
trellis3_t256 planned MoE from local-inference-lab/b12x#49. No change
to that work's weight loading, formats, or decode path; this commit
only extends its batch dispatch.

The vllm-project#139 backend serves every batch with m > 32 through the eager
exllamav3_ext parity path: fp16-in/fp32-out staging (~25 GB extra HBM
traffic per 4096-token step at GLM-5.2 geometry), python chunk loops,
and one expert re-stream per 128-row chunk. That covers 100% of
prefill, so prefill throughput is capped at ~2.0-2.3k tok/s while the
same weights decode at full speed through the planned Trellis window.

Build a second trellis_moe plan at max_tokens=max_num_batched_tokens
with block_size_m=64 (env VLLM_EXL3_PREFILL_BLOCK_M, allowed
{8,16,32,48,64}) beside the existing decode plan (32/8), and dispatch
three ways in _apply_rank_sliced:

* m in [min, max]      -> decode plan (unchanged)
* max < m <= capacity  -> prefill plan (sparkinfer bind already accepts
                          any tokens in [1, max_tokens]; zero kernel
                          changes needed)
* m < min              -> parity path, whose persistent staging
                          (xh/out32/token_sorted/weight_sorted) shrinks
                          from capacity rows to one chunk while the
                          prefill plan is live (~110 MiB/GPU returned)

VLLM_EXL3_PREFILL_TRELLIS=0 restores the exact single-plan parity
behavior (one-variable serving A/B lever). The parity branch now raises
during CUDA graph capture instead of silently recording eager ext
calls. The prefill arena (~1.05 GiB/GPU at capacity 3072) allocates
during the profile pass, so vLLM's memory profiler sees it and the KV
pool auto-shrinks instead of risking request-time OOM.

Matched A/B serving brandonmusic/GLM-5.2-EXL3-TR3-3.0bpw on the
published verdictai/glm52-exl3-sparkinfer runtime image (4x RTX PRO
6000 Blackwell, TP4/DCP4/MTP3, identical boot geometry, only the
kill-switch flipped, fresh JIT cache both arms; llm_decode_bench
prefill-only, exact /tokenize, C1, 60 s/context):

  ctx    parity   trellis   delta
  8k      2,287     3,742   +63.6%
  32k     2,218     3,557   +60.4%
  64k     2,078     3,381   +62.7%
  128k    1,920     3,032   +57.9%

Decode C1 unchanged-to-better; 57k-token needle retrieval exact.
davidsyoung pushed a commit to davidsyoung/vllm that referenced this pull request Jul 22, 2026
Optional companion to the prefill-plan commit; mocked plan/ext APIs,
no GPU, sparkinfer, or exllamav3_ext required. Covers plan
construction order, the three-way dispatch boundaries, chunk-capped
parity staging, the VLLM_EXL3_PREFILL_TRELLIS=0 kill-switch,
VLLM_EXL3_PREFILL_BLOCK_M override, elastic re-plan above scheduler
capacity, and the parity-path capture guard. Follows the existing
CPU-test pattern of tests/quantization/test_exl3.py from
local-inference-lab#139.
@brandonmmusic-max

brandonmmusic-max commented Jul 22, 2026

Copy link
Copy Markdown
Author

Rebased onto Gilded Gnosis v20 canonical (6722c1d)

Force-pushed a rebase of this PR onto dev/gilded-gnosis 6722c1d (the v20 canonical head). The local GG fixes this branch previously carried are dropped as superseded by canonical — head-major/cuBLAS (#147), graph-resource isolation (#149), same-model draft cap (#155), and the MTP verifier-decode dispatch (#164). What remains on top of v20 is the EXL3-specific work:

  • EXL3 Trellis MoE backend for rank-sliced GLM/DeepSeek routed experts
  • MTP tool-call + DSA-crash fix — the structured-output grammar advances from the authoritative step delta (tool calling engages under speculative decoding), and has_indexer is derived from index_k so MTP draft steps that skip top-k no longer trip the fused-norm-rope assertion
  • Dual-plan Trellis prefill — prefill batches route through the planned Trellis MoE
  • SM120 + B12X flattening fix — MTP next_n>2 uses the native (B, next_n) sparse-indexer path instead of the DeepGEMM next_n<=2 flatten fallback, which had corrupted MTP-3 code generation

Validation (4x RTX PRO 6000 Blackwell 96 GB, TP4/DCP4, MTP-3 greedy, NVFP4 KV, FULL_AND_PIECEWISE cudagraphs)

Test v20 Prior base
Code generation (Python/HTML, temp 0) 94–100% valid — reported ~50% syntax-error symptom eliminated ~50% (reported)
LAVD r10/c5 10/10 (6 exact, 4 near, 0 fail) 8/10 (2 fail)

The LAVD fail count 2 → 0 reflects the v20 canonical MTP fixes plus the flattening fix. Tested image: verdictai/glm52-exl3-sparkinfer:v20-gg6722c1d-si1a88b38-cu132-sm120a.

Re #163: the dual-plan Trellis prefill from #163 is incorporated in this rebase, so #163 can be closed or rebased onto v20 as preferred.
Full results on current base for a full validation sweet a/b for kv cache, set on reasoning high for the PR’s serve.sh, docker compose |Test |nvfp4_ds_mla |fp8 |
|---------------------------|--------------------|--------------------|
|Estonia (133K needle) |PASS 30 / FAIL 0|PASS 30 / FAIL 0|
|LAVD (ledger) |18E/11N/1F — 97%|15E/13N/2F — 93% |
|Hotel-lights (low tier)|15E/15F — 50% |18E/12F — 60% |
|KLD vs BF16 |0.116138 |0.101198 |
|Decode C1 / C8 |87.5 / 308.1 |86.6 / 312.2 |
|Prefill 8k / 128k |2,551 / 1,833 |2,660 / 1,771 |
Full server.sh, docker compose yaml and image and full results. Al run on four in pro 6ks, capped at 300 watts each, so on full workstation or higher power, decode and prefill would be faster. here https://huggingface.co/brandonmusic/GLM-5.2-EXL3-TR3-3.0bpw/blob/main/RELEASE_TEST_SUITE.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@vllm/v1/attention/backends/mla/indexer.py`:
- Around line 399-402: Update the B12X activation condition in the relevant
build path around the sparse-indexer capability check to use the canonical
backend-aware predicate, including attention_config.backend == "B12X_MLA_SPARSE"
when the environment variable is unset. Preserve the existing SM120 and next_n
behavior while ensuring the native (B, next_n) path remains disabled for all
supported B12X configurations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e1796822-6dd0-4a09-a332-cead2920cc76

📥 Commits

Reviewing files that changed from the base of the PR and between 2fdc6d3 and 31ff5a2a4c036f6f2b28658fd4d42c4537611c35.

📒 Files selected for processing (14)
  • docker/Dockerfile
  • tests/quantization/test_exl3.py
  • tests/quantization/test_exl3_prefill_plan.py
  • tests/v1/structured_output/test_reasoning_structured_output.py
  • vllm/config/model.py
  • vllm/model_executor/layers/fused_moe/routed_experts.py
  • vllm/model_executor/layers/quantization/__init__.py
  • vllm/model_executor/layers/quantization/exl3.py
  • vllm/model_executor/models/deepseek_v2.py
  • vllm/model_executor/models/glm4_moe.py
  • vllm/models/deepseek_v32/nvidia/attention.py
  • vllm/v1/attention/backends/mla/indexer.py
  • vllm/v1/core/sched/scheduler.py
  • vllm/v1/structured_output/__init__.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • vllm/v1/core/sched/scheduler.py
  • vllm/model_executor/layers/fused_moe/routed_experts.py
  • vllm/model_executor/layers/quantization/init.py
  • vllm/models/deepseek_v32/nvidia/attention.py
  • vllm/v1/structured_output/init.py

Comment thread vllm/v1/attention/backends/mla/indexer.py Outdated
@brandonmmusic-max

Copy link
Copy Markdown
Author

Credit goes to davidsyoung for prefill improvement

@davidsyoung

Copy link
Copy Markdown

Note on the incorporated prefill work (cross-ref #163):

As of the v20 rebase, this branch carries the dual-plan Trellis prefill dispatch verbatim from #163:

so reviewing/merging this PR covers that change completely. #163 stays open only as the isolated review scope against the pre-rebase base (2fdc6d3676); it collapses to an empty diff once this merges and I'll close it then.

Validation data for the incorporated change, measured on the pre-v20 stack (pinned digest verdictai/glm52-exl3-sparkinfer@sha256:01e8eec4… + the #163 overlay), TP4/DCP4, 4× RTX PRO 6000 Blackwell:

  • prefill 8k/32k/64k/128k: 2,287/2,218/2,078/1,920 → 3,742/3,557/3,381/3,032 tok/s (+58–64%), decode C1 unchanged
  • long-context retrieval on the same stack: 9/9 exact needles at 162K/190K/241K prompt tokens × depths 0.30/0.60/0.93

The public test image I published earlier (davidyoung/glm52-exl3-sparkinfer:v1-prefill-trellis-plan-20260722) predates this rebase and 31ff5a2a4 (the use_flattening next_n>2 MTP fix) — treat it as superseded for testing once the v20-based image is up. We serve MTP3 (next_n=3), so we'll revalidate tool-calling + decode on the new image and report back.

@brandonmmusic-max

Copy link
Copy Markdown
Author

@coderabbitai review

Fixes are in — the flattening gate now uses the canonical backend-aware use_b12x_sparse_indexer() predicate (6a1a9f9b3a), so --attention-backend B12X_MLA_SPARSE is honored with or without the env var. Done with changes; please re-verify.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Target module outline =="
ast-grep outline vllm/v1/attention/backends/mla/indexer.py --items all --type class,function --view expanded || true

echo
echo "== Targeted flattening gate and imports =="
rg -n -C 12 'use_b12x_sparse_indexer|use_flattening|B12X_MLA_SPARSE|VLLM_USE_B12X_SPARSE_INDEXER' \
  vllm/v1/attention/backends/mla/indexer.py

echo
echo "== Predicate definition and call sites =="
rg -n -C 8 'def use_b12x_sparse_indexer\b|use_b12x_sparse_indexer\s*\(' vllm --glob '*.py'

echo
echo "== Current PR diff for the relevant module =="
git diff --unified=40 'HEAD^' -- vllm/v1/attention/backends/mla/indexer.py

echo
echo "== Reported commit diff (when present in local history) =="
git show --format=fuller --stat --oneline 6a1a9f9b3a -- vllm/v1/attention/backends/mla/indexer.py || true
git show --format= --unified=40 6a1a9f9b3a -- vllm/v1/attention/backends/mla/indexer.py || true

Length of output: 43841


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== B12X request-detection implementation =="
sed -n '600,665p' vllm/model_executor/layers/sparse_attn_indexer.py

echo
echo "== Backend configuration symbols and B12X selection references =="
rg -n -C 6 'B12X_MLA_SPARSE|_b12x_sparse_indexer_requested|attention_backend' \
  vllm/model_executor/layers/sparse_attn_indexer.py \
  vllm/v1/attention/backends/mla/indexer.py \
  vllm --glob '*.py'

echo
echo "== Direct env-gated B12X branches in the metadata builder =="
sed -n '600,665p' vllm/v1/attention/backends/mla/indexer.py
sed -n '750,805p' vllm/v1/attention/backends/mla/indexer.py
sed -n '910,955p' vllm/v1/attention/backends/mla/indexer.py
sed -n '1080,1145p' vllm/v1/attention/backends/mla/indexer.py

echo
echo "== Existing focused tests for B12X flattening/backend selection =="
rg -n -C 5 'use_flattening|use_b12x_sparse_indexer|B12X_MLA_SPARSE|next_n' \
  tests --glob '*.py' | head -n 300

Length of output: 142171


@brandonmmusic-max Re-verified. The flattening gate now correctly uses use_b12x_sparse_indexer(), whose request detection recognizes both the environment setting and explicit B12X_MLA_SPARSE backend selection (including enum and string forms), while enforcing the CUDA/SM120 requirement.

Thus, with --attention-backend B12X_MLA_SPARSE and next_n > 2, use_flattening remains disabled even when VLLM_USE_B12X_SPARSE_INDEXER is unset. The reported issue is addressed. I did not run CUDA tests in this sandbox.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@brandonmmusic-max

Copy link
Copy Markdown
Author

Validation — rank-sliced tr3 MTP layer now loads & serves

The two fixes in 2cb2e08 let the MTP draft head load a rank-sliced EXL3 (hybrid_tr3_tail) MoE layer. Reproduced end-to-end on 4× RTX PRO 6000 (SM120, TP4/DCP4, MTP-3) with a tr3-converted MTP layer-78 head merged into GLM-5.2-EXL3-TR3-3.0bpw.

Image: verdictai/glm52-exl3-sparkinfer:v21-mtp78tr3-gg6722c1d-si1a88b38-cu132-sm120a (sha256:9b1befc1…)

Runtime note: a tr3 MTP layer also needs VLLM_EXL3_TRELLIS_MIN_M=1 so the MTP-N draft's small-m (m=1…N) GEMMs stay inside the Trellis cudagraph decode window; the default 4 raises EXL3 eager parity path entered during CUDA graph capture (m=3).

Load

Clean load, MTP-3 active. Before the fixes: KeyError: model.layers.78.mtp_block.mlp.experts.routed_experts.w2_rank0.mcg.

Throughput (gpu-util 0.96, auto-profiled KV)

  • KV cache: 1,132,544 tokens, max concurrency 2.16× @ 524K ctx — vs ~680K / ~1.3× with the BF16 MTP head (the tr3 head frees ~3.9 GiB/rank).
  • Prefill (C=1): 8k 2,521 / 64k 1,916 / 128k 1,765 tok/s.
  • Decode C1–C8: 89.7 / 152.6 / 183.8 / 225.3 / 238.0 / 271.9 / 278.6 / 293.5 tok/s.

Accuracy (unchanged — MTP is lossless)

  • Estonia (133K retrieval, c2×10): PASS 10/10.
  • LAVD (ledger consistency, c5×10): EXACT 5 / NEAR 5 / FAIL 0.

@brandonmmusic-max

brandonmmusic-max commented Jul 25, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

Correcting my earlier wording on this comment, which understated the change and could have led to a shallower review.

This branch was rebased onto dev/gilded-gnosis @ 89b4a98d (head dc0286f) for the finalized Gilded Gnosis v20 base. The PR's own diff is the same size (16 files, +2452/-41), but the branch was replayed onto 20 newer upstream commits, so the code this PR's edits sit on top of has changed. Specifically:

  • vllm/v1/attention/backends/mla/indexer.py was modified by both sides. Upstream changed it +31/-2 in that span (including the new _align_block_table_width), and this PR's use_flattening predicate change (and not use_b12x_sparse_indexer()) was auto-merged onto that newer version by git rather than re-authored. That auto-merge is the main thing worth a careful look.
  • Upstream also moved mla_attention.py, b12x_mla_sparse.py, b12x_attn.py and the DCP workspace tests in the same span. Those are not in this PR's diff, but the EXL3 MoE/indexer paths interact with them at runtime.

So please review the rebased state on its merits rather than assuming a no-op rebase — particularly the indexer auto-merge and any interaction between the EXL3 Trellis path and the newer DCP/prefill work.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

@brandonmmusic-max I’ll review the rebased PR state against dev/gilded-gnosis at dc0286f, with particular attention to rebase conflicts and interactions with the finalized v20 base.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@brandonmmusic-max

brandonmmusic-max commented Jul 25, 2026

Copy link
Copy Markdown
Author

Rebased for the finalized Gilded Gnosis v20 base

Force-pushed exl3-backend — rebased onto dev/gilded-gnosis @ 89b4a98d, new head dc0286f (was 2cb2e085).

Diff size is unchanged (16 files, +2452/-41) and all 14 commits replayed without conflicts — but this is not a no-op rebase: the branch now sits on 20 newer upstream commits. In particular vllm/v1/attention/backends/mla/indexer.py was changed by both sides (upstream +31/-2 in that span, adding _align_block_table_width), so this PR'''s use_flattening predicate was auto-merged onto the newer file by git rather than re-authored. Upstream also moved mla_attention.py, b12x_mla_sparse.py and b12x_attn.py in the same span, which the EXL3 indexer/MoE paths touch at runtime.

Also validated against the finalized v20 common base

Per the v20 release note, EXL3 is enabled by rebasing the EXL3 source layer onto the pinned stack (the base ships no EXL3/Trellis loader), not by pointing the base tag at an EXL3 checkpoint. So in addition to the branch above, the EXL3 layer was rebased onto the v20-final pins and built:

Of the 12 runtime overlay files, only models/deepseek_v2.py and v1/attention/backends/mla/indexer.py changed in the finalized base. Both were re-derived from the v20-final versions with the EXL3 edits replayed on top, so v20's new DCP/indexer/prefill work is preserved rather than overwritten by the overlay — verified by diffing each against the v20-final tree (they differ by exactly the 10- and 20-line EXL3 additions and nothing else).

Validated image:

verdictai/glm52-exl3-sparkinfer:v23-gg-v20final-vllm5517197-sibe0edca-cu132-sm120a@sha256:da185fe8bd71f5dee866e651695b1265f05338fc467394fcd75585d78ea20c15

Runtime validation (4x RTX PRO 6000 Blackwell SM120a, TP4/DCP4, MTP-3, NVFP4 DS-MLA KV)

  • engine reports v0.11.2.dev280+gilded.gnosis.v20.vllm5517197.sibe0edca.fi801d57a.cu132.20260725
  • vLLM is using nccl==2.30.4
  • EXL3 rank-sliced runtime planned: Trellis m=1..32 block_m=8, prefill trellis block_m=64 arena=1054.2MiB capacity=3072 chunk=128 topk=8
  • v20 DCP prefill auto-policy resolved for TP4/DCP4: query split 1, full CKV gather 1, top-k owner merge 1, indexer shards 0, CKV prefetch depth 1, DCP_PREFILL_WORKSPACE=1 (VLLM_DCP_PROJECT_BEFORE_MERGE=1 + VLLM_B12X_MLA_DCP_GATHER_IN_WORKSPACE=1)
  • Preallocated 30.8 MiB for 2 persistent CKV execution lane(s), Using native CKV layer prefetch with depth=1 and 2 workspace slots
  • GPU KV cache 1,115,904 tokens (2.13x at 524,288 per request)
  • Estonia c2 x5: 5/5 pass, 0 fail. LAVD c5 x5: 2 EXACT / 3 NEAR / 0 FAIL. Correct rate 1.00 on both — no regression.

Two notes for the runtime side:

  1. This EXL3 preset invokes vllm serve directly for the EXL3 flags, so it bypasses /usr/local/bin/serve-gilded-gnosis.sh and DCP_*=auto never resolves. The resolved TP4/DCP4 values are now set explicitly in serve.sh / docker-compose.yml (pulled from the launcher via DRY_RUN=1). Worth calling out in the Compose contract for direct-serve integrations.
  2. Loading safetensors using InstantTensor loader does not appear on this path — the EXL3 checkpoint loads through the EXL3 rank-sliced loader. All other boot assertions hold.

@brandonmmusic-max

brandonmmusic-max commented Jul 25, 2026

Copy link
Copy Markdown
Author

One CI note: pre-run-check is failing on this PR with

PR must have the 'verified', 'ready', or 'ready-run-all-tests' label
(the ready labels also trigger tests) or the author must have at least
4 merged PRs (found 1).

This is the repo's label gate rather than anything in the diff — it was already failing on the previous head (2cb2e085) before today's rebase, so it is pre-existing and not introduced by the rebase. I only have pull access here, so I can't apply the label myself.

Also noting CodeRabbit reports Review rate limited on this PR, which is why it has not re-reviewed the rebased code yet.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== PR/base topology and changed files =="
git status --short
git branch --show-current
git merge-base HEAD origin/dev/gilded-gnosis || true
git diff --stat "$(git merge-base HEAD origin/dev/gilded-gnosis)" HEAD
git diff --name-status "$(git merge-base HEAD origin/dev/gilded-gnosis)" HEAD

echo
echo "== Target module structure =="
ast-grep outline vllm/v1/attention/backends/mla/indexer.py --items all --type class,function --view expanded
ast-grep outline vllm/model_executor/layers/quantization/exl3.py --items all --type class,function --view expanded
for f in mla_attention.py b12x_mla_sparse.py b12x_attn.py; do
  fd -a -t f "^${f}$" vllm -x ast-grep outline {} --items all --type class,function --view expanded \;
done

echo
echo "== PR diff: indexer auto-merge target =="
base="$(git merge-base HEAD origin/dev/gilded-gnosis)"
git diff --unified=60 "$base" HEAD -- vllm/v1/attention/backends/mla/indexer.py

echo
echo "== Current flattening/alignment context and B12X predicate =="
rg -n -C 18 '_align_block_table_width|use_flattening|use_b12x_sparse_indexer|next_n' \
  vllm/v1/attention/backends/mla/indexer.py \
  vllm/model_executor/layers/sparse_attn_indexer.py

echo
echo "== EXL3 rank-sliced planning, capture, DCP/prefill, and workspace references =="
rg -n -C 10 'rank_sliced|_apply_rank_sliced|prefill|plan|capture|workspace|dcp|DCP|block_m|Trellis' \
  vllm/model_executor/layers/quantization/exl3.py \
  vllm/model_executor/models/deepseek_v2.py \
  vllm/model_executor/models/glm4_moe.py \
  vllm/v1/attention/backends/mla/indexer.py \
  vllm/v1/attention/backends/mla \
  --glob '*.py'

echo
echo "== Focused test coverage and current diff for relevant tests =="
rg -n -C 8 'align_block_table|use_flattening|use_b12x_sparse_indexer|rank_sliced|prefill.*trellis|Trellis|DCP' \
  tests --glob '*.py'
git diff --unified=30 "$base" HEAD -- \
  tests/quantization/test_exl3.py \
  tests/quantization/test_exl3_prefill_plan.py \
  vllm/model_executor/layers/quantization/exl3.py

Length of output: 2675


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Available repository refs and remotes =="
git remote -v
git branch -a
git show -s --format='HEAD %H%nparents %P%nsubject %s' HEAD
git for-each-ref --format='%(refname:short) %(objectname) %(subject)' \
  refs/heads refs/remotes | head -n 200

echo
echo "== Pull request metadata =="
gh pr view 139 --repo local-inference-lab/vllm \
  --json number,headRefName,headRefOid,baseRefName,baseRefOid,mergeStateStatus \
  || true

echo
echo "== Resolve a usable comparison base and inspect rebase-sensitive paths =="
base=""
for candidate in \
  "origin/dev/gilded-gnosis" \
  "dev/gilded-gnosis" \
  "origin/89b4a98d" \
  "89b4a98d"; do
  if git rev-parse --verify --quiet "${candidate}^{commit}" >/dev/null; then
    base="$(git merge-base HEAD "$candidate")"
    echo "Resolved candidate: $candidate -> merge base: $base"
    break
  fi
done

if [ -z "$base" ]; then
  echo "No local base ref was found; showing HEAD source context without a diff."
else
  echo "== Changed files and relevant PR diffs =="
  git diff --stat "$base" HEAD
  git diff --name-status "$base" HEAD
  git diff --unified=60 "$base" HEAD -- \
    vllm/v1/attention/backends/mla/indexer.py \
    vllm/model_executor/layers/quantization/exl3.py \
    tests/quantization/test_exl3.py \
    tests/quantization/test_exl3_prefill_plan.py
fi

echo
echo "== Module maps =="
ast-grep outline vllm/v1/attention/backends/mla/indexer.py --items all --type class,function --view expanded
ast-grep outline vllm/model_executor/layers/quantization/exl3.py --items all --type class,function --view expanded

echo
echo "== Current indexer alignment/flattening and B12X detection =="
rg -n -C 20 '_align_block_table_width|use_flattening|use_b12x_sparse_indexer|next_n' \
  vllm/v1/attention/backends/mla/indexer.py \
  vllm/model_executor/layers/sparse_attn_indexer.py

echo
echo "== EXL3 planned dispatch, capture safety, DCP and workspace interactions =="
rg -n -C 12 'def _apply_rank_sliced|def process_weights_after_loading|def apply\(|prefill|capture|workspace|DCP|dcp|plan|block_m|trellis' \
  vllm/model_executor/layers/quantization/exl3.py \
  vllm/v1/attention/backends/mla \
  --glob '*.py'

echo
echo "== Relevant test definitions and assertions =="
rg -n -C 8 'def test_.*(flatten|align|b12x|rank_sliced|prefill|capture)|use_flattening|_align_block_table_width|_apply_rank_sliced' \
  tests --glob '*.py'

Length of output: 202941


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== GitHub PR base/head and changed-file list =="
gh api repos/local-inference-lab/vllm/pulls/139 \
  --jq '{base: (.base.ref + "@" + .base.sha), head: (.head.ref + "@" + .head.sha), mergeable: .mergeable, changed_files: .changed_files}'
gh api --paginate repos/local-inference-lab/vllm/pulls/139/files \
  --jq '.[] | [.filename, .status, .additions, .deletions] | `@tsv`'

echo
echo "== Local commits and all available parent diff summaries =="
git show -s --format='HEAD=%H%nparents=%P%nsubject=%s' HEAD
git log --oneline -n 20
git diff --stat HEAD^ HEAD

echo
echo "== Current indexer: imports, alignment helper, and flattening gate =="
rg -n '^(def _align_block_table_width|class DeepseekV32IndexerMetadataBuilder|    def |from .*sparse_attn_indexer import|import .*sparse_attn_indexer)' \
  vllm/v1/attention/backends/mla/indexer.py
sed -n '1,110p' vllm/v1/attention/backends/mla/indexer.py
sed -n '600,700p' vllm/v1/attention/backends/mla/indexer.py
sed -n '730,830p' vllm/v1/attention/backends/mla/indexer.py
sed -n '1080,1165p' vllm/v1/attention/backends/mla/indexer.py

echo
echo "== Current B12X request predicate =="
rg -n -C 15 'def use_b12x_sparse_indexer|def _b12x_sparse_indexer_requested|B12X_MLA_SPARSE' \
  vllm/model_executor/layers/sparse_attn_indexer.py

echo
echo "== EXL3 rank-sliced method boundaries =="
rg -n '^\s*def (_apply_rank_sliced|_ensure_rank_sliced|_plan|_get|apply|process_weights_after_loading)|^\s*class Exl3MoEMethod' \
  vllm/model_executor/layers/quantization/exl3.py
rg -n -C 14 'def _apply_rank_sliced|is_current_stream_capturing|capture|prefill_plan|decode_plan|workspace|bind\(' \
  vllm/model_executor/layers/quantization/exl3.py

echo
echo "== Exact PR patches from GitHub for the relevant files =="
for path in \
  vllm/v1/attention/backends/mla/indexer.py \
  vllm/model_executor/layers/quantization/exl3.py \
  tests/quantization/test_exl3_prefill_plan.py \
  tests/quantization/test_exl3.py; do
  echo "--- $path ---"
  gh api "repos/local-inference-lab/vllm/pulls/139/files?per_page=100" \
    --jq ".[] | select(.filename == \"$path\") | .patch" \
    | sed -n '1,260p'
done

Length of output: 59085


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Indexer constructor: final auto-merged context =="
sed -n '337,450p' vllm/v1/attention/backends/mla/indexer.py

echo
echo "== Indexer alignment use sites and focused regression test =="
rg -n -C 10 '_align_block_table_width' \
  vllm/v1/attention/backends/mla/indexer.py \
  tests/model_executor/layers/test_sparse_attn_indexer_b12x.py
sed -n '1088,1165p' tests/model_executor/layers/test_sparse_attn_indexer_b12x.py

echo
echo "== EXL3 runtime cache key, plan allocation, and all binding paths =="
sed -n '1325,1575p' vllm/model_executor/layers/quantization/exl3.py
sed -n '1570,1708p' vllm/model_executor/layers/quantization/exl3.py
rg -n -C 6 '_RANK_SLICED_RUNTIMES|exl3_trellis_weights|exl3_pointer_tables|exl3_expert_map' \
  vllm/model_executor/layers/quantization/exl3.py

echo
echo "== Final MTP-layer loading patch and supporting weight-name/model loading paths =="
git diff --unified=50 HEAD^ HEAD -- \
  vllm/model_executor/models/deepseek_mtp.py \
  vllm/model_executor/models/utils.py
rg -n -C 12 'normalize_rank_sliced_weight_name|mtp_block|load_weights' \
  vllm/model_executor/models/deepseek_mtp.py \
  vllm/model_executor/models/deepseek_v2.py \
  vllm/model_executor/models/glm4_moe.py \
  vllm/model_executor/models/utils.py

echo
echo "== Test collection references for target/draft resource separation and EXL3 MTP loading =="
rg -n -C 5 'target.*draft|draft.*target|rank.sliced|hybrid_tr3_tail|mtp_block|_RANK_SLICED_RUNTIMES' \
  tests/quantization/test_exl3.py \
  tests/quantization/test_exl3_prefill_plan.py \
  tests/model_executor \
  --glob '*.py' | head -n 600

Length of output: 96012


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Line-numbered EXL3 runtime key and mutable buffers =="
nl -ba vllm/model_executor/layers/quantization/exl3.py | sed -n '1355,1665p'

echo
echo "== All cache lifecycle/ownership references =="
rg -n -C 10 '_RANK_SLICED_RUNTIMES|rank_sliced_runtime|trellis_scratch|prefill_scratch|token_sorted|expert_count' \
  vllm tests --glob '*.py'

echo
echo "== Existing model/draft execution and graph resource isolation hooks =="
rg -n -C 8 'draft.*(workspace|scratch|graph|capture)|target.*(workspace|scratch|graph|capture)|(workspace|scratch|graph|capture).*draft' \
  vllm tests --glob '*.py' | head -n 800

Length of output: 1042


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Line-numbered EXL3 runtime key and mutable-buffer use =="
awk 'NR >= 1355 && NR <= 1665 { printf "%6d  %s\n", NR, $0 }' \
  vllm/model_executor/layers/quantization/exl3.py

echo
echo "== Cache lifecycle and ownership tests (bounded) =="
rg -n -C 8 '_RANK_SLICED_RUNTIMES|rank_sliced_runtime|trellis_scratch|prefill_scratch|token_sorted|expert_count' \
  vllm/model_executor/layers/quantization/exl3.py \
  tests/quantization \
  tests/model_executor \
  --glob '*.py' | head -n 500

echo
echo "== Target/draft graph-resource isolation mechanisms relevant to this runtime =="
rg -n -C 6 'draft.*(workspace|scratch|graph|capture)|target.*(workspace|scratch|graph|capture)|(workspace|scratch|graph|capture).*draft' \
  vllm/v1 \
  vllm/model_executor \
  tests/model_executor \
  tests/distributed \
  --glob '*.py' | head -n 500

Length of output: 82057


@brandonmmusic-max I reviewed the rebased state against 89b4a98d.

The indexer.py auto-merge looks correct: it preserves the upstream _align_block_table_width allocation/stride fix and its regression test, while the new use_flattening condition uses the canonical backend-aware B12X predicate. Thus, explicit B12X_MLA_SPARSE selection retains the native (B, next_n) MTP path even without the environment flag.

I found one issue in the EXL3 runtime integration:

  • vllm/model_executor/layers/quantization/exl3.py, Line 1387: _RANK_SLICED_RUNTIMES is module-global and its cache key contains only device, shape, and planner settings—not the RoutedExperts layer/model identity. The cached value includes mutable Trellis scratch buffers (Lines 1475–1477, passed to bind at Lines 1580–1604) as well as mutable parity staging/sort buffers (Lines 1485–1534, mutated at Lines 1620–1673).

    A target MoE layer and rank-sliced MTP draft layer with matching dimensions therefore reuse the same runtime entry and scratch allocations. This defeats the target/draft resource isolation needed for their independently captured graphs; shared scratch can make graph lifetime/execution depend on the other model.

    Please scope the runtime to its owning layer/model—e.g., make it layer-owned, or include a stable layer/weight-storage identity in the key—and add a regression test that creates two same-shape layers and verifies their runtime/scratch objects are distinct.

I did not run CUDA tests in this sandbox.

@voipmonitor

Copy link
Copy Markdown

Superseded by #190. The original head fork rejects maintainer pushes despite maintainerCanModify=true, so the implementation was replayed on the current dev/gilded-gnosis head in a clean branch while preserving original commit authorship. #190 drops the unrelated Dockerfile change, updates the stale Trellis-capacity test to the fail-closed runtime contract, and passes the focused EXL3 unit suite (15/15).

voipmonitor pushed a commit to voipmonitor/vllm that referenced this pull request Jul 29, 2026
Builds on the rank-sliced EXL3 (ExLlamaV3 trellis) support added in
local-inference-lab#139 by @brandonmusic, paired with the
trellis3_t256 planned MoE from local-inference-lab/b12x#49. No change
to that work's weight loading, formats, or decode path; this commit
only extends its batch dispatch.

The vllm-project#139 backend serves every batch with m > 32 through the eager
exllamav3_ext parity path: fp16-in/fp32-out staging (~25 GB extra HBM
traffic per 4096-token step at GLM-5.2 geometry), python chunk loops,
and one expert re-stream per 128-row chunk. That covers 100% of
prefill, so prefill throughput is capped at ~2.0-2.3k tok/s while the
same weights decode at full speed through the planned Trellis window.

Build a second trellis_moe plan at max_tokens=max_num_batched_tokens
with block_size_m=64 (env VLLM_EXL3_PREFILL_BLOCK_M, allowed
{8,16,32,48,64}) beside the existing decode plan (32/8), and dispatch
three ways in _apply_rank_sliced:

* m in [min, max]      -> decode plan (unchanged)
* max < m <= capacity  -> prefill plan (sparkinfer bind already accepts
                          any tokens in [1, max_tokens]; zero kernel
                          changes needed)
* m < min              -> parity path, whose persistent staging
                          (xh/out32/token_sorted/weight_sorted) shrinks
                          from capacity rows to one chunk while the
                          prefill plan is live (~110 MiB/GPU returned)

VLLM_EXL3_PREFILL_TRELLIS=0 restores the exact single-plan parity
behavior (one-variable serving A/B lever). The parity branch now raises
during CUDA graph capture instead of silently recording eager ext
calls. The prefill arena (~1.05 GiB/GPU at capacity 3072) allocates
during the profile pass, so vLLM's memory profiler sees it and the KV
pool auto-shrinks instead of risking request-time OOM.

Matched A/B serving brandonmusic/GLM-5.2-EXL3-TR3-3.0bpw on the
published verdictai/glm52-exl3-sparkinfer runtime image (4x RTX PRO
6000 Blackwell, TP4/DCP4/MTP3, identical boot geometry, only the
kill-switch flipped, fresh JIT cache both arms; llm_decode_bench
prefill-only, exact /tokenize, C1, 60 s/context):

  ctx    parity   trellis   delta
  8k      2,287     3,742   +63.6%
  32k     2,218     3,557   +60.4%
  64k     2,078     3,381   +62.7%
  128k    1,920     3,032   +57.9%

Decode C1 unchanged-to-better; 57k-token needle retrieval exact.

(cherry picked from commit d57d775)
voipmonitor pushed a commit to voipmonitor/vllm that referenced this pull request Jul 29, 2026
Optional companion to the prefill-plan commit; mocked plan/ext APIs,
no GPU, sparkinfer, or exllamav3_ext required. Covers plan
construction order, the three-way dispatch boundaries, chunk-capped
parity staging, the VLLM_EXL3_PREFILL_TRELLIS=0 kill-switch,
VLLM_EXL3_PREFILL_BLOCK_M override, elastic re-plan above scheduler
capacity, and the parity-path capture guard. Follows the existing
CPU-test pattern of tests/quantization/test_exl3.py from
local-inference-lab#139.

(cherry picked from commit f80a56d)
lukealonso pushed a commit that referenced this pull request Jul 30, 2026
Builds on the rank-sliced EXL3 (ExLlamaV3 trellis) support added in
#139 by @brandonmusic, paired with the
trellis3_t256 planned MoE from local-inference-lab/b12x#49. No change
to that work's weight loading, formats, or decode path; this commit
only extends its batch dispatch.

The #139 backend serves every batch with m > 32 through the eager
exllamav3_ext parity path: fp16-in/fp32-out staging (~25 GB extra HBM
traffic per 4096-token step at GLM-5.2 geometry), python chunk loops,
and one expert re-stream per 128-row chunk. That covers 100% of
prefill, so prefill throughput is capped at ~2.0-2.3k tok/s while the
same weights decode at full speed through the planned Trellis window.

Build a second trellis_moe plan at max_tokens=max_num_batched_tokens
with block_size_m=64 (env VLLM_EXL3_PREFILL_BLOCK_M, allowed
{8,16,32,48,64}) beside the existing decode plan (32/8), and dispatch
three ways in _apply_rank_sliced:

* m in [min, max]      -> decode plan (unchanged)
* max < m <= capacity  -> prefill plan (sparkinfer bind already accepts
                          any tokens in [1, max_tokens]; zero kernel
                          changes needed)
* m < min              -> parity path, whose persistent staging
                          (xh/out32/token_sorted/weight_sorted) shrinks
                          from capacity rows to one chunk while the
                          prefill plan is live (~110 MiB/GPU returned)

VLLM_EXL3_PREFILL_TRELLIS=0 restores the exact single-plan parity
behavior (one-variable serving A/B lever). The parity branch now raises
during CUDA graph capture instead of silently recording eager ext
calls. The prefill arena (~1.05 GiB/GPU at capacity 3072) allocates
during the profile pass, so vLLM's memory profiler sees it and the KV
pool auto-shrinks instead of risking request-time OOM.

Matched A/B serving brandonmusic/GLM-5.2-EXL3-TR3-3.0bpw on the
published verdictai/glm52-exl3-sparkinfer runtime image (4x RTX PRO
6000 Blackwell, TP4/DCP4/MTP3, identical boot geometry, only the
kill-switch flipped, fresh JIT cache both arms; llm_decode_bench
prefill-only, exact /tokenize, C1, 60 s/context):

  ctx    parity   trellis   delta
  8k      2,287     3,742   +63.6%
  32k     2,218     3,557   +60.4%
  64k     2,078     3,381   +62.7%
  128k    1,920     3,032   +57.9%

Decode C1 unchanged-to-better; 57k-token needle retrieval exact.

(cherry picked from commit d57d775)
lukealonso pushed a commit that referenced this pull request Jul 30, 2026
Optional companion to the prefill-plan commit; mocked plan/ext APIs,
no GPU, sparkinfer, or exllamav3_ext required. Covers plan
construction order, the three-way dispatch boundaries, chunk-capped
parity staging, the VLLM_EXL3_PREFILL_TRELLIS=0 kill-switch,
VLLM_EXL3_PREFILL_BLOCK_M override, elastic re-plan above scheduler
capacity, and the parity-path capture guard. Follows the existing
CPU-test pattern of tests/quantization/test_exl3.py from
#139.

(cherry picked from commit f80a56d)
randomvariable pushed a commit to randomvariable/vllm that referenced this pull request Aug 19, 2026
Builds on the rank-sliced EXL3 (ExLlamaV3 trellis) support added in
local-inference-lab#139 by @brandonmusic, paired with the
trellis3_t256 planned MoE from local-inference-lab/b12x#49. No change
to that work's weight loading, formats, or decode path; this commit
only extends its batch dispatch.

The vllm-project#139 backend serves every batch with m > 32 through the eager
exllamav3_ext parity path: fp16-in/fp32-out staging (~25 GB extra HBM
traffic per 4096-token step at GLM-5.2 geometry), python chunk loops,
and one expert re-stream per 128-row chunk. That covers 100% of
prefill, so prefill throughput is capped at ~2.0-2.3k tok/s while the
same weights decode at full speed through the planned Trellis window.

Build a second trellis_moe plan at max_tokens=max_num_batched_tokens
with block_size_m=64 (env VLLM_EXL3_PREFILL_BLOCK_M, allowed
{8,16,32,48,64}) beside the existing decode plan (32/8), and dispatch
three ways in _apply_rank_sliced:

* m in [min, max]      -> decode plan (unchanged)
* max < m <= capacity  -> prefill plan (sparkinfer bind already accepts
                          any tokens in [1, max_tokens]; zero kernel
                          changes needed)
* m < min              -> parity path, whose persistent staging
                          (xh/out32/token_sorted/weight_sorted) shrinks
                          from capacity rows to one chunk while the
                          prefill plan is live (~110 MiB/GPU returned)

VLLM_EXL3_PREFILL_TRELLIS=0 restores the exact single-plan parity
behavior (one-variable serving A/B lever). The parity branch now raises
during CUDA graph capture instead of silently recording eager ext
calls. The prefill arena (~1.05 GiB/GPU at capacity 3072) allocates
during the profile pass, so vLLM's memory profiler sees it and the KV
pool auto-shrinks instead of risking request-time OOM.

Matched A/B serving brandonmusic/GLM-5.2-EXL3-TR3-3.0bpw on the
published verdictai/glm52-exl3-sparkinfer runtime image (4x RTX PRO
6000 Blackwell, TP4/DCP4/MTP3, identical boot geometry, only the
kill-switch flipped, fresh JIT cache both arms; llm_decode_bench
prefill-only, exact /tokenize, C1, 60 s/context):

  ctx    parity   trellis   delta
  8k      2,287     3,742   +63.6%
  32k     2,218     3,557   +60.4%
  64k     2,078     3,381   +62.7%
  128k    1,920     3,032   +57.9%

Decode C1 unchanged-to-better; 57k-token needle retrieval exact.

(cherry picked from commit d57d775)
randomvariable pushed a commit to randomvariable/vllm that referenced this pull request Aug 19, 2026
Optional companion to the prefill-plan commit; mocked plan/ext APIs,
no GPU, sparkinfer, or exllamav3_ext required. Covers plan
construction order, the three-way dispatch boundaries, chunk-capped
parity staging, the VLLM_EXL3_PREFILL_TRELLIS=0 kill-switch,
VLLM_EXL3_PREFILL_BLOCK_M override, elastic re-plan above scheduler
capacity, and the parity-path capture guard. Follows the existing
CPU-test pattern of tests/quantization/test_exl3.py from
local-inference-lab#139.

(cherry picked from commit f80a56d)
randomvariable pushed a commit to randomvariable/vllm that referenced this pull request Aug 29, 2026
Builds on the rank-sliced EXL3 (ExLlamaV3 trellis) support added in
local-inference-lab#139 by @brandonmusic, paired with the
trellis3_t256 planned MoE from local-inference-lab/b12x#49. No change
to that work's weight loading, formats, or decode path; this commit
only extends its batch dispatch.

The vllm-project#139 backend serves every batch with m > 32 through the eager
exllamav3_ext parity path: fp16-in/fp32-out staging (~25 GB extra HBM
traffic per 4096-token step at GLM-5.2 geometry), python chunk loops,
and one expert re-stream per 128-row chunk. That covers 100% of
prefill, so prefill throughput is capped at ~2.0-2.3k tok/s while the
same weights decode at full speed through the planned Trellis window.

Build a second trellis_moe plan at max_tokens=max_num_batched_tokens
with block_size_m=64 (env VLLM_EXL3_PREFILL_BLOCK_M, allowed
{8,16,32,48,64}) beside the existing decode plan (32/8), and dispatch
three ways in _apply_rank_sliced:

* m in [min, max]      -> decode plan (unchanged)
* max < m <= capacity  -> prefill plan (sparkinfer bind already accepts
                          any tokens in [1, max_tokens]; zero kernel
                          changes needed)
* m < min              -> parity path, whose persistent staging
                          (xh/out32/token_sorted/weight_sorted) shrinks
                          from capacity rows to one chunk while the
                          prefill plan is live (~110 MiB/GPU returned)

VLLM_EXL3_PREFILL_TRELLIS=0 restores the exact single-plan parity
behavior (one-variable serving A/B lever). The parity branch now raises
during CUDA graph capture instead of silently recording eager ext
calls. The prefill arena (~1.05 GiB/GPU at capacity 3072) allocates
during the profile pass, so vLLM's memory profiler sees it and the KV
pool auto-shrinks instead of risking request-time OOM.

Matched A/B serving brandonmusic/GLM-5.2-EXL3-TR3-3.0bpw on the
published verdictai/glm52-exl3-sparkinfer runtime image (4x RTX PRO
6000 Blackwell, TP4/DCP4/MTP3, identical boot geometry, only the
kill-switch flipped, fresh JIT cache both arms; llm_decode_bench
prefill-only, exact /tokenize, C1, 60 s/context):

  ctx    parity   trellis   delta
  8k      2,287     3,742   +63.6%
  32k     2,218     3,557   +60.4%
  64k     2,078     3,381   +62.7%
  128k    1,920     3,032   +57.9%

Decode C1 unchanged-to-better; 57k-token needle retrieval exact.

(cherry picked from commit d57d775)
randomvariable pushed a commit to randomvariable/vllm that referenced this pull request Aug 29, 2026
Optional companion to the prefill-plan commit; mocked plan/ext APIs,
no GPU, sparkinfer, or exllamav3_ext required. Covers plan
construction order, the three-way dispatch boundaries, chunk-capped
parity staging, the VLLM_EXL3_PREFILL_TRELLIS=0 kill-switch,
VLLM_EXL3_PREFILL_BLOCK_M override, elastic re-plan above scheduler
capacity, and the parity-path capture guard. Follows the existing
CPU-test pattern of tests/quantization/test_exl3.py from
local-inference-lab#139.

(cherry picked from commit f80a56d)
cbertucci33 pushed a commit to cbertucci33/vllm-v29-glm53flash-exl3-dgx that referenced this pull request Sep 10, 2026
Builds on the rank-sliced EXL3 (ExLlamaV3 trellis) support added in
local-inference-lab/vllm#139 by @brandonmusic, paired with the
trellis3_t256 planned MoE from local-inference-lab/b12x#49. No change
to that work's weight loading, formats, or decode path; this commit
only extends its batch dispatch.

The #139 backend serves every batch with m > 32 through the eager
exllamav3_ext parity path: fp16-in/fp32-out staging (~25 GB extra HBM
traffic per 4096-token step at GLM-5.2 geometry), python chunk loops,
and one expert re-stream per 128-row chunk. That covers 100% of
prefill, so prefill throughput is capped at ~2.0-2.3k tok/s while the
same weights decode at full speed through the planned Trellis window.

Build a second trellis_moe plan at max_tokens=max_num_batched_tokens
with block_size_m=64 (env VLLM_EXL3_PREFILL_BLOCK_M, allowed
{8,16,32,48,64}) beside the existing decode plan (32/8), and dispatch
three ways in _apply_rank_sliced:

* m in [min, max]      -> decode plan (unchanged)
* max < m <= capacity  -> prefill plan (sparkinfer bind already accepts
                          any tokens in [1, max_tokens]; zero kernel
                          changes needed)
* m < min              -> parity path, whose persistent staging
                          (xh/out32/token_sorted/weight_sorted) shrinks
                          from capacity rows to one chunk while the
                          prefill plan is live (~110 MiB/GPU returned)

VLLM_EXL3_PREFILL_TRELLIS=0 restores the exact single-plan parity
behavior (one-variable serving A/B lever). The parity branch now raises
during CUDA graph capture instead of silently recording eager ext
calls. The prefill arena (~1.05 GiB/GPU at capacity 3072) allocates
during the profile pass, so vLLM's memory profiler sees it and the KV
pool auto-shrinks instead of risking request-time OOM.

Matched A/B serving brandonmusic/GLM-5.2-EXL3-TR3-3.0bpw on the
published verdictai/glm52-exl3-sparkinfer runtime image (4x RTX PRO
6000 Blackwell, TP4/DCP4/MTP3, identical boot geometry, only the
kill-switch flipped, fresh JIT cache both arms; llm_decode_bench
prefill-only, exact /tokenize, C1, 60 s/context):

  ctx    parity   trellis   delta
  8k      2,287     3,742   +63.6%
  32k     2,218     3,557   +60.4%
  64k     2,078     3,381   +62.7%
  128k    1,920     3,032   +57.9%

Decode C1 unchanged-to-better; 57k-token needle retrieval exact.

(cherry picked from commit d57d77534630127e703867d2597a505030079d1b)
(cherry picked from commit 37b3443edf9eafd479ee2f56c99c62a452c0c4f4)
cbertucci33 pushed a commit to cbertucci33/vllm-v29-glm53flash-exl3-dgx that referenced this pull request Sep 10, 2026
Optional companion to the prefill-plan commit; mocked plan/ext APIs,
no GPU, sparkinfer, or exllamav3_ext required. Covers plan
construction order, the three-way dispatch boundaries, chunk-capped
parity staging, the VLLM_EXL3_PREFILL_TRELLIS=0 kill-switch,
VLLM_EXL3_PREFILL_BLOCK_M override, elastic re-plan above scheduler
capacity, and the parity-path capture guard. Follows the existing
CPU-test pattern of tests/quantization/test_exl3.py from
local-inference-lab/vllm#139.

(cherry picked from commit f80a56df14cf2941d8539037392f74c974f8e6f4)
(cherry picked from commit eb3b217da759b7efd4bbe508bb3bdfb406ef568c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants