Repository navigation
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
|
The change-to-evidence chain (evidence_policy.yaml, evidence_check.py and the evidence waivers) was never wired into CI: changed_ops.py produced a manifest nobody read, the resolver ran only in unit tests, and no code read the exceptions registry. Remove it and give known deviations one machine-checked home. - Delete evidence_policy.yaml, evidence_check.py, its tests and evidence_exceptions.yaml. - Move the three standards exceptions to collector/notes/<backend>.yaml as deviation notes (D-vllm-compute-scale-standalone, D-vllm-fp8-static-derived, D-trtllm-mhc-unfused). Code and data comments cite the note id instead of restating it. - Add check_collector_data.py rule R8: notes match a closed schema, and no note covering the pinned version has a verified_on behind the pin of a table in its scope. - Add .claude/rules/collector/overview.md (Pin, Plan, Record, Note, Rule; the failure principle; collection cost; what to record when) and align the rule files, the collector skills, AGENTS.md, the CodeRabbit collector instructions and the collector docs with it. Kernel-limit guards are now reserved for cases that would mismeasure, hang or waste significant time. - Keep changed_ops.py as an informational PR report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The three GEMM getters each carried their own SM ladder, shape filters and case order. They now call one typed plan, case_generator.plan_gemm(backend, sm): the gemm_types axis of gemm.yaml times the shared shapes, minus whole dtype regions that capabilities.yaml rules out. - capabilities.yaml gains backend_gaps: a whole (op, dtype) region on listed SMs that one backend's collector cannot run, citing a guard note. The one entry is SGLang fp8_block on SM89 and SM120 (G-sglang-gemm-fp8-block-deepgemm-only): the collector calls DeepGEMM directly, while serving runs Triton on SM89 and CUTLASS on SM120. - Removed per-framework filters: the SGLang and TRT-LLM skip of block-scaled n<128 or k<128 (vLLM 0.30.0 on b200 has rows for all 6,808 such cases with n and k multiples of 16), TRT-LLM's m*n or m*k >= 2^31 and fp8_block n*k >= 2^31 skips (SGLang and vLLM have rows for them), AIC_COLLECT_GEMM_TYPES, and SGLang's seed-42 shuffle. - Removed the vLLM fp8_block n%16/k%16 raise; its natural failure is a cheap exception. ai-dynamo#649 removed the matching TRT-LLM fp8 raise, and the TRT-LLM op-cache test now checks that an unaligned fp8 case runs. - GemmCase is a NamedTuple whose str() keeps the list form, so case IDs, checkpoints and --case-filter strings do not change. vLLM's GEMM case set and case_plan_hash are identical at every SM, and TRT-LLM keeps its order. - With --sm or --gpu, --plan-only reports typed plans: cases per consumer key, the regions left out and plan_hash. --plan-table writes one CSV row per case. - SGLang's FIXME(re-verify) serving gaps become deviation notes D-sglang-gemm-bf16-cutedsl, D-sglang-gemm-nvfp4-act-quant and D-sglang-gemm-fp8-block-triton-fallback. The last one also covers the SGLang fp8_block cases with n=32 or k<128 that the plan now queues on SM90/100: serving runs Triton there, the collector times DeepGEMM. The stale vLLM SM120 fp8_block comment is gone: the 0.30.0 RTX PRO 6000 table has 31,598 fp8_block rows. - The rules, READMEs, docs and both collector skills describe typed plans and backend gaps. The GEMM hash closures now include capabilities.yaml. Per-system plan growth (SGLang / TRT-LLM): SM89 0 / +8,269, SM90 +7,918 / +8,269, SM100 and SM103 +15,836 / +16,228, SM120 +7,918 / +16,228. vLLM is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The GEMM plan was GEMM-specific code: plan_gemm, a TypedPlan wrapper and a
GEMM-only test file. Moving the next op would have meant the same again. One
generic plan now serves every op, and moving an op is a declaration.
- collector/op_plans.py holds one OpPlan entry per op: its case type, an
expand function (every case, in run order), its dtype field and the fields
that share one module build. plan(op, backend, sm) removes only the whole
regions that a capabilities.yaml floor or backend gap rules out. Each
getter is one line, plan_cases("<op>", "<backend>", get_sm_version()).
- An op may declare rows for a backend whose run function takes more than
the shared case. Rows say how a case runs, never whether: a case with no
row raises.
- backend_gaps entries name a region by dtype or by another region field the
op plan declares. The loader rejects any other field and any op without a
plan.
- tests/unit/collector/test_op_plans.py runs over every OP_PLANS entry:
one-line getters, backends differing only by backend gaps, whole-region
removal, and the list form of case strings. It replaces test_gemm_plan.py.
- GEMM queues exactly the same case list as before, in the same order, for
SGLang, TRT-LLM and vLLM at SM80, 86, 89, 90, 100, 103 and 120. The plan
report counts cases per dtype.
- op_plans.py joins the GEMM hash closures; the rules, READMEs and skills
describe op plans.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The three MoE getters each read their own quant-mode list, model policy and parallel layouts, and planned 7,503 (SGLang), 9,552 (TRT-LLM) and 3,135 (vLLM) layer cases on SM100 from the same model rows. MoE now moves onto the op plan with no change to the plan mechanism: a MoeCase type, an expand function and two rows adapters in op_plans.py, and one-line getters. - One quant-mode axis, common_case_values.moe.quantization_modes, replaces the moe_sglang, moe_trtllm and moe_vllm lists. A model row declares its checkpoint's modes in quantization_modes, the same for every backend; a row that declares none plans every mode. allowed_model_paths keeps int4_wo and the MXFP4 formats to the models that ship them. MoE rows may no longer declare frameworks or per-backend allowed_modes; framework_quantization keeps a backend's module_config and vllm_xpu's policy only. - The shared expand dedupes rows that time the same layer and raises when two rows would time different layers under one consumer key, once for all backends instead of three getter copies. - Rows say how a case runs: SGLang's adds the row's routing, activation and the runner pinned for the SM; TRT-LLM's adds min_latency_mode and, for nvfp4 on SM100/103 with at most 256 experts, the min-latency row. For every case the old getters queued, the rows are unchanged. - capabilities.yaml backend gaps, each citing a guard note verified at the pin: vLLM tp>1 with ep>1 (MoE region parallel=tp_ep, flattened into EP by FusedMoEParallelConfig.make), vLLM w4a8_mxfp4_mxfp8 on SM120, SGLang per-tensor fp8 (no collector path), SGLang int4_wo on SM80/86 and w4a8_mxfp4_mxfp8 on SM120 (no verified runner pin), and TRT-LLM int4_wo on SM100/103 (no MoE implementation at 1.3.0rc29; the worker raise it replaces is gone). - Per-backend SM gates without a current-pin citation are deleted, and those cases now run and record failures: SGLang and TRT-LLM fp8_block on SM89, TRT-LLM int4_wo below SM100 and w4a16_mxfp4 on SM89/120. - Plan change on SM100 (cases): SGLang 7,503 -> 8,274, TRT-LLM 9,552 -> 9,864 (11,697 rows with min-latency), vLLM 3,135 -> 3,498. Removed: bf16/fp8_block on the vLLM-only Nemotron latent width for SGLang and TRT-LLM, per-tensor fp8 on the GLM-5 shape (no such checkpoint), TRT-LLM int4_wo on SM100/103, and vLLM w4a16_mxfp4 below the SM89 floor. - The TRT-LLM seed-42 shuffle is gone; cases keep the shared order. - WideEP callers of get_common_moe_test_cases drop the backend argument. The vLLM EP population keeps its 46 distinct invocations; the duplicate fp8_block invocations under the GLM-5 BF16/NVFP4 names go. - MoE tests now exercise the shared plan; op_plans.py, capabilities.yaml join the MoE hash closures; the rules, READMEs and skills describe it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
Both ops already queued the same cases on every backend, through three copies of the same getter. They move onto op plans; each queues exactly the case list it queued before, in the same order, for SGLang, TRT-LLM and vLLM at SM80, 86, 89, 90, 100, 103 and 120. - compute_scale: ComputeScaleCase (m, k), dtype fp8. The getters' SM <= 86 check was the compute_scale op floor in capabilities.yaml, which the plan applies. The shared sweep moves from framework_specific_op_cases.trtllm to all_frameworks_op_cases in compute_scale.yaml; the op is still opted in per backend by the Qwen3 static-FP8 artifact only. - encoder_attention: EncoderAttentionCase (batch, seq, heads, head_dim), bf16. The token budget (128K) and the 32-bit activation-index budget the three getters each applied now live once in the expand, which logs how many cases they leave out. - case_generator.get_shared_base_op_case_specs reads the specs an op plan shares and rejects a CUDA backend's own case list for that op. - The docs point at OP_PLANS instead of naming the migrated ops; the hash closures of both ops include op_plans.py and capabilities.yaml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
Which kernel or runner a backend measures is what Rule 2 checks against serving, but SGLang's MoE runner was chosen inside its rows, where rows are meant to add execution arguments only. - OpPlan gains dispatch: backend -> the kernel or runner the plan picks for a case. Rows receive it; --plan-only reports by_dispatch and --plan-table adds a dispatch column, so a checker can match each case (model, dtype) against what serving was observed to run. SGLang MoE's runner pin moves from its rows to dispatch; its queued rows are unchanged. - Plan logs go to the collector log. The MoE and encoder-attention expands printed to stdout and broke the --plan-only JSON. - test_op_plans.py checks that planning imports no framework (SGLang, vLLM, TensorRT-LLM and torch blocked), that region fields stay a few string categories, and that --plan-only reports and tables every op plan. - case_authoring.md and the op-development skill describe dispatch: a field that enters the persisted key or changes the kernel belongs in the case or the dispatch, not in rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
GDN (SGLang, TRT-LLM, vLLM), KDA (SGLang, vLLM) and Mamba2 (TRT-LLM) move onto op plans. Each queues exactly the case list it queued before, in the same order, at SM80, 86, 89, 90, 100, 103 and 120. - GdnCase carries the model's mamba_ssm_dtype, which SGLang's run function takes; TRT-LLM's and vLLM's rows drop it, as their run functions take no state dtype. The generator already restricts it to float32, the only state dtype the persisted GDN key can represent. - KdaCase and Mamba2Case are the getters' list forms. Generation cases keep no sequence sweep, as before. - Every case type now prints through one list-form helper. - The --plan-only test requests the op plans each backend registers; the Qwen3.5 GDN test checks the plan of all three backends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
mla_bmm_gen_pre and mla_bmm_gen_post move onto op plans. Each backend queues exactly the case list it queued before, in the same order, at SM80, 86, 89, 90, 100, 103 and 120. - The getters' dtype filters become declarations. The SGLang and TRT-LLM SM gate on fp8 was the fp8 floor in capabilities.yaml. vLLM's bf16-only set becomes a backend gap on fp8 for both ops, citing the new guard note G-vllm-mla-bmm-fp8-not-served: on NVIDIA vLLM runs both BMMs as bf16 torch.bmm and its fp8/fp4 BMMs are ROCm AITER only (checked at v0.30.0). - get_mla_bmm_case_specs without a backend reads the shared sweep. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
mla_context and mla_generation (SGLang, TRT-LLM) move onto op plans. Both collectors built the same MLA catalog per KV dtype and TP, deduplicated on the loader key (dtype, local heads, batch, input length) at the smallest TP; the shared expand does that once. - Rows build the run tuples the collectors queued before: SGLang's torch dtype and the page size of its MLA backend, TRT-LLM's DataType and KV block size. Both need the framework, so a Plan now builds its rows on demand: planning stays framework-free, and --plan-only on a CPU counts the cases but reports plan_hash null with the missing module. - SGLang's MLA backend map covers SM89/90/100/103/120; SM80/86 become a backend gap (G-sglang-mla-backend-unmapped) where the getter raised. - SGLang no longer drops fp8 KV on its triton platforms (SM89/120); that filter had no citation at the pin, so those cases run and record failures. TRT-LLM loses its fp8 cases on SM80/86, below the fp8 floor. - The SGLang backend selector drops its 0.5.14 version narration; the mapping is the current pin's, and git keeps the history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
mhc_module (SGLang, TRT-LLM, vLLM) moves onto an op plan. A case is one
mHC call site of an architecture at one (hidden_size, hc_mult), with its
token sweep; models that share a geometry reuse it.
- Rows keep each backend's run unit and IDs: TRT-LLM and vLLM queue one
row per token count, SGLang one row per site that sweeps every token
count in one worker. TRT-LLM's 140 rows, vLLM's 175 GLM-5.3-Flash rows
and SGLang's 4 DeepSeek-V4 rows are unchanged at every SM.
- The runtime architecture gates become backend gaps on the new region
field architecture, each citing a guard note:
- SGLang, GLM-5.3-Flash (G-sglang-mhc-glm5next-not-ported): its 4 cases
always failed the runtime audit.
- vLLM, DeepSeek-V4 (G-vllm-mhc-dsv4-shared-key): its 140 cases always
failed the runtime audit, which keeps DeepSeek-V4 rows out of the
table GLM-5.3-Flash rows share a key with.
- TRT-LLM, GLM-5.3-Flash (G-trtllm-mhc-glm5next-not-served): no row
change; the getter already folded GLM into DeepSeek-V4's rows.
- The getters' --smoke shortcut to 16 tokens is gone; --smoke samples
four rows like every other op.
- --plan-only's plan_hash takes an {id, params} row's own id, the ID a
run records for it; one helper now builds both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The MoE validation runs at b012f30 (plan v4moe_20261031b) showed three regions where TensorRT-LLM's MoE resolution turns down every candidate at layer build, whatever the shape. They become backend gaps: - int4_wo on every SM (G-trtllm-moe-int4-wo-no-implementation, extended from SM100/103): CutlassFusedMoE does not support W4A16. Observed on a100, l40s, h200 and b200; no TensorRT-LLM table holds an int4_wo row. - fp8_block on SM89 and w4a16_mxfp4 on SM89/SM120 (G-trtllm-moe-cutlass-sm-support): below SM100 CutlassFusedMoE is the only candidate, and it runs FP8_BLOCK_SCALES on SM90/SM120 and W4A16_MXFP4 on SM90 only. Every such case failed on l40s. The rtxpro6000 run is still queued; the SM120 entry follows the support set the resolution reports, and no SM120 table holds a w4a16_mxfp4 row. TRT-LLM MoE cases queued: SM80/86 2,163 -> 2,049; SM89 6,459 -> 3,753; SM90 6,459 -> 6,345; SM120 9,978 -> 9,537; SM100/103 unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The op-plan rules now say what commits 9 and 10 added: a row may be an
{id, params} mapping that a run records (and --plan-only hashes) under
its id, and rows that hold framework objects are built only when the
getter runs, so --plan-only on a CPU reports plan_hash null for them.
The layer permissions name mHC's architecture region field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The rtx pro 6000 validation run (plan v4moe_20261031b, pipeline 78153191) rejected every w4a16_mxfp4 and int4_wo MoE case at layer build, so the SM120 entries of G-trtllm-moe-cutlass-sm-support and G-trtllm-moe-int4-wo-no-implementation are now observed rather than inferred. The cutlass note also cites why serving has no other implementation on SM89/SM120: TritonFusedMoE runs on SM90 only, the TRTLLM-Gen implementations on the SM100 family only, and every other backend falls back to CUTLASS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
Llama 3.1 405B has 128 query and 8 KV heads. At TP1, as under pipeline parallelism, one rank runs all of them. No base grid has that shape: the context grids stop at 96 query heads (64 on vLLM), and vLLM's decode grid at 64. The Llama profile now declares the 405B attention row for TP 1, 2, 4 and 8. The smaller TPs deduplicate into the base grids. The row applies to every backend. On attention rows, frameworks can only exclude SGLang. Cases added per SM (SM80/86 in parentheses): - TRT-LLM: +357 (+119) context cases; generation unchanged. - vLLM: +238 (+119) context and +256 (+128) generation cases. - SGLang, SM89-120: +357 context cases; generation unchanged. SGLang cases name the architecture of the profile that owns the shape. 1,071 context and 1,168 generation cases of the 405B shapes now name LlamaForCausalLM instead of Qwen3MoeForCausalLM or none. Only their case IDs change: neither architecture triggers SGLang's FlashInfer workspace override, and the perf row does not record the architecture. The SGLang SM90 structural population test now expects 162 context shapes (was 161); generation stays at 147. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
collector/skips.py is now the one place that keeps cases out of a collection. Each entry names what it skips (backend, op, sm, model, dtype or any case field), and the comment above it says why. There are no ids, no notes and no framework versions. An entry belongs there only when the cases would be mismeasured, would hang, would fail as a whole block, or come from a model the backend cannot serve. Moved into SKIPS and deleted: - cases/capabilities.yaml: the dtype_min_sm and op_min_sm floors, now explicit SM lists, and the 16 backend_gaps; - the 12 G- guard notes in collector/notes/*.yaml, condensed into the entries' comments. The D- deviation notes stay, and R8 now accepts only deviations; - cases/denylist.yaml (empty) and its loader; - collector/capabilities.py: detect_sm_version and case_dtypes move to skips.py. Op plans apply SKIPS when they expand; collect.py and fullnode.py apply it around every other getter and before queueing. A model entry drops a case file's rows before cases are merged, so a shape another model also needs is still collected, and a model run (--model-path) plans no op its backend skips. --plan-only reports what each entry left out, with the entry itself as the reason. New: four TRT-LLM model entries, for MiMo, MiMo-V2-Flash, Muse Glimmer and GLM-5.3-Flash, for which TRT-LLM registers no model class. The GLM-5.3-Flash entry replaces the TRT-LLM mHC architecture gap. GPU-free parity against 88c0f92 (every op plan and both attention ops, 3 backends x SM 80/86/89/90/100/103/120, getter rows and the rows left after the queue filter): identical except the TRT-LLM rows of those models, removed in order with nothing added. Per SM89-120: - attention context -6,324 and generation -6,042 (SM80/86: -2,108 and -3,021): MiMo-V2-Flash head_dim 192 (9,604) and Muse Glimmer window 2048 (2,762); - GEMM -2,960 (-2,220 on SM89/90, -740 on SM80/86): GLM-5.3-Flash's off-grid widths at k=4096; - MoE rows -783 on SM100/103 (-666 SM120, -450 SM90, -234 SM89, -117 SM80/86): MiMo-V2-Flash and GLM-5.3-Flash. Model runs: TRT-LLM plans no op for the four models, and vLLM's DeepSeek-V4 run no longer schedules mhc_module, whose rows were already all skipped. collector_hash: SHARED_CORE names skips.py instead of capabilities.py, so every module's hash changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
…armed Follow-up to a ai-dynamo#649 review comment. If the worker dies between the fork and the child's prctl(PR_SET_PDEATHSIG), the child has already been reparented and never gets the signal. The preexec_fn now captures the worker pid in the parent and, after prctl, exits the child when its parent is no longer the worker. The docstring also notes that PDEATHSIG follows the forking thread, which is the worker's main thread: run_measurement_subprocess is only called from there. Two unit tests cover the armed case and the orphaned case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
…erve them MiMo-V2-Flash's hybrid_layer_pattern marks sliding-window layers with 1. vLLM builds its SWA attention where the pattern is 1, and SGLang lists those layers as its SWA layers. The SDK read 1 as global, so it modeled 39 global and 9 SWA layers. It now models 9 global layers (one of them with a dense FFN) and 39 SWA layers. Llama 4 attends globally only in its layers without RoPE: where no_rope_layers is 0 or, when that list is empty, every no_rope_layer_interval-th layer (default 4), as transformers fills it. The other layers use chunked local attention. The SDK alternated even and odd layers, giving 24/24; it now gives 12 global and 36 chunked layers. Golden diff: only mimo-v2-flash-b200-vllm-hybrid-attn-xshape moves, refreshed with pin_goldens.py --refresh: - static: ctx 22.82 -> 21.44 (-6.1%), gen 4.392 -> 4.437 (+1.0%), total -4.9%; - agg: TPOT -5.6%, TTFT -2.1%; disagg: TTFT -6.1%, TPOT +0.2%. The Llama-4 Scout case is unchanged: at isl 1024 its 8192-token chunk covers the whole sequence, so both layer types cost the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
Attention moves onto the op plans with one case list for SGLang, TRT-LLM and vLLM. The shared grid is the generic full attention at head_dim 128 that all three backends already collected, plus every model's attention profile on every backend. The per-backend base grids are gone: their other shapes (head_dim 64 and 256 grids, window 128, head counts only one or two backends swept) were an exact key for no packaged model, and a model that needs one declares a profile. - A profile carries the model's attention properties: v_head_dim, has_attention_sink, and SGLang's runtime window, chunk size, scaling and backend per SM. SGLang's separate variant rows (gpt-oss, Muse Glimmer, Nemotron-H) fold into the shared profiles, `frameworks:` is retired, and each backend's rows take what its run function supports. - SGLang's attention backend is the plan's dispatch. A shape that two models serve on different backends (Nemotron-H on flashinfer, the other models and the generic grid on trtllm_mha) runs on both; on one backend a model's semantics win over the base grid's, and two models that disagree raise. - A collector/skips.py entry may name a `dispatch`: it leaves the case out on that kernel only. The SGLang refusals that used to fail at run time become such entries: a BF16-compute prefill on an FP8 KV cache on fa3 (head_dim <= 256) or trtllm_mha, and an FP8-compute prefill on flashinfer (8.7k to 13.6k error records per SM89-120 system). Also entries: vLLM's missing FP8-compute input, SGLang on SM80/86, and the two SM90 TRT-LLM FP8-KV decode crashes, which no shared shape reaches. - TRT-LLM serves Gemma 4 on its default TRTLLM backend (Gemma4ForCausalLM.get_model_defaults), so its rows run there. The FlashInfer routing and code path go, with the guard that refused every Gemma 4 case on SM89/90/120 and the FlashInfer FP8 guard. So do the head_dim 192 guard (TRT-LLM cannot serve MiMo-V2-Flash), the dead SM120 FP8-FMHA helper and the import shims for older releases. - One decode budget for every backend: T * 128 // min(head_dim, 128) // len // heads, the largest of the three formulas. The TRT-LLM XQA head-ratio skip on SM100+ is deleted. - Deviations are commented next to the rows: vLLM times MiMo-V2-Flash with V = 192 (serving's V head is 128) and gpt-oss without sinks; TRT-LLM adds sinks to every head_dim 64 row, Kimi-K3's draft attention included. The stale "vLLM omits it" comments on op activation now say what model runs and full runs do. Cases queued per SM, GPU-free against 5aeba48 (getter plus queue filter, SM80-120; SM89/103 match SM90/100 except where noted): | | SM90 before -> after | SM100 before -> after | |---|---|---| | SGLang context | 56,256 -> 29,784 | 64,008 -> 35,326 | | SGLang generation | 45,072 -> 36,096 | 51,550 -> 41,370 | | TRT-LLM context | 77,727 -> 36,261 | 73,443 -> 36,261 | | TRT-LLM generation | 53,834 -> 30,054 | 52,810 -> 30,054 | | vLLM context | 54,706 -> 28,390 | 54,706 -> 28,390 | | vLLM generation | 67,892 -> 36,096 | 67,892 -> 36,096 | Every difference is one of: - removed: shapes outside the shared grid (13.7k SGLang, 41.5k TRT-LLM, 26.3k vLLM context rows on SM90); the SGLang refusals above, which were queued and failed before; SGLang trtllm_mha rows of head_dim 256 shapes only the old SGLang grid planned on that backend (SM100/103); - added: decode points the shared budget admits for head_dim != 128 (SGLang +840, TRT-LLM +298, vLLM +840 on SM90); TRT-LLM GQA ratio 40 and 48 context rows on SM100+ (+714); - changed: TRT-LLM Gemma 4 rows' backend element FLASHINFER -> TRTLLM; SGLang rows whose shape several models plan now name the first model in file order (Muse Glimmer or Nemotron-H instead of Qwen3), which changes the case ID only. SGLang on SM80/86 queued nothing before (its getter raised) and after. Rows keep each backend's run arguments, so every other case keeps its ID. The vLLM XPU collector keeps its own grid; its 145 head keys per phase are unchanged except that MiMo-V2-Flash's sliding-window keys now carry their sinks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
A collector/skips.py entry may name the dispatch kernel when a backend runs one case on two kernels and only one of them cannot run it (the SGLang attention entries in 4622201). The layer permission table and the case-authoring lookup table now say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The DSA, MSA and DeepSeek-V4 attention-module collectors gain a series entry: one task measures several (seq_len, prefix_len) points of one key (model, heads or TP, precision, batch). The op-plan batch rows will call it. Today's getters, registry entries and case IDs are unchanged, and each single-point worker runs a series of one. What a series shares and what it does not: - The layer comes once from the per-worker layer cache, as before. - Each point still builds its own KV cache manager, metadata and inputs and tears them down, exactly like a one-point case. The manager's capacity is a kernel input: the attention metadata reads max_seq_len from the manager, DeepSeek-V4 sizes its compressed-index buffers from it, and the MSA indexer copies the whole index-K pool every forward. One manager sized for the largest point would change what the smaller points measure, so no perf row field or value changes. - The checking dry run runs once per seq_len. - Points run largest first. A point that fails for a non-fatal reason is recorded, and the series continues; a sticky CUDA error aborts it. Failures are raised after the series: a single failure as it is, several as a summary that keeps the kernel-limit classification when every failure is a kernel limit. run_mla_module now releases the KV pool in a finally block, as the MSA and DeepSeek-V4 collectors already did, so a failed point does not leak its pool into the next one. collector/trtllm/module_series.py joins the hash closures of the three collectors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
TRT-LLM's MLA context attention follows the KV cache dtype: with an FP8 KV cache it quantizes Q/K/V and runs FP8 FMHA on SM90/100/103/120 (thop/attentionOp.cpp), whatever the BF16 inputs say. The MLA module collector labelled every row mla_dtype=bfloat16, so its FP8-KV context rows claimed BF16 compute. The SDK looks these rows up with fmha=fp8 for FP8 checkpoints (DeepSeek-V3/R1, Kimi-K2), so on TRT-LLM those lookups missed and fell back to op-level ops. The op-level collector got the same fix in ai-dynamo#264. - collect_mla_module.py labels MLA context rows with an FP8 KV cache on SM90/100/103/120 as mla_dtype=fp8, like collect_mla.py. - The shipped tables get the same label: 51,187 rows in 26 files, the module context tables at rc20 and rc29 on b200, b300, gb200, gb300, h100, h200 and rtx_pro_6000, the op-level context tables at rc29, and the op-level rc20 tables ai-dynamo#264 did not touch. Latencies and every other column are unchanged. - op_backend_facts.yaml follows (49 entries); backend_facts.py --check and check_collector_data.py pass. - Tests follow: - test_power_data pins the new hash of b200's rc20 module table; - the large-EP task test now expects fp8 FMHA on the FP8 KV cache, with no fallback; - the wide-EP compile-engine parity case now uses fp8 FMHA on the FP8 KV cache, which is what TRT-LLM runs. Its golden is unchanged, because it reads the same rows, relabelled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
…s on Blackwell The TRT-LLM DeepSeek-V4 module collector timed a BF16 KV pool on SM100/103. The probe behind that choice tried only the packed fp8_ds_mla pool, which is not servable off Hopper (it needs 256-token blocks and the fallback attention refuses it). Blackwell serves the plain FP8 pool: it is TRT-LLM's recommended DeepSeek-V4 configuration (examples/models/core/deepseek_v4/README.md) and what its B200 CI runs. The SDK already looks DeepSeek-V4 up with an FP8 KV cache, so the BF16 rows were never read by default. The collector now times FP8 KV on every SM. Hopper keeps the fp8_ds_mla pool it requires. AIS_DSV4_KV_CACHE_DTYPE still overrides it. The SDK comment that claimed FP8 KV is required everywhere now says what each backend serves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
TRT-LLM has no separate precision for MLA attention. On SM90/100/103/107/120, an FP8 KV cache turns on FP8 context MLA (mFP8ContextMLA in thop/attentionOp.cpp), and generation MLA runs FP8 for an FP8 KV cache on every SM. BF16 compute on an FP8 KV cache is therefore not a configuration TRT-LLM can run there. Since commit 7d925f6 the shipped tables say so, and an explicit fmha=bfloat16 on an FP8 KV cache found no rows. - helpers.trtllm_mla_runs_fp8 states the rule for the MLA families (DeepSeek-V3/R1, Kimi-K2/K2.5/K3). - helpers.resolve_trtllm_mla_compute resolves an explicit bfloat16 to fp8 there and logs a warning. It sits next to the SGLang MLA resolver, on the same call sites: the estimate path, KV-cache memory, the inference session and the estimate-path FMHA guard. - The Task resolves it before validation, so an explicit bfloat16 does not fail validate. - An unset FMHA is left to the checkpoint inference, which already picks fp8 for an FP8 KV cache. - A bfloat16 KV cache, SM80/89, other backends and whole-model FPM are untouched. - The engine path loads the system spec only when the request is bfloat16, so a malformed system YAML still raises where it did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The packaged Step-3.7-Flash configs were normalized by hand from the upstream text_config when the model was added (AIConfigurator #1447 and #1452). Two upstream values were dropped: - attention_other_setting, which gives the 33 sliding-attention layers 96 query heads (8 KV groups, head_dim 128) against the 64 heads of the global layers; - the context length, written as 65,536, while every upstream revision says 262,144. The SDK parser already reads attention_other_setting, so it sized every sliding layer with 64 heads. Meanwhile the collector plans the 96-head shapes that vLLM, SGLang and TRT-LLM build. Both files now carry the upstream values at the pinned revisions: stepfun-ai/Step-3.7-Flash@5f62440 and -FP8@b3d7916fccac844cca050d7520f2aaa513f9a84f. Both copies of THIRD_PARTY_NOTICES.md record the files, the revisions, the Apache-2.0 license and every normalization. check_packaged_legal_files.py passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
A module collector builds the module once and times several points on it. Per-case rows cannot express that, so an op plan may now declare batch_rows for a backend: - The function receives the kept cases and returns (row, the cases it times) pairs. - A row lists its points explicitly; the run never derives them again. - Plan.rows checks that every kept case is timed by exactly one row and that no row times a case the plan left out. A backend declares either batch_rows or rows/dispatch, never both. dtype_field may also name several fields, for a case that carries its KV cache, compute and GEMM dtypes separately. A skips.py dtype entry matches any of them, and the plan summary counts each combination as one key, such as bfloat16/fp8/fp8_block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
mla_context_module and mla_generation_module now expand one sweep for TRT-LLM and vLLM: the mla_module_plan section of cases/base_ops/mla_module.yaml. - Heads are the union over the MLA models: DeepSeek-V3's shards (128 to 1) and Kimi-K3's (96, 48, 24, 12), all measured on the canonical DeepSeek-V3 module. - Precisions are the union of the combinations either backend collected. Three skips.py entries keep each backend's set as it was: FP8 compute stays off SM89/90, TRT-LLM has no FP8-compute context case of its own, and vLLM keeps SM89 to BF16 KV. - TRT-LLM queues one run_mla_module_series_worker task per (model, heads, precision, batch) with its (seq_len, prefix_len) points. vLLM keeps its series rows. The plan no longer depends on the device. vLLM's generation getter used to drop points whose KV cache could not fit the device. The run now refuses those points before allocating them, with a FIXME(kernel-limit) "does not fit" reason, and sizes the module for the points that fit. H100 and H200 therefore get the same plan. The DSA module getters keep the generation-time filter. GPU-free parity against the previous getters at SM 80, 86, 89, 90, 100, 103, 120 and 121: - Each backend keeps its precision combinations and (batch, length) grid on every SM. - TRT-LLM gains heads 96, 48, 24 and 12, which vLLM already timed, on each of its own precision combinations. - vLLM's rows are unchanged with the memory filter off. On each device, the run refuses exactly the points the filter dropped. --plan-only now sends planning output to stderr. The MLA module loader prints notes about the models it collapses, and stdout must carry only the JSON report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
dsa_context_module and dsa_generation_module now expand one plan for TRT-LLM, vLLM and SGLang from the mla_module_plan section of cases/base_ops/mla_module.yaml. - Grid: a context point (batch, isl, prefix) follows serving's chunked prefill: batch x isl <= 16384 new tokens, batch x (isl + prefix) <= 1M KV tokens, and prefix + isl within the model's max_position_embeddings. Prefixes are 13 anchors at x2 spacing up to 1048575, keeping the 2048 top-k knee; from a 16K prefix on only isl 1, 512, 2048, 8192 and 16384 run. Decode keeps the shared grid and adds KV lengths 262144, 524288 and 1048575 at batch 1, 2 and 4 where the model's context allows them. - Models: one checkpoint per (architecture, projection GEMM), the longest-context one: DeepSeek-V3.2, DeepSeek-V3.2-NVFP4 (it keeps o_proj in NVFP4), GLM-5.2 and GLM-5.2-FP8. A GEMM no checkpoint runs is timed on the architecture's longest-context checkpoint. TRT-LLM moves from GLM-5 to GLM-5.2. - Precisions: the plan holds the union of the combinations the backends collected. skips.py entries keep each backend's set: TRT-LLM has no FP8 KV on SM90, and SGLang times only a checkpoint's own projection GEMM, with no NVFP4 projections. SGLang also leaves out the one-token prefill and NVFP4 checkpoints below SM100, as its getter did. - Rows: TRT-LLM queues one run_mla_module_series_worker task per module, vLLM series list their (isl, prefix) points, and SGLang rows carry their [batch, isl, prefix] points into the subprocess, which no longer derives them. SGLang's FP8-KV attention backend is the plan's dispatch, so batch rows may now come with a dispatch. The plan no longer depends on the device. SGLang refuses a point beyond the prefill chunk it uses on the device or beyond its KV pool, and vLLM a decode point whose KV cache cannot fit, with a FIXME(kernel-limit) reason before allocating it. The AIC_DSA_CONTEXT_* switches are gone. The per-backend sweep sections keep only what the MSA modules, the wideep MLA modules and the GLM-5 sparse kernels read, and the TRT-LLM and vLLM module CLIs run the plan's rows. GPU-free comparison with the previous getters at SM 80 to 120 (SM80/86/89 skip these ops before and after): - Each backend keeps its precision combinations per architecture on every SM. - Points per SM90 / SM100+ (context, decode): TRT-LLM 4,880 / 14,640 -> 11,110 / 33,330 and 3,680 / 11,040 -> 3,770 / 11,310; vLLM 71,660 / 107,490 -> 22,220 / 33,330 and 7,360 / 11,040 -> 7,540 / 11,310; SGLang 57,344 -> 14,590 and 3,656 -> 5,700 on every SM. - SGLang gains the TP16 head shard its getter left out and moves to the shared grid: its own batches 512 and 1024, isl 4 and 8, 26-value prefix list and per-model ceiling points go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
dsa_context_module_skip_indexer and dsa_generation_module_skip_indexer expand the DSA module plan for the checkpoints whose layers share one top-k index (index_topk_freq > 1, read from the packaged config): GLM-5.2 and GLM-5.2-FP8. Only SGLang collects them; their rows are the full DSA modules' SGLang rows of those checkpoints, and the registry still binds skip_indexer=True. The getters are the one-line plan call. GPU-free comparison with the previous getters, on every SM from SM90: context 40,016 -> 9,800 points (176 -> 180 rows) and decode 2,464 -> 3,860 points (16 -> 20 rows), the same grid classes as the full modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
msa_context_module and msa_generation_module now expand one plan for TRT-LLM, vLLM and SGLang from the mla_module_plan section of cases/base_ops/mla_module.yaml. - Grid: MiniMax-M3 (1M context) takes the DSA modules' long-context grid: batch x isl <= 16384 new tokens, batch x (isl + prefix) <= 1M KV tokens, the 13 prefix anchors, and from a 16K prefix on only isl 1, 512, 2048, 8192 and 16384. 2048 is M3's knee too (16 top-k blocks of 128). Decode keeps the shared grid and adds KV lengths 262144, 524288 and 1048575 at batch 1, 2 and 4. The grid's YAML keys and sweep fields lose their dsa_ prefix, and the sparse-module expand and model rule take the attention type. - Heads and model: MiniMax-M3's TP 1 to 16 shards (64 to 4 heads), as before. - Precisions: the plan holds the union of the combinations the backends collected. skips.py entries keep each backend's set: TRT-LLM takes no FP8 KV cache, SGLang times BF16 projections only and no FP8 KV on SM89. - TRT-LLM runs MSA off SM100/103 on its Triton reference, a dense FP32 attention. A skips.py entry stops its context at a 32K prefix there, where a 16K chunk does no more work than the isl-32768 point collected before (18 s per forward on h200); a longer prefix runs out of memory. It replaces the 32768-token Triton budget. - Rows: TRT-LLM queues one run_msa_module_series_worker task per module build, vLLM keeps one task per point (run_msa_module_worker takes the case), and SGLang rows carry their [batch, isl, prefix] points instead of a manifest the getter built. The plan no longer depends on the device. SGLang refuses a point beyond the prefill chunk it uses on the device (the collector no longer raises the chunk to the largest planned shape) or beyond its KV pool, and vLLM a decode point whose KV cache cannot fit, each with a FIXME(kernel-limit) reason before allocating it. The AIC_MSA_* switches, SGLang's plan-time memory filter and get_msa_head_counts are gone; the mla_module_trtllm and mla_module_vllm sections, read only by the MSA getters, are deleted; and the TRT-LLM, vLLM and SGLang module CLIs run the plan's rows. The rule docs describe batch rows and the run-time refusal. GPU-free comparison with the previous getters at SM 80 to 120: - Each backend keeps its precision combinations on every SM. vLLM's FP8 KV on SM80/86 now falls under the FP8 floor in skips.py; no MSA table exists there. - Context points per SM90 / SM100 (TRT-LLM, vLLM, SGLang): 1,940 / 3,660 -> 5,210 / 8,445; 4,880 / 7,320 -> 11,260 / 16,890; 35,000 -> 5,630. Decode: 1,840 / 2,760 -> 1,930 / 2,895; 3,680 / 5,520 -> 3,860 / 5,790; 1,850 -> 1,930. - TRT-LLM and vLLM lose prefix 128 and batch x isl beyond the 16K chunk, and gain prefixes to 1M (TRT-LLM to 32K on SM80-90 and SM120). SGLang loses the one-shot prefills beyond the chunk, its 26-value prefix list, batches 512 and 1024, isl 4 and 8 and decode KV 1, and gains isl 1536 to 12288 and the long-KV decode points. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
… refuse The DSA diag on h200 (pipeline 78355014) refused 22 points as planned: prefills of more than the 8,192 new tokens SGLang chunks on that GPU. The other 90 points were measured. But the failure was recorded as unexpected rather than kernel_limit. Under torch.distributed, SGLang's subprocess prefixes every output line with "[rank0]: ", so the parent found no traceback to read the classified error from. The DSA/MLA and MSA module runners now strip that prefix before looking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
dsv4_{csa,hca}_{context,generation}_module now expand one plan for
TRT-LLM, vLLM and SGLang.
- Grid: context takes the DSA and MSA modules' long-context grid: batch
x isl <= 16384 new tokens, batch x (isl + prefix) <= 1M KV tokens, the
13 prefix anchors, which keep the 512 (DeepSeek-V4-Flash) and 1024
(DeepSeek-V4-Pro) top-k knees, and from a 16K prefix on only isl 1,
512, 2048, 8192 and 16384. Decode keeps the dsv4 block's batch and KV
lists within the decode budget of cases/base_ops/dsv4_attention.yaml,
to a 1M KV length at batch 1, now on every backend.
- Models and heads: the Flash and Pro FP8 checkpoints at TP 1, 2, 4 and
8, as before.
- Precisions: the plan holds BF16 and FP8 block-scaled projections
(module_gemm_types). skips.py keeps what each backend collected:
TRT-LLM and vLLM time fp8_block only, and SGLang no fp8_block for a
native checkpoint on SM90. The KV cache is FP8 on every backend and
the rows name it; TRT-LLM picks the fp8_ds_mla pool on SM90 and the
plain FP8 pool elsewhere.
- Rows: TRT-LLM queues one run_dsv4_attn_series_worker task per module
build, vLLM keeps one task per point, and every SGLang row, decode too,
carries its (prefix, seq_lens) points, so the subprocess never derives
a grid.
The plan no longer depends on the device. SGLang's context memory filter
is gone: at 16384 new tokens the BF16 hidden state stays below 250 MB.
SGLang refuses a prefill beyond the chunk it derives on the device before
building the ModelRunner, and a point beyond its KV or SWA KV pool after
building it, each with a FIXME(kernel-limit) reason, and its subprocess
keeps that classification. Before, those points were skipped and the
task passed. The refusal helpers move from the SGLang MSA collector to
runtime_limits.py, and both collectors use them.
AIS_DSV4_KV_CACHE_DTYPE, AIC_VLLM_DSV4_MAX_SEQ_LEN, the --smoke argv
checks of the module getters and workers, the max_seq_len and
max_context_query_tokens budgets and the case_generator module getters
are gone. The SGLang CLI runs the plan's rows, and the module hash
closures name the plan's inputs.
GPU-free comparison with the previous getters at SM 80 to 120, per
attention kind:
- Each backend keeps its precision combinations on every SM, and
SM80/86/89 plan nothing, as before.
- Context points on SM90 to SM120 (TRT-LLM, vLLM, SGLang): 5,840,
5,840, 113,872 -> 4,504, 4,504, 9,008. TRT-LLM and vLLM lose isl 4
and 8, batches 512 and 1024, batch x isl beyond 16K and the prefixes
128 and 65536 - isl, and gain the prefix anchors to 1M. SGLang loses
the one-shot prefills beyond the chunk, its 28-value prefix list, isl
4 and 8 and batches 512 and 1024.
- Decode points: TRT-LLM and vLLM 1,544 -> 1,600 (KV lengths beyond
65536 at small batch); SGLang 3,200, unchanged.
- Tasks: TRT-LLM 5,840 -> 72 context and 1,544 -> 88 decode; SGLang
176 -> 144 context.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
dsv4_paged_mqa_logits_module (SGLang, vLLM) and dsv4_csa_topk_calib (SGLang) now expand op plans too. - paged_mqa_logits: one grid for both backends, the dsv4 block's sparse lists vLLM timed (batch x isl <= 8192, batch x (isl + past KV) <= 1M, TP 1) for both default checkpoints. vLLM keeps one task per point, with the same rows and case IDs. SGLang times one row per (model, TP, batch) whose points the plan lists, instead of deriving them from the module sweep and the prefill chunk of the device. - topk_calib: the CSA module plan's points of the calibrated checkpoint, expanded at plan time: the v1 top-k on the context points and the v2 top-k on the decode points, one new token after the KV length. One SGLang row per batch. SGLang's run_dsv4_sparse_kernel_worker takes the row's batch, TP and [prefix, isl, variant] points, and writes the row's TP. The case_generator sparse getters and lists, module_past_kv_lengths, AIC_VLLM_DSV4_SPARSE_MAX_QUERY_TOKENS and the vLLM --smoke argv checks are gone, and the sparse hash closure names the plans' inputs. GPU-free comparison with the previous getters and SGLang's derived shapes, per SM: - paged_mqa_logits: vLLM 3,918, unchanged. SGLang 4,110 (SM90/120) and 4,790 (SM100/103) -> 3,918: it loses past KV 10000 and 1000000 (184 points), 8 decode shapes at exactly 1M KV tokens, and on SM100/103 the 680 prefills beyond 8192 new tokens. - topk_calib (SGLang): 2,251 (SM90/120) and 2,591 (SM100/103) -> 763: it loses the prefixes off the 13 anchors, isl 4 and 8, the isl that are not chunk-sized at a prefix of 16K or more and context batches 512 and 1024. On SM90/120 it gains the 96 prefills of 8K to 16K new tokens the context plan holds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
moe_ep (SGLang and TRT-LLM wide-EP registries), deepep_ll and
deepep_normal now expand one plan each in collector/op_plans.py, and
their getters are the one-line plan call.
- moe_ep: one case per large-EP build, i.e. quant mode, routed-expert
layer, EP size and EPLB layout, from the wideep: true MoE rows at TP 1
of the shared grid. The plan holds the union of both backends' builds:
fp8_block and nvfp4; EPLB off, on, and on with the 288-slot layout
where it holds every expert; slots shard over EP.
- TRT-LLM rows run one task per power-law draw of the shared grid, with
the same 16 run arguments as before.
- SGLang rows keep the 9 run arguments; SGLang still sweeps its own
prefill and decode grid inside the task.
- skips.py entries keep each backend's builds:
- SGLang times FP8-block only, without EPLB, on the checkpoint's own
quant mode.
- TRT-LLM times a build once across models: its synthetic weights
ignore the model, and the table has no model column.
- TRT-LLM's fp8_block on SM89 fails in the DeepGEMM compiler.
- deepep_ll and deepep_normal: one case per distinct
(hidden_size, num_experts, topk) of the packaged MoE model configs, as
before. Their shared shape reader moves into the plan, and rows keep
the shape dict the full-node runners take.
- AIC_ACCURATE_WIDEEP_SIM is gone: TRT-LLM rows carry the accurate
wide-EP simulation they always ran with by default.
- test_op_plans.py runs its per-getter checks over the wide-EP
registries too. The hash closures of the four modules gain
op_plans.py.
GPU-free comparison with the previous getters at SM 80 to 120:
- deepep_ll and deepep_normal: identical, 25 shapes on every SM.
- moe_ep SGLang: identical (62) on SM89 to SM120. SM80/86 drop to 0
under the shared FP8 floor; FP8 needs SM89 and DeepGEMM SM90.
- moe_ep TRT-LLM: the same rows (0 / 224 / 448 on SM89 / SM90 /
SM100+). Within a model, quant mode and EP size, they now run layout
before draw; the case plan hash does not depend on order.
- Case IDs are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
moe_expert_compute_perf has no model column, so moe_ep builds of different models that write the same key are now one case in the plan. The case is owned by the first model, in plan order, whose checkpoint plans the quant mode, or by the first model when none does; SGLang's own_quant entry still leaves those out. This replaces the repeated_build field and its TRT-LLM skips.py entry, so the dedup lives in the plan. GPU-free comparison with the previous commit at SM 80 to 120: - SGLang: 62 -> 46 on SM89 to SM120. The 16 rows dropped are the GLM-5.1-FP8 and GLM-5.2-FP8 builds at EP 2 to 256, whose keys GLM-5-FP8 writes with the same SGLang routing fields. - TRT-LLM: the same 224 / 448 runtime identities. 112 rows on SM90 and 294 on SM100/103/120 now name the checkpoint that plans the quant mode (for example zai-org/GLM-5-FP8 rather than nvidia/GLM-5-NVFP4 for fp8_block), so their case IDs change. - deepep_ll and deepep_normal: unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
vLLM takes FP8 prefill queries only on device capability family 100 (backend_supports_prefill_query_quantization in vllm/model_executor/layers/attention/mla_attention.py). On SM120 it falls back to BF16 queries, which the collector refuses to record as FP8, so the FP8-compute mla_context_module cases queued there failed on every run; the shipped rtx_pro_6000_server tables hold no FP8-compute rows. The skips.py entry that covered SM89 and SM90 now covers SM120 too. GPU-free: vLLM mla_context_module on SM120 goes from 972 to 648 cases; every other op, backend and SM is unchanged. The SDK resolves FMHA from the data it finds, so with no FP8 slice on SM120 it already falls back to BF16 (or rejects an explicit FP8 request). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
Nothing read the per-module granularity of collector_hash. Full CI turned it into a changed-operation manifest that it uploaded and nothing consumed once the evidence chain was removed; the collection harness does not read it; the SDK only checks that the field is a non-empty string. Keeping it cost an authored closure per module in hash_closures.yaml, and a missing entry was easy to miss. - collector_hash is one content hash per source tree: every .py, .yaml, .yml, .sh and .patch file under collector/, plus the SDK Python and the packaged model configs the runners import, skipping __pycache__. JSON under collector/ is left out because the TRT-LLM MoE autotuners write their caches there. provenance.hashed_files lists the covered paths. - collection_meta.yaml keeps its schema: collector_ref, collector_hash and case_plan_hash stay. - hash_closures.yaml, the closure loader and module enumeration in provenance.py, tools/perf_database/changed_ops.py with its tests, and the Full CI changed-ops steps with the comparison base they needed are gone. - Tests that pinned closure membership now check that the files a runner depends on are hashed, or that editing them changes the hash. Every table collected from one tree now carries the same collector_hash. The suffix-less wideep/vllm host_tools/ibstat shim is the one closure file the hash no longer covers; collector_ref still identifies it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The six deviation notes lived in collector/notes/<backend>.yaml under a closed schema that check_collector_data.py R8 validated, failing a note whose verified_on fell behind a pin. Like the reasons in collector/skips.py, each is now a comment at the code that measures the deviating path: - SGLang GEMM (bf16 CuTe DSL dispatch, nvfp4 activation quant, fp8_block Triton fallback): collector/sglang/collect_gemm.py. - TRT-LLM unfused mHC on SM100/103: collector/trtllm/collect_mhc_module.py; the four mHC reuse.yaml comments point there. - vLLM standalone compute_scale under torch.compile: collector/vllm/collect_computescale.py. - vLLM fp8_static derived from the dynamic row: the fp8 branch of collector/vllm/collect_gemm.py. Each comment keeps what differs and where, the direction of the error, its sources and how to retire it, and drops verified_on, approved_by and version pins. The notes files, R8 and its tests are gone, so check_collector_data.py runs R1-R7 again. The rules, docs, skills and CodeRabbit instructions describe a note as that comment; a pin bump re-checks the notes in scope in review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
glm5_mqa_logits_module, glm5_topk_module and glm5_dsa_attn_module (SGLang) now expand one op plan each, and their getters are the one-line plan call. - Points: the DSA module plan's points of the checkpoint (the shared long-context grid), context as (batch, isl, prefix) and decode as one new token over its KV length. Before, the worker derived its own shapes from the SGLang module sweep; rows now carry them: one run_glm5_dsa_sparse_kernel_worker task per (model, batch) with its [prefix, isl] points, shortest prefix first. - Model: the case carries the checkpoint. The plan holds the BF16 GLM-5 and the first declared NVFP4 checkpoint (GLM-5.2-NVFP4), and two commented skips.py entries keep today's choice: GLM-5 on Hopper, GLM-5.2-NVFP4 on SM100/103/120. A targeted run (COLLECTOR_MODEL_PATH) gets the same checkpoints as before on every SM. - Removed with the old derivation: the --smoke sampling, the shape helpers only this getter used (_dsa_context_prefix_shape_is_valid, _DSA_CEILING_MAX_POSITIONS, dsa_indexer_total_kv_tokens_supported, _derive_context_shapes), and dsv32_dsa_sparse_modules.py, an unregistered DeepSeek-V3.2 wrapper with no table or consumer. GPU-free comparison with the previous getter (points per kernel; the three kernels share them): - SM90 (GLM-5): 3,026 -> 672; SM100/103/120 (GLM-5.2-NVFP4): 3,333 -> 692; SM80/86/89 plan nothing, before and after. Tasks: 11 per SM, as before. - Lost (SM90 / SM100): context prefixes off the 13 anchors, incl. the max-position ceilings (1,168 / 1,194); batch x isl above 16,384 (511 / 558); batch x (isl + prefix) above 1M (253 / 448); context batches 512 and 1024 (280 each); isl 4 and 8 (138 / 144); non-chunk isl at a 16K+ prefix (119 / 140); decode KV 1 and the 163,839 / 202,751 ceilings (13). - Gained: isl 1,536 to 12,288 (66); decode batch x KV above 262,144 up to the module plan's budget (42 / 49); decode KV 2 and the long-KV points (11 / 12); a one-token prefill without prefix per context batch (9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
dsv41_module (SGLang) now expands one op plan, and its getter is the
one-line plan call. A case is (checkpoint, TP, execution profile), from the
model profile's tensor_parallel_sizes and execution_profiles; its row is
the native runner's existing {id, params: [model, tp, profile, sweep]}.
DSV41_EXECUTION_PROFILE is gone. The two profiles still write separate
tables, so a run collects one of them with a case filter on the row id
(--case-filter dsv41_full_ or dsv41_decoder_bounded_); the locked output
marker still refuses a second profile on one table.
GPU-free comparison with the previous getter at SM 80 to 120: the same 8
rows on every SM, in the same order, with the same ids and parameters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
…ps.py dsv4_csa_topk_calib took its checkpoints from dsv4.calib_model_paths, a collection-cost policy that dropped DeepSeek-V4-Pro from default plans with a log line and let a targeted run collect any model. The plan now calibrates every planned DeepSeek-V4 checkpoint, and one commented skips.py entry leaves sgl-project/DeepSeek-V4-Pro-FP8 out. calib_model_paths, its validation and get_dsv4_models(calib=...) are gone. Default plans are unchanged: the same 11 rows on SM90 to SM120, none below. A targeted run on sgl-project/DeepSeek-V4-Pro-FP8 no longer calibrates Pro; one on deepseek-ai/DeepSeek-V4-Pro still does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
… time vLLM's XPU attention getters were the last to drop cases with a generation-time memory filter: a case whose bf16 KV pool (8192 blocks of 64 tokens) exceeds 0.45 of the device was never queued, so the case list depended on the device. The getters now queue every case, and run_attention_torch refuses such a case before allocating it, with a "FIXME(kernel-limit): does not fit" reason the failure log classifies as a kernel limit. GPU-free: the getters now return 14,294 context and 24,532 generation cases on any device; before, a 24 GB device queued 13,946 and 24,044 and a 48 GB one 14,120 and 24,300. Those differences are now run-time refusals. No getter filters on memory any more, so the collector rules replace "the one sanctioned in-collector filter" with the run-time capacity refusal (layer_permissions.md, and its mentions in failure_handling.md, case_authoring.md, the op-development skill and the CodeRabbit instructions). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
…ps.py Some runtime FIXME(kernel-limit) raises depended only on case fields and the SM, so every case they covered failed on every run after being queued. Each becomes a commented skips.py entry, and its raise goes: - TRT-LLM MLA (mla_context, mla_generation and both MLA modules) below Hopper: AttentionOp asserts there. The two runners keep an assert for direct runs, which would otherwise abort. - TRT-LLM MLA decode on SM100/103 with more than 16 heads per rank that are not a multiple of 16 (numHeadsPerCta=16). MlaCase gains local_heads. - TRT-LLM and vLLM DSA modules on SM100/103 with fewer than 8 heads per rank (trtllm-gen sparse-MLA tiles). - vLLM DSA modules on SM100/103 with an FP8 KV cache and 64 < heads per rank < 128 (FLASHINFER_MLA_SPARSE has no kernel). No planned DSA checkpoint shards to such a head count today. - TRT-LLM wide-EP fp8_block off Hopper (DeepGEMM's JIT compiles for SM90 only); the existing SM89 entry now also names SM100, SM103 and SM120. Queued rows, before -> after: - mla_context / mla_generation, TRT-LLM: SM80/86 1,540 / 2,534 -> 0, SM89 3,080 / 5,068 -> 0; mla_generation SM100/103 5,068 -> 4,706. - mla_context_module / mla_generation_module, TRT-LLM: SM80/86 108 / 132 -> 0, SM89 432 / 528 -> 0. - dsa_context_module / dsa_generation_module, TRT-LLM and vLLM, SM100/103: 540 / 660 -> 486 / 594 series rows. - moe_ep, TRT-LLM, SM100/103/120: 448 -> 224. No other op, backend or SM changes. Left at run time: - the per-shape MoE alignment checks (SGLang and TRT-LLM collect_moe), which fail single shapes, not blocks; - SGLang's trtllm_mla decode head range, whose backend depends on the image's CUDA version; - vLLM's MiniMax-M3 decode scorer check, which no planned head count reaches; - the "does not fit" capacity refusals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
…n base Collector Data no longer fetches a comparison base: it only fed the changed-operation manifest, which "hash the collector source once" removed together with the base_sha input of collector-check.yml. Three workflow contract tests still asserted the fetch and the input, so the Repository Policy job failed: - test_migrated_workflows_keep_reviewed_safety_fixes drops its BASE_SHA fetch assertion and keeps the --depth=1 one; - _run_comparison_base checks only prediction-regression, the one remaining consumer of verify-target's comparison-base output; - test_collector_comparison_fetch_preserves_full_history is removed with the fetch it guarded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
…mla pool An RTX PRO 6000 run of the TRT-LLM DSA modules without the SM120 raise (1.3.0rc29, pipeline 78388970) failed every point of the seven selected tasks: 109 points of DeepSeek-V3.2 and GLM-5.2, BF16 and FP8 KV, context and generation. Each failure was TrtllmAttention's "DeepSeek-V4/DSA sparse MLA on SM120/SM121 requires kv_cache_config.dtype='fp8_ds_mla'" (attention/backends/trtllm.py). The DeepGEMM "Unsupported architecture" assert that the raise cited no longer fires, because rc29's DeepGEMM dispatches SM120. The same check covers DeepSeek-V4. Its attention inherits MLA, which hands extra_attrs["kv_cache_dtype"] (default "auto") to the backend, and collect_dsv4_attn sets fp8_ds_mla on SM90 only. - collector/skips.py leaves out TRT-LLM's DSA modules and the four DeepSeek-V4 attention modules on SM120, with the reason. The SM90 FP8-KV DSA entry drops its stale SM120 sentence. - run_mla_module loses the SM120 raise and its two FIXME comments. Queued on TRT-LLM SM120, before -> after (series rows / points): - dsa_context_module 540 / 33,330 -> 0; dsa_generation_module 660 / 11,310 -> 0; - dsv4_csa_context_module and dsv4_hca_context_module 72 / 4,504 -> 0 each; - dsv4_csa_generation_module and dsv4_hca_generation_module 88 / 1,600 -> 0 each. No other op, backend or SM changes. No shipped table has TRT-LLM rows for these ops on SM120. Timing them on the fp8_ds_mla pool, as serving does, is a follow-up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
dsv4_csa_topk_calib now plans every default DeepSeek-V4 checkpoint: skips.py no longer leaves sgl-project/DeepSeek-V4-Pro-FP8 out. Consumers key the top-k DELTA per native head geometry (128 heads for Pro, 64 for Flash), so Pro rows land in their own bucket and never replace Flash's. Until a collection ships them, Pro predictions keep running without the top-k correction. Default SGLang plans on SM90 to SM120 grow from 11 tasks and 763 points to 22 tasks and 1,526 points; plans below SM90 stay empty. A GPU smoke on SGLang 0.5.21 ran Pro's batch-1 and batch-1,024 tasks (168 points, up to a 1,048,575-token prefix and a 16,384-token prefill) on h200 and b200, one GPU each (pipelines 78444833 and 78444839): 336 rows per GPU, no failures. Rows are zero exactly where the compressed KV fits within Pro's top-k of 1,024 entries. At the points Flash's tables share, the non-zero values match Flash's: median ratio 1.01 on h200 and 1.00 on b200. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
The collector rules, skills and review instructions now describe the
collector as it is: every op except moe_a2a is on an op plan, and
collector/skips.py is the one place that leaves cases out.
- overview.md:
- the five things, with the Record now carrying one collector_hash
and the case_plan_hash;
- the failure principle;
- the rules and their checkers;
- an open-gaps table (moe_a2a, the vLLM XPU getters, Record counts,
the consumer signal) in place of the migration table.
- layer_permissions.md:
- one "Leaving cases out" section holds the four reasons a case may
be skipped;
- the capacity, kernel-selection, serving-parity, deviation, version
and module-boundary rules keep their substance;
- source citations name file and symbol;
- every re-check at a pin bump is listed once, in the version
contract.
- failure_handling.md and case_authoring.md point to those sections
instead of restating them:
- the op-plan section covers dispatch, rows and batch rows;
- the stale "tp=4" filter example is dropped.
- The collector op-development and auto-collect skills, the silicon
alignment skill, AGENTS.md and both CodeRabbit configurations drop
quant-axis min_sm floors, in-collector skips, capability floors and
generation-time memory filters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
Comments, docstrings and messages under collector/, tools/perf_database/ and the collector tests, rules and skills no longer narrate history: - Source citations name the file and symbol, or file:line, without a framework version: `file.py:12@1.3.0rc20` becomes `file.py:12`. - Decision dates, internal PR or issue numbers and most observation dates are gone, including the "owner policy" date on the one-release- per-file header of 22 collectors. - "Re-verify on the next bump" sentences are gone; the version contract in layer_permissions.md has every pin bump re-check citations, skips and notes. - A few history-only passages now state the current fact instead: the TRT-LLM MLA module header, the vLLM block-FP8 dispatch note, the SGLang Llama-4 router note and the all-reduce capture note. - Stale "capability floor" references point at collector/skips.py. Kept on purpose: - functional version strings: framework pins, __compat__, manifest versions, docker digests, data paths and version comparisons in code; - framework_manifest.yaml's retired-pin notes, which explain shipped tables; - the source fields of kernel_source_backends.yaml, which record where a label came from; - citations of upstream framework PRs (FlashInfer, vLLM, SGLang, TensorRT-LLM) that serve as sources; - FIXME(re-verify) comments, whose versions name the open question. Left for a follow-up: 62 comment lines in 25 collector files still date a source audit or a hardware observation. An example is the SGLang 0.5.14/0.5.17 audit at the top of sglang/collect_gemm.py. Several still explain how older shipped tables were collected, so each passage has to be read against the data before it is rewritten. No behaviour changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tianhao Xu <tianhaox@nvidia.com>
tianhaox
force-pushed
the
feat/collector-v4-gemm-plan
branch
from
November 2, 2026 01:54
f3a9a27 to
4d8ecf2
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
How to review
One commit per step; each builds on the previous one. Against main the forty-seven commits change 273 files, +10,392 / −16,712 lines.
.claude/rules/collector/overview.md,collector/notes/*.yaml, R8 intools/perf_database/check_collector_data.pycollect_gemm.pygetters,capabilities.yamlbackend_gapscollector/op_plans.py,tests/unit/collector/test_op_plans.pyop_plans.py,cases/base_ops/moe.yaml, the newbackend_gapsand guard notesop_plans.py; the getters are one lineOpPlan.dispatch, the new checks intest_op_plans.pyop_plans.py_run_case_idincollect.py, thearchitecturebackend gapsbackend_gapsand their two notescase_authoring.md, "Op plans"cases/models/LlamaForCausalLM_cases.yamlcollector/skips.py,plan()inop_plans.py,test_skips.py_die_with_worker_preexecincollector/helper.pysdk/utils.py, the MiMo record ingoldens/engine_step.jsonop_plans.py, the attention entries inskips.py,cases/base_ops/attention_*.yaml,test_attention_plan.pylayer_permissions.md,case_authoring.mdcollector/trtllm/module_series.py,test_module_series.pycollect_mla_module.py,op_backend_facts.yaml; 26 relabelled tablescollect_dsv4_attn.pyresolve_trtllm_mla_computeinsdk/models/helpers.py,test_context_fmha_compat.pystepfun-ai--Step-3.7-Flash*_config.json,THIRD_PARTY_NOTICES.mdbatch_rowsinop_plans.py,test_op_plans.pyop_plans.py,vllm/collect_mla_module.py,cases/base_ops/mla_module.yamlop_plans.py, the DSA entries inskips.py, the three DSA collectorsop_plans.py, the MSA entries inskips.py, the three MSA collectorssglang/collect_mla_module.pyandsglang/collect_msa_module.pyop_plans.py,sglang/runtime_limits.py, the threecollect_dsv4_attn.pysglang/deepseekv4_sparse_modules.pyop_plans.py, itsskips.pyentries_expand_moe_epskips.pycollector/provenance.py,collector-check.ymlcheck_collector_data.pysglang/deepseekv4_sparse_modules.pyworker pointsskips.pyrun_attention_torchinvllm/collect_attn_xpu.py,layer_permissions.mdskips.pyentries,MlaCase.local_headstests/test_ci_workflow_contracts.pyskips.pyskips.py,test_dsv4_common_test_cases.py.claude/rules/collector/overview.md, thenlayer_permissions.mdCommit IDs before the DCO rebuild
Commit 3 replaces commit 2's GEMM-specific plan code with the generic one. Commits 4, 5 and 7–10 add ops; most of commit 4's line count is MoE YAML policy and tests. Two commits touch the mechanism: commit 6 declares the kernel a backend measures instead of picking it inside rows, and commit 9 builds rows on demand so that rows may hold framework objects while planning stays framework-free. Commit 10 lets
--plan-onlyhash{id, params}rows by the ID a run records. Commit 11 turns three MoE regions the GPU validation found unservable on TRT-LLM into backend gaps; commit 13 adds the SM120 run to their notes. Commit 14 adds one attention shape through a model profile; attention itself stays on its getters. Commit 15 replaces the capability floors, backend gaps, guard notes and the empty denylist with one commented list,collector/skips.py, and adds four TRT-LLM model entries. Commit 16 is a follow-up to a #649 review comment. Commit 17 is the only SDK change: two layer-type fixes found while checking which models read the attention tables. Commit 18 moves attention onto the op plans. Commits 19–22 prepare the module ops: the TRT-LLM series runner, and two collector-side mismatches with what the SDK looks up (TRT-LLM MLA labels, DeepSeek-V4 KV on Blackwell). Commits 23–24 are SDK-side: TRT-LLM MLA FMHA resolution and the Step-3.7-Flash configuration. Commits 25–26 add batch rows and move the MLA attention modules onto op plans; commits 27–28 move the DSA modules and commit 29 the MSA modules. Commit 30 fixes how SGLang module refusals are classified. Commits 31–32 move DeepSeek-V4, and commits 33–34 the wide-EP ops. Commits 35–37 simplify: one SM120 skip, one collector hash, and the deviation notes as code comments. Commits 38–39 move the last SGLang-only ops. Commit 40 moves the DeepSeek-V4 calibration's model choice intoskips.py, commit 41 retires the last plan-time memory filter, and commit 42 stops planning cases that fail on every run. Commit 43 updates three CI contract tests for the comparison base that commit 36 removed. Commit 44 settles TRT-LLM DSA on SM120 with a GPU run, and commit 45 calibrates DeepSeek-V4-Pro's top-k by default. Commit 46 rewrites the collector rules for op plans, and commit 47 drops version narration from the collector's comments.Why and what changed
Sections 1–14 name guard notes (
G-…) andbackend_gapsas they were when each commit landed. Commit 15 turns each into a commented entry ofcollector/skips.pywith the same scope. Commit 37 turns the six deviation notes into code comments and removes R8.1. Collector notes replace the evidence mechanism
The change-to-evidence chain (
evidence_policy.yaml,evidence_check.py, the evidence waivers) was never wired into CI. This part removes it and gives known measurement gaps one machine-checked home.collector/notes/<backend>.yamlholds two kinds of note, each with a closed schema: a deviation (D-, the table measures something other than what serving runs) and a guard (G-, a case region the collector deliberately does not run). Each records scope,verified_on, sources,retire_viaandapproved_by; code and data cite the note id.check_collector_data.pyvalidates every notes file and fails when a note'sverified_onis behind the collector pin of a table in its scope, so a pin bump forces a re-check. It replaces feat: upgrade the op collector to vLLM 0.30.0, SGLang 0.5.21 and TRT-LLM 1.3.0rc29 #649'stest_standards_exceptions_verified_on.py..claude/rules/collector/overview.mddefines the five collector concepts (Pin, Plan, Record, Note, Rule) and the failure principle: every framework plans the same cases, only whole regions are left out at expansion, and guards are reserved for cases that would mismeasure, hang or waste significant GPU time. The other rule files, both collector skills,AGENTS.md, the CodeRabbit instructions and the collector docs follow it.2, 3 and 6. Op plans: one case list per op for every backend
Each backend's getter used to build its own case list, with its own SM ladder, shape filters and order, so the three tables covered different cases with nothing measured to justify the difference.
collector/op_plans.pyholds oneOpPlanper migrated op: its case type (a named tuple whose string form is the list form case IDs already use), an expand function (every case, in run order, fromcases/YAML), its dtype field and the fields that share one module build.plan(op, backend, sm)removes only the cases thatcollector/skips.pynames. Before commit 15, those were thecapabilities.yamlfloors andbackend_gaps. Each getter is one line,plan_cases("<op>", "<backend>", get_sm_version()).dispatch;--plan-onlycounts cases per dispatch and--plan-tableadds adispatchcolumn, so each case can be checked against what serving was observed to run.rows: the run arguments for one case and its dispatch. Rows say how a case runs, never whether; a case with no row raises.--plan-onlyruns on any CPU (tested with SGLang, vLLM, TensorRT-LLM and torch blocked).backend_gapswithcollector/skips.py(section 15).tests/unit/collector/test_op_plans.pyruns over every registered op: one-line getters, backends that differ only by skip-list entries, and the case string form. Migrating an op needs no new test file.--plan-only --sm Nreports each op plan's cases per dtype, the cases left out with the skip entry that matched, andplan_hash;--plan-table DIRwrites one CSV row per case.GEMM. The plan is the
gemm_typesaxis ofgemm.yamltimes the shared shapes. Removed per-framework filters, each with data already checked in:n<128 or k<128skipm*n or m*k >= 2^31skipn*k >= 2^31skipn%16 / k%16raise (SM90+)AIC_COLLECT_GEMM_TYPES, seed-42 shuffleOne backend gap: SGLang
fp8_blockon SM89/SM120 (G-sglang-gemm-fp8-block-deepgemm-only). SGLang'sFIXME(re-verify)serving gaps become deviation notesD-sglang-gemm-bf16-cutedsl,D-sglang-gemm-nvfp4-act-quantandD-sglang-gemm-fp8-block-triton-fallback, re-checked at v0.5.21.GEMM plan growth per system (cases added; none removed; vLLM unchanged): SGLang +7,918 on SM90/120 and +15,836 on SM100/103; TRT-LLM +45 on SM80, +8,269 on SM89/90 and +16,228 on SM100/103/120.
4. MoE
The three MoE getters read their own quant-mode list, per-model policy and parallel layouts from the same model rows, and planned 7,503 (SGLang), 9,552 (TRT-LLM) and 3,135 (vLLM) layer cases on SM100.
common_case_values.moe.quantization_modes, replaces themoe_sglang,moe_trtllmandmoe_vllmlists. A model row declares its checkpoint's modes inquantization_modes, the same for every backend; a row that declares none plans every mode.allowed_model_pathskeepsint4_woand the MXFP4 formats to the models that ship them. MoE rows may no longer declareframeworksor per-backendallowed_modes;framework_quantizationkeeps a backend'smodule_configand vllm_xpu's own policy only.min_latency_modeand, for nvfp4 on SM100/103 with at most 256 experts, the min-latency row.parallel: tp_ep, every SMG-vllm-moe-tp-and-epFusedMoEParallelConfig.makeflattens TP x DP into EP (config.py:1182-1228@v0.31.0)w4a8_mxfp4_mxfp8, SM120G-vllm-moe-w4a8-mxfp4-sm120oracle/mxfp4.py:367-390@v0.31.0)fp8, SM89+G-sglang-moe-fp8-not-collectedint4_woSM80/86,w4a8_mxfp4_mxfp8SM120G-sglang-moe-runner-unpinnedint4_wo, every SMG-trtllm-moe-int4-wo-no-implementationmoe_resolution.py:659-667@v1.3.0rc29); replaces the worker raise; every SM after the GPU validation (commit 11)fp8_blockSM89,w4a16_mxfp4SM89/120G-trtllm-moe-cutlass-sm-supportfp8_blockon SM89, TRT-LLMint4_wobelow SM100, TRT-LLMw4a16_mxfp4on SM89/120. The GPU validation then showed that SGLang runsfp8_blockon SM89 and that the three TRT-LLM regions have no implementation, so commit 11 declares those as backend gaps with the cited reason. The TRT-LLM seed-42 shuffle is gone.MoE cases queued per backend (TRT-LLM counts include min-latency rows):
Removed classes: bf16/fp8_block on the vLLM-only Nemotron latent width for SGLang and TRT-LLM; per-tensor fp8 on the GLM-5 shape, which no checkpoint ships; TRT-LLM
int4_woon every SM, which never produced a row; vLLMw4a16_mxfp4below the SM89 floor. WideEP: the vLLM EP population keeps its 46 distinct invocations and drops duplicates under the GLM-5 BF16/NVFP4 names.5. compute_scale and encoder attention
Both ops already queued the same cases on every backend, through three copies of the same getter. Each now queues exactly the case list it queued before, in the same order, at every SM. compute_scale's shared sweep moves from
framework_specific_op_cases.trtllmtoall_frameworks_op_cases. Encoder attention's token budget (128K) and 32-bit activation-index budget, applied identically by all three getters, now live once in the expand, which logs how many cases they leave out.7–10. Linear attention, MLA BMMs, MLA attention, mHC
G-vllm-mla-bmm-fp8-not-served: on NVIDIA, vLLM runs both BMMs as bf16torch.bmm; its fp8/fp4 BMMs are ROCm AITER only).Plan.rowsbuilds them on demand;--plan-onlyon a CPU counts the cases and reportsplan_hash: nullwith the missing module. Case changes: SGLang SM80/86, where the getter raised, become a backend gap (G-sglang-mla-backend-unmapped); SGLang now queues fp8 KV on its triton platforms SM89/120 (+1,540 context, +2,534 generation), whose filter had no citation; TRT-LLM drops fp8 on SM80/86 (−1,540 / −2,534) under the fp8 floor.architecture:G-sglang-mhc-glm5next-not-portedG-vllm-mhc-dsv4-shared-keyG-trtllm-mhc-glm5next-not-servedThe getters'
--smokeshortcut to 16 tokens is gone;--smokesamples four rows like every other op.14. Llama 3.1 405B attention shape
Llama 3.1 405B has 128 query and 8 KV heads. At TP1, as under pipeline parallelism, one rank runs all 128 heads. No base grid has that shape: the context grids stop at 96 query heads (64 on vLLM), and vLLM's decode grid stops at 64. The Llama profile now declares the 405B attention row for TP 1, 2, 4 and 8. The TP2–8 shapes deduplicate into the base grids.
The row applies to every backend, like every other attention row. On attention rows,
frameworkscan only exclude SGLang, and a backend-specific attention row is read by SGLang alone. A TRT-LLM-only row would therefore need a per-backend grid edit.SGLang cases carry the architecture of the profile that owns the shape. The 405B TP1–8 shapes now name
LlamaForCausalLMinstead ofQwen3MoeForCausalLMor none: 1,071 context and 1,168 generation cases per SM. Only their case IDs change. SGLang's FlashInfer workspace override covers Qwen2, Qwen3, MiMo and Qwen3-VL, and neither old nor new architecture is one of them. The perf row does not record the architecture.15. One commented list of skipped cases
Every rule that keeps cases out of a collection now lives in one list,
collector/skips.py. Each entry has a comment above it with the reason. Entries carry no IDs and no framework versions, and anyone can edit or delete an entry when its reason stops being true.backend,op,sm,model(the architecture of the case file a model row comes from),dtypeor any case field. A list value matches any of its items.capabilities.yamlfloors, now explicit SM lists;backend_gaps, now 12 entries;denylist.yaml;G-notes.capabilities.pyand op-planregion_fieldsare removed. The notes files keep the six deviation notes, and R8 now accepts onlyD-notes.plan()applies the list.collect.pyandfullnode.pyapply it around every getter and before queueing, so ops still on getters see it too.--plan-onlyprints the matching entry as the reason.modelentry drops that model's rows before deduplication, so a shape that another model also needs is still collected. Model runs (--model-path) drop every op that is skipped for all selected models.hash_closures.yamlnow listsskips.pyin the shared core instead ofcapabilities.py, so every module'scollector_hashchanges.16. Orphaned measurement child
This is a follow-up to a #649 review comment. If a worker dies between the fork and the child's
prctl(PR_SET_PDEATHSIG), the child has already been reparented and never gets the signal. Thepreexec_fnnow captures the worker pid in the parent. Afterprctl, the child exits when its parent is no longer the worker. Two unit tests cover both cases.17. SDK: MiMo-V2-Flash and Llama 4 layer types
These came up while checking which models read the attention tables (section 14).
hybrid_layer_patternmarks sliding-window layers with 1, and vLLM and SGLang build SWA attention there. The SDK read 1 as global, so it modeled 39 global and 9 SWA layers. It now models 9 global layers (one of them with a dense FFN) and 39 SWA layers.no_rope_layersis 0, or by default every fourth layer, which is how transformers fills an empty list. The SDK alternated layers, 24/24. It now models 12 global and 36 chunked layers.mimo-v2-flash-b200-vllm-hybrid-attn-xshapemoves, refreshed withpin_goldens.py --refresh.18. Attention
There is now one case list for SGLang, TRT-LLM and vLLM.
The shared grid. It is the generic full attention at head_dim 128 that all three backends already collected, plus every model's attention profile on every backend.
Model profiles.
frameworks:is retired.SGLang dispatch.
dispatch.Skip entries that name a kernel.
skips.pyentry may name adispatch. It then leaves the case out on that kernel only.Gemma 4 on TRT-LLM.
Gemma4ForCausalLM.get_model_defaults), so its rows run there.kernel_sourceis not a lookup key for TRT-LLM attention, so the consumer is unaffected.Decode budget.
Deviations, commented next to the rows.
Cases queued per SM. Measured GPU-free against 5aeba48: getter plus queue filter.
Every difference falls into one class:
All other rows keep their run arguments and case IDs.
19–20. TRT-LLM module series
TRT-LLM's DSA, MSA and DeepSeek-V4 module workers can now time a list of (seq_len, prefix_len) points in one task (
collector/trtllm/module_series.py).Unchanged:
max_seq_len, the DeepSeek-V4 HCA index-buffer width, and MSA's per-forward index-K pool copy. A manager shared across points would change what the smaller points measure.What the series saves:
Failures:
Small fix:
run_mla_modulenow releases its KV pool infinally.Commit 19 adds one line each to the layer-permission and case-authoring rules: a skip entry may name a dispatch kernel.
21. TRT-LLM MLA context labels
TRT-LLM's MLA context attention follows the KV cache dtype. With an FP8 KV cache it runs FP8 FMHA on SM90/100/103/120 (
thop/attentionOp.cpp).mla_dtype=bfloat16. The SDK looks up FP8 checkpoints (DeepSeek-V3/R1, Kimi-K2) with fmha fp8. On TRT-LLM those lookups missed the module table and quietly fell back to op-level ops. fix: correct TRT-LLM MLA labels and GPT-OSS MXFP4 profiles #264 fixed the op-level collector the same way.fp8.op_backend_facts.yamlfollows.backend_facts.py --checkandcheck_collector_data.pypass.22. DeepSeek-V4 KV pool on TRT-LLM Blackwell
The TRT-LLM DeepSeek-V4 collector timed a BF16 KV pool on SM100/103. The probe behind that choice tried only the packed
fp8_ds_mlapool, which is not servable off Hopper.23. TRT-LLM MLA FMHA on an FP8 KV cache
TRT-LLM has no separate precision for MLA attention. On SM90/100/103/107/120, an FP8 KV cache turns on FP8 context MLA (
mFP8ContextMLAinthop/attentionOp.cpp). Generation MLA runs FP8 for an FP8 KV cache on every SM. So TRT-LLM cannot run BF16 compute on an FP8 KV cache on those SMs. Since commit 21 the tables say so, and an explicitfmha=bfloat16on an FP8 KV cache finds no rows.helpers.resolve_trtllm_mla_computeresolves such a request to fp8 and logs a warning. It covers DeepSeek-V3/R1 and Kimi-K2/K2.5/K3.24. Step-3.7-Flash configuration
The packaged Step-3.7-Flash configs were normalized by hand when the model was added (AIConfigurator #1447 and #1452). They dropped two upstream values:
attention_other_setting. It gives the 33 sliding-attention layers 96 query heads (8 KV groups, head_dim 128), against 64 heads in the global layers.The SDK therefore sized every sliding layer with 64 heads, while the collector plans the 96-head shapes that vLLM, SGLang and TRT-LLM build.
Both files now carry the upstream values at pinned revisions:
stepfun-ai/Step-3.7-Flash@5f62440and-FP8@b3d7916.THIRD_PARTY_NOTICES.md, in both copies, records the files, revisions, the Apache-2.0 license and every normalization.25–26. Batch rows and the MLA attention modules
OpPlan.batch_rows[backend]lets one task time several cases. It returns pairs of (row, cases it times), andplan()checks that every kept case is timed by exactly one row. Dropped, doubled or foreign cases raise. Rows carry their points explicitly and never re-derive them.mla_context_moduleandmla_generation_modulemove onto op plans for TRT-LLM and vLLM. SGLang has no registered MLA module op.Heads. The heads are the union over the MLA models: DeepSeek-V3's 128…1 plus Kimi-K3's 96/48/24/12. This is the only point difference. TRT-LLM gains those four heads, +50% points on every SM, on its own precision combos. No point is lost.
Precision. The precision combos per backend and SM are unchanged (M2).
Rows.
run_mla_module_series_workertask per (model, heads, precision, batch), with explicit[seq_len, prefix_len]points.Memory. vLLM generation's KV-fit filter becomes a refusal at run time, before allocation (
does not fit …). The points refused on each device are exactly the ones the filter used to drop: 72 on H100-80GB, 36 on A100-80GB, 72 on L40S, none on H200, B200, B300 or RTX PRO 6000. H100 and H200 now get the same plan.Side effects.
--plan-onlysends planning output to stderr, so the module loader's notes no longer break its JSON.--resumefrom an older checkpoint re-runs them.27–28. DSA modules and SGLang's skip-indexer variants
dsa_context_moduleanddsa_generation_modulemove onto op plans for all three backends. SGLang's*_skip_indexervariants follow.Grid (one rule for every backend).
Models. One rule for every backend: the longest-context checkpoint per (architecture, operator GEMM). That gives DeepSeek-V3.2, GLM-5.2, GLM-5.2-FP8, and DeepSeek-V3.2-NVFP4 on SM100+.
Precision. Each backend keeps exactly its current precision combos. New
skips.pyentries record why:Device. The plan no longer depends on the device. SGLang's prefill-chunk and KV-pool checks and vLLM's generation memory filter now refuse points at run time, before allocation.
Rows.
run_mla_module_series_worker.dispatch.AIC_DSA_CONTEXT_*is gone.Context points per SM, before → after.
Why the counts move:
29. MSA modules
msa_context_moduleandmsa_generation_modulemove onto op plans for all three backends. The model is still MiniMax-M3 (1M context) at its TP 1–16 head shards, 64 to 4 heads.Grid. The DSA rule from section 27:
Precision. Each backend keeps exactly its current precision combos. New
skips.pyentries record why:vLLM's FP8 KV on SM80/86 now falls under the existing FP8 floor; no MSA table exists there.
TRT-LLM off SM100/103. On SM80–90 and SM120, TRT-LLM runs MSA on its Triton reference, a dense FP32 attention. A
skips.pyentry stops its context at a 32K prefix there, which replaces the 32,768-token Triton budget:Device. As for DSA, the plan no longer depends on the device. Points are refused at run time, before allocation:
SGLang's plan-time memory filter,
get_msa_head_countsand theAIC_MSA_*switches are gone.Rows.
run_msa_module_series_workertask per module build.Points per SM, before → after.
Why the counts move:
30. Refusals under torch.distributed
The DSA GPU diag on H200 refused 22 SGLang prefills as planned: more new tokens than the 8,192 SGLang chunks on that GPU. They were recorded as
unexpectedrather thankernel_limit. Under torch.distributed, SGLang's subprocess prefixes every output line with[rank0]:, so the parent found no traceback to read the classified error from. The DSA/MLA and MSA module runners now strip that prefix first.31–32. DeepSeek-V4 attention modules and sparse kernels
The CSA and HCA context and generation modules move onto op plans for all three backends.
dsv4_paged_mqa_logits_module(vLLM, SGLang) and SGLang'sdsv4_csa_topk_calibfollow.Grid. The long-context rule from section 27 applies, with DeepSeek-V4's top-k knees kept as anchors: 512 for Flash and 1,024 for Pro. Decode reaches 1M KV on every backend.
Precision. Each backend keeps its combinations on every SM.
skips.pyentries:deepseek-ai/*checkpoints take no fp8_block on SM90, replacing a device check.Device. SGLang now refuses points with a classified reason instead of skipping them silently:
The context hidden-state filter is gone: at 16,384 new tokens the BF16 hidden state stays under 250 MB, so it never triggered. The refusal helpers move to
sglang/runtime_limits.py, which MSA shares.Rows.
run_dsv4_attn_series_workertask per module build, so 72 context and 88 decode tasks instead of 5,840 and 1,544.topk_calibtakes its points from the CSA plan.paged_mqa_logitskeeps vLLM's 3,918-point grid, which SGLang now shares.AIS_DSV4_KV_CACHE_DTYPE,AIC_VLLM_DSV4_MAX_SEQ_LEN,AIC_VLLM_DSV4_SPARSE_MAX_QUERY_TOKENSand the--smokechecks.Points per kind, before → after (SM90 to SM120; SM80–89 plan none):
Why the counts move:
33–34. Wide-EP MoE and DeepEP
moe_ep(the SGLang and TRT-LLM wide-EP registries),deepep_llanddeepep_normalmove onto op plans.moe_ep cases. One case per large-EP build, from the
wideep: trueMoE rows: quant mode, routed-expert layer, EP size and EPLB layout.skips.pykeeps each backend's builds:Rows.
AIC_ACCURATE_WIDEEP_SIMis gone. Rows always carry the accurate simulation, which was already the default.deepep. One case per distinct (hidden, experts, top-k) of the packaged model configs, 25 shapes as before.
moe_a2a stays on its own population. Each backend's collector measures a different all-to-all library for one launched world (EP size and node count), with backend-specific axes. There is no shared case list to plan.
Builds per SM, before → after.
Why the counts move:
--resumefrom an older checkpoint reruns those rows.35. vLLM FP8-compute MLA context outside the SM100 family
vLLM takes FP8 prefill queries only on the SM100 family (
backend_supports_prefill_query_quantizationinmla_attention.py) and falls back to BF16 elsewhere.mla_context_moduleon SM120 goes from 972 to 648 cases.36. One collector hash
Before this commit:
collector_hashcovered a closure of files listed inhash_closures.yaml;Nothing has read that manifest since commit 1, and a missed closure entry silently weakens the hash: MSA's closure lacked
op_plans.py.Now.
collector_hashis one hash over:.py,.yaml,.yml,.shand.patchfiles undercollector/;JSON is left out, because the TRT-LLM MoE autotuners write their caches there.
Deleted:
hash_closures.yaml, the closure loader,tools/perf_database/changed_ops.pyand its CI steps.Unchanged:
collector_ref,case_plan_hashand thecollection_meta.yamlschema.37. Deviation notes as code comments
The six
D-notes move into comments at the code that deviates:sglang/collect_gemm.pytrtllm/collect_mhc_module.pyvllm/collect_computescale.pyvllm/collect_gemm.pyEach comment keeps what differs, the direction of the error, the sources and how to retire it.
collector/notes/, its schema and R8 are deleted, socheck_collector_data.pyis back to R1–R7. The four mHCreuse.yamlfiles point at the code comment.The cost: a framework pin bump no longer forces a re-check of these six deviations.
38–39. GLM-5 sparse kernels and DeepSeek-V4.1
GLM-5 sparse kernels.
glm5_mqa_logits_module,glm5_topk_moduleandglm5_dsa_attn_module(SGLang) take the DSA module plan's points for their checkpoint, on the shared long-context grid.--smokesampling is gone.skips.pyentries keep today's model choice: GLM-5 on Hopper, GLM-5.2-NVFP4 on SM100/103/120.dsv32_dsa_sparse_modules.pyis deleted. It was unregistered, with no table and no consumer.Points go from 3,026 to 672 on SM90 and from 3,333 to 692 on SM100/103/120, still in 11 tasks per SM.
DeepSeek-V4.1.
dsv41_module's existing{id, params}rows become the plan's rows.DSV41_EXECUTION_PROFILEis gone. To run one profile, use--case-filter dsv41_full_or--case-filter dsv41_decoder_bounded_.40. DeepSeek-V4 top-k calibration through skips.py
The calibration plan used special plan code, with a log line, to drop DeepSeek-V4-Pro. Now one
skips.pyentry leavessgl-project/DeepSeek-V4-Pro-FP8out, and the default rows are unchanged (11 per SM on SM90–120).Without Pro's table, the SDK applies no top-k correction to Pro, and its CSA context-parallel model refuses to run. Commit 45 removes the entry again.
41. XPU attention capacity at run time
The vLLM XPU attention getters dropped cases by a generation-time memory budget; this was the last plan-time memory filter.
run_attention_torchnow refuses a KV pool the device cannot hold before allocating it (FIXME(kernel-limit): does not fit …).The XPU getters themselves stay outside op plans: XPU has no SM and keeps its own case lists (Follow-ups).
42. Static guards into skips.py
A run-time
FIXME(kernel-limit)raise whose condition depends only on case fields and the SM fails on every run. The plan no longer queues those cases, andskips.pyentries carry the reasons.mla_context/mla_generationmla_generationmoe_epThese guards stay at run time:
43. CI contract tests
Commit 36 removed Collector Data's comparison-base fetch and the
base_shainput ofcollector-check.yml, together with the changed-ops manifest they served. Three tests intests/test_ci_workflow_contracts.pystill asserted them, so Repository Policy failed.--depth=1check and drops theBASE_SHAfetch check.prediction-regression, the remaining consumer ofverify-target's comparison base.44. TRT-LLM sparse MLA on SM120
A GPU run decided the SM120 guard of the TRT-LLM DSA modules (rtx pro 6000, TRT-LLM 1.3.0rc29, pipeline 78388970). With the raise removed, all 109 points of the seven selected tasks failed. The tasks covered DeepSeek-V3.2 and GLM-5.2, BF16 and FP8 KV, context and generation. Each point failed with
TrtllmAttention's "DeepSeek-V4/DSA sparse MLA on SM120/SM121 requires kv_cache_config.dtype='fp8_ds_mla'". The DeepGEMM assert that the raise cited no longer fires.collect_dsv4_attnbuilds the fp8_ds_mla pool on SM90 only.skips.pyentry leaves out TRT-LLM's DSA modules and the four DeepSeek-V4 attention modules on SM120, and the raise goes.45. DeepSeek-V4-Pro top-k calibration
Commit 45 removes the
skips.pyentry of commit 40, so the default SGLang plans calibratesgl-project/DeepSeek-V4-Pro-FP8next to Flash.46. Collector rules
The rules, skills and review instructions describe the collector as it now is: every op except moe_a2a is on an op plan, and
collector/skips.pyis the one place that leaves cases out.overview.md: the collector in five things (Pin, Plan, Record, Note, Rule), the failure principle, the rules and their checkers, and an open-gaps table (moe_a2a, the vLLM XPU getters, Record counts, the consumer signal).layer_permissions.md: one "Leaving cases out" section holds the four reasons a case may be skipped. The capacity, kernel-selection, serving-parity, deviation, version and module-boundary rules keep their substance, and the version contract lists every re-check a pin bump needs.failure_handling.mdandcase_authoring.mdpoint to those sections instead of restating them.AGENTS.mdand both CodeRabbit configurations no longer mention quant-axismin_smfloors, in-collector skips, capability floors or generation-time memory filters.47. Version narration
Comments, docstrings and messages under
collector/,tools/perf_database/and the collector tests, rules and skills state current facts instead of history. There are no behaviour changes.file:line, without a framework version.layer_permissions.mdmakes every pin bump re-check citations, skips and notes.sourcefields ofkernel_source_backends.yaml;FIXME(re-verify)comments.Review map
collector/op_plans.py,collector/skips.py,--plan-table, aplansblock in--plan-onlyJSON.collector/skips.pyreplacescapabilities.yaml(floors andbackend_gaps),denylist.yamland theG-notes.collector/notes/with R8,hash_closures.yaml, andtools/perf_database/changed_ops.pywith its CI step.collector_hashkeeps its field but is one hash over the collector source.cases/base_ops/moe.yamlmoves to one quant-mode axis; MoE model rows usequantization_modes.evidence_policy.yamlandevidence_exceptions.yamlare removed.--resumefrom an older checkpoint runs those cases again.mhc/trtllm/1.3.0rc23/reuse.yamlfiles only change their reason comment). A re-collection adds or drops the cases above. Rollback is a revert.Evidence
pytest tests/unit/collector tests/unit/toolsat b287241: 4,624 passed, 32 skipped, 0 failed (12 min 48 s).test_op_plans, the MoE population, dedup, model-case, capabilities and provenance tests at b012f30: 316 passed.check_collector_data.pyR1–R8 OK;test_check_collector_dataandtest_op_plans239 passed.pytest tests/unit/collector tests/unit/tools4,776 passed, 31 skipped, 1 failed (12 min 32 s); the failure was the SGLang SM90 structural population count, updated in the commit; the attention, case-generation, profile and op-plan tests then pass (669). The attention getters were dumped GPU-free before and after for the three backends at SM80–120: the added cases are exactly the counts in section 14, and no case is removed.check_collector_data.py: R1–R8 OK.ruff@0.14.1 checkandformat --checkare clean; the documentation-link check passes.m*n or m*k >= 2^31n*k >= 2^31pytest tests/unit/collector tests/unit/tools: 4,758 passed, 31 skipped, 0 failed (13 min 30 s).pytest tests/unit/sdk: 5,368 passed, 13 skipped, 1 failed. The failure istest_fpm_learned::test_feature_list_is_unique_and_bounded, which needs scikit-learn and is not installed here; it fails the same way without this PR.test_engine_step_parity.pyandtest_compile_engine_parity.py: 389 passed, after the MiMo refresh in commit 17.ruff@0.14.1 checkandformat --checkonpython/aisimulateandtests: clean.pytest tests/unit/collector tests/unit/tools: 4,774 passed, 32 skipped, 0 failed (13 min 30 s).ruff: clean.--plan-onlyand--plan-table: checked for SGLang on SM100.test_fpm_learnedneeds scikit-learn, which is not installed here.backend_facts.py --checkandcheck_collector_data.py: clean.pytest tests/unit: 13,913 passed. The one failure,test_fpm_learned, needs scikit-learn.check_packaged_legal_files.py: passes.skips.pyentry sets.kernel_limit:pytest tests/unit: 14,165 passed. The one failure,test_fpm_learned, needs scikit-learn.check_collector_data.pyandbackend_facts.py --check: clean.kernel_limit. There are no other failures.pytest tests/unit: 14,097 passed. The one failure,test_fpm_learned, needs scikit-learn.check_collector_data.py(R1–R7),backend_facts.py --checkand the documentation-link check: clean.pytest tests/unit: 14,139 passed. The one failure,test_fpm_learned, needs scikit-learn.check_collector_data.py,backend_facts.py --checkand the documentation-link check: clean.tests/(the Full CI contracts shard, without the workflow contracts) andtests/cross_package, at 4c26239 and at main (e8cbe2d) in the same environment: identical results.pytest tests/unit/collector tests/unit/tools: 5,027 passed.pytest tests/unit tests/goldenand parity ran at 5516da4f1, which differs from f3a9a27 only in comment text. Unit and golden: 14,151 passed; the one failure,test_fpm_learned, needs scikit-learn. Parity: 389 passed.check_collector_data.py,backend_facts.py --check, and the documentation-link, copyright and CODEOWNERS checks: clean.Signed-off-bymatching its author, and the messages are otherwise unchanged.pytest tests/unit/collector tests/unit/tools: 5,027 passed; ruff: clean.Modeling or data provenance
mla_dtypelabel of 51,187 rows in 26 shipped TRT-LLM MLA context tables (section 21). Latencies and every other column are unchanged; no other table rows change.collector_hashas every other table collected at that revision.Follow-ups (not in this PR)
w4a8_mxfp4_mxfp8for gpt-oss and Kimi-K3. Probe-based dispatch decides which MXFP4 path vLLM serves them with.w4a16_mxfp4on SM80/86.collector/skips.pykeeps it off these SMs on every backend, carried over from the old floor. There is no recorded reason for vLLM, so recheck it against a vLLM run.Tracking
🤖 Generated with Claude Code