Skip to content

fix(linear): repair B12X kernel registry after the b12x_block rebase - #50

Merged
randomvariable merged 3 commits into
homelabs-mainfrom
fix/b12x-block-import-rebase-fallout
Aug 19, 2026
Merged

randomvariable merged 3 commits into
homelabs-mainfrom
fix/b12x-block-import-rebase-fallout

Conversation

@randomvariable

Copy link
Copy Markdown
Owner

Purpose

import vllm.model_executor.kernels.linear.scaled_mm raised:

ModuleNotFoundError: No module named
  'vllm.model_executor.kernels.linear.scaled_mm.b12x_block'

which aborted collection of every test touching the package — including tests/v1/attention/test_flashinfer_sparse_mla_sm120_api.py, whose failure had been misread as an environment limitation.

Root cause: upstream 4ab5e5012a (#52368) consolidated scaled_mm/b12x_block.py and scaled_mm/b12x_tensor.py into scaled_mm/b12x.py, and replaced the standalone warmup_b12x_*_linear functions with a get_b12x_warmup_unit provider protocol. The rebase took the new module and the file deletion but left the old import paths and several duplicated registrations behind.

Pulling that thread surfaced five further defects, all from the same half-applied refactor.

Defects fixed

1. Dead import path (the reported P0). scaled_mm/__init__.py imported from the deleted b12x_block. Pointed at b12x, matching linear/__init__.py, which was already correct.

2. Duplicate registrations silently reordering kernel priority. Three lists carried the same kernel twice, because the fork registered it before upstream did and the rebase kept both entries — with the duplicate at the head of the list, so it took priority:

List Duplicated kernel Effect of the stale head entry
_POSSIBLE_FP8_KERNELS MarlinFP8ScaledMMLinearKernel Marlin ahead of FlashInfer and Cutlass
_POSSIBLE_NVFP4_KERNELS B12xNvFp4LinearKernel B12X ahead of every FlashInfer path
_POSSIBLE_MXFP4_KERNELS B12xMxFp4LinearKernel B12X ahead of FlashInfer/Marlin/Humming

Blame confirms the provenance: the head entries are fork commits e080b6ed0e (2026-07-21) and the pre-vllm-project#52182 Marlin position; the lower entries are upstream 3c79b1a8bf (vllm-project#52016) and bca7bea240 (vllm-project#52182). Upstream's positions are the maintained ones and the registration-priority tests already pin them, so the head duplicates are dropped.

Selection via explicit --linear-backend resolves through _LINEAR_BACKEND_KERNEL_MAP, not list order — verified by the test that monkeypatches _get_linear_backend — so the qualified B12X serving path is unaffected.

3. _POSSIBLE_MXFP6_KERNELS defined twice, identically. mypy rejects the redefinition as soon as the file is touched.

4. mxfp8/b12x.py missing three imports. It referenced b12x_warmup_token_counts, Iterable and Any without importing any of them, so warmup_b12x_mxfp8_linear raised NameError as soon as it found a layer to warm.

5. Three test files importing deleted symbols. test_b12x_linear.py imported from both b12x_block and b12x_tensor; the latter's two symbols were unused and one (_b12x_tensor_fp8_linear) no longer exists anywhere. test_b12x_{mxfp4,nvfp4}_linear.py imported the deleted standalone warmup functions.

Test migration

The FP4 warmup tests moved onto the provider protocol rather than being deleted: the dedupe contract now lives in unit.key, so they assert that two layers with the same weight signature produce equal keys and a differing one does not, then compile the distinct units. The per-call weight/alpha/bias assertions carry over unchanged, so the same behaviour is pinned — only the entry point moved. Marker assertions (layer.b12x_mxfp4_linear) became provider-identity assertions, matching what process_weights_after_loading now sets.

Test Plan

.venv/bin/python -m pytest tests/model_executor/kernels/ -q
.venv/bin/python -m pytest tests/v1/attention/test_flashinfer_sparse_mla_sm120_api.py -q
.venv/bin/pre-commit run --files <the seven changed files>

Duplicate check:

for name in ("_POSSIBLE_FP8_KERNELS", "_POSSIBLE_FP8_BLOCK_KERNELS",
             "_POSSIBLE_MXFP8_KERNELS", "_POSSIBLE_MXFP4_KERNELS",
             "_POSSIBLE_NVFP4_KERNELS", "_POSSIBLE_MXFP6_KERNELS"):
    for platform, kernels in getattr(L, name).items():
        assert len({k.__name__ for k in kernels}) == len(kernels)

Test Result

  • tests/model_executor/kernels/: 49 passed — previously 3 of 4 files could not be collected
  • tests/v1/attention/test_flashinfer_sparse_mla_sm120_api.py: 5 passed — previously uncollectable
  • duplicate check: 0 duplicate lists remaining (was 4)
  • pre-commit: exit 0 (ruff, ruff-format, mypy 3.10)

Known remaining drift

Not fixed here, deliberately, because resolving it needs on-device evidence rather than a guess:

scaled_mm/b12x_tensor.py survives as a duplicate of b12x.py's B12xTensorFP8ScaledMMLinearKernel, and warmup/kernel_warmup.py still calls its standalone warmup_b12x_tensor_fp8_linear while also calling b12x_warmup. Both select layers by the b12x_tensor_fp8_packed_weight attribute that b12x.py sets, so the tensor-FP8 path is plausibly warmed twice. Confirming that — and removing the stale file — wants a GB10 warmup log, so it is left for the image build.

AI assistance was used for this change.

randomvariable and others added 3 commits August 19, 2026 17:14
The nvidia DeepseekV4DecoderLayer exposes hc_pre and hc_post_pre but no
hc_post wrapper: the model calls mhc_post_tilelang directly from
DeepseekV4Model.forward. The warmup sweep therefore compiled the pre and
fused-post-pre kernels but left mhc_post to JIT on the first request that
reached the end of the layer stack.

Call mhc_post_tilelang alongside hc_post_pre in the sweep. Its token
dimension is T.dynamic and it takes no split-k factor, so any shape warms
every shape; it rides the existing loop rather than a separate pass.

Add token-size selection tests pinning the invariant that the sweep
covers both split-k families: mhc_pre/mhc_fused_post_pre derive split-k
from hc_mult * hidden_size while mhc_pre_broadcast uses hidden_size
alone, and the smaller K only merges plateaus, so the broadcast
transitions are a subset of the swept ones.

Adapted from vllm-project#52941. The PR's primary change - detecting
nvidia layers that lack hc_pre/hc_post and calling tilelang directly -
does not apply: this fork's nvidia layer does define those wrappers, so
_find_first_mhc_layer already matches and the sweep already runs.

Co-authored-by: OMP Agent <noreply@omp.local>
Signed-off-by: Naadir Jeewa <naadir@randomvariable.co.uk>
Upstream 4ab5e50 (vllm-project#52368) consolidated scaled_mm/b12x_block.py and
scaled_mm/b12x_tensor.py into scaled_mm/b12x.py. The rebase took the new
module and the deletion of b12x_block.py, but left the old import paths
and several duplicated registrations behind.

scaled_mm/__init__.py still imported from the deleted b12x_block module,
so importing vllm.model_executor.kernels.linear.scaled_mm raised
ModuleNotFoundError. That aborted collection of every test touching the
package, including tests/v1/attention/test_flashinfer_sparse_mla_sm120_api.py.
Point it at b12x, matching linear/__init__.py, which was already correct.

Three priority lists carried the same kernel twice, because the fork
registered it before upstream did and the rebase kept both entries:

  _POSSIBLE_FP8_KERNELS   MarlinFP8ScaledMMLinearKernel
  _POSSIBLE_NVFP4_KERNELS B12xNvFp4LinearKernel
  _POSSIBLE_MXFP4_KERNELS B12xMxFp4LinearKernel

The duplicates sat at the head of each list, so they silently took
priority: Marlin ahead of FlashInfer and Cutlass for FP8, and B12X ahead
of every FlashInfer path for FP4. Drop them and keep upstream's
positions, which the registration-priority tests already pin. Selection
by explicit --linear-backend resolves through
_LINEAR_BACKEND_KERNEL_MAP rather than list order, so the qualified B12X
serving path is unaffected.

_POSSIBLE_MXFP6_KERNELS was defined twice, identically; mypy rejects the
redefinition as soon as the file is touched.

mxfp8/b12x.py referenced b12x_warmup_token_counts, Iterable and Any
without importing any of them, so warmup_b12x_mxfp8_linear raised
NameError when it found a layer to warm.

tests/model_executor/kernels/test_b12x_linear.py imported from
b12x_block and from b12x_tensor; the latter's two symbols were unused,
and one of them (_b12x_tensor_fp8_linear) no longer exists anywhere.
Import from the package facade, as upstream's copy of this file does.

tests/model_executor/kernels/test_b12x_linear.py: 33 passed (was: no
collection). tests/v1/attention/test_flashinfer_sparse_mla_sm120_api.py:
5 passed (was: no collection).

Co-authored-by: OMP Agent <noreply@omp.local>
Signed-off-by: Naadir Jeewa <naadir@randomvariable.co.uk>
Upstream 4ab5e50 (vllm-project#52368) replaced the standalone
warmup_b12x_{mxfp4,nvfp4}_linear functions with a get_b12x_warmup_unit
provider that b12x_warmup discovers through layer.b12x_warmup_provider,
and dropped the b12x_{mxfp4,nvfp4}_linear marker attributes. The rebase
took the new kernels but left these two test files importing the deleted
functions, so neither collected.

Assert the contract where it now lives: two layers with the same weight
signature produce equal unit keys and a differing one does not, and
compiling a unit runs the kernel once per token count. The per-call
weight, alpha and bias assertions carry over unchanged, so the same
behaviour is still pinned - only the entry point moved. The marker
assertions become provider-identity assertions.

tests/model_executor/kernels/: 49 passed (was: 2 files uncollectable).

Co-authored-by: OMP Agent <noreply@omp.local>
Signed-off-by: Naadir Jeewa <naadir@randomvariable.co.uk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant