Skip to content

moe: bound W4A16 scratch and repair tail correctness - #109

Closed
voipmonitor wants to merge 16 commits into
masterfrom
fix/w4a16-reachable-block-scratch-master-20260801
Closed

moe: bound W4A16 scratch and repair tail correctness#109
voipmonitor wants to merge 16 commits into
masterfrom
fix/w4a16-reachable-block-scratch-master-20260801

Conversation

@voipmonitor

@voipmonitor voipmonitor commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Bound unpinned W4A16 scratch to launch geometries reachable within the declared token capacity, expose a cheap arena-size query, and repair the tail cases that the tighter planner made reproducible.

This is the current-master successor to #100. It contains only the commits after that PR's obsolete stacked base; no already-merged Trellis history is replayed.

Planner changes

  • Compute the conservative set of route block sizes reachable for 1 <= m <= max_tokens.
  • Size fused and replicated-input EP route buffers only for that set.
  • Account independently for packed-route and direct-top-k/TC-decode c_tmp geometry.
  • Preserve explicit block pins and mapped full-rotation Trellis behavior.
  • Export fused_moe.required_nbytes(Caps) without compiling or retaining a launch.

For the documented max_tokens=64, topk=8, E=160, H=6144, I/rank=512 case, the unpinned non-full W4A16 arena falls from 94.94 MiB to 30.03 MiB per rank. This does not alter kernel selection or numerical math.

Correctness repairs

The bounded arena exposed pre-existing generic W4A16 tail defects. This PR also:

  • clears or masks stale direct-FC2 scratch lanes;
  • preserves native ModelOpt E8M0 scale strides and non-64 scale tails;
  • bounds weight, scale, and activation tail loads by logical rows;
  • chooses FC1 chunk counts that partition the logical intermediate into whole 16-value blocks;
  • covers narrow and wide non-aligned residue classes in fused and EP paths.

Aligned production shapes retain their existing geometry.

Verification

32 passed, 80 skipped

Focused suites cover fused/EP planning, route packing, replay, non-aligned native shapes, and W4A16 E2E cases. Changed-file Ruff checks and git diff --check pass.

No merge is performed by this PR creation.

Summary by CodeRabbit

  • New Features

    • Added required_nbytes to estimate fused MoE workspace requirements without launching computation.
    • Improved automatic routing capacity and block-size selection for varied workloads.
  • Bug Fixes

    • Improved handling of non-aligned dimensions and padded scale layouts.
    • Prevented out-of-bounds loads, stale intermediate data, and NaN results in W4A16/NVFP4 operations.
  • Tests

    • Expanded coverage for workspace planning, routing capacities, bounds safety, scale padding, and non-aligned model dimensions.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates ModelOpt W4A16 and E8M0 scale layouts, adds logical-width safety checks, replaces fixed route-size planning with capacity-aware sizing, and exposes required_nbytes for fused MoE scratch planning.

Changes

MoE kernel and scale layout safety

Layer / File(s) Summary
Padded scale preparation and addressing
sparkinfer/moe/_shared/kernels/micro.py, sparkinfer/moe/_shared/kernels/w4a16/prepare.py, tests/moe/test_w4a16_e2e.py
ModelOpt scale preparation and FC1 consumers now use padded 64-row or 64-column layouts. Tests cover padded E8M0 dimensions and parameterized intermediate sizes.
Logical-width kernel validation and tail masking
sparkinfer/moe/_shared/kernels/micro.py, tests/moe/test_w4a16_e2e.py
W4A16 loads, prefetches, chunk retiling, and intermediate tails now use logical-width validity checks. CUDA tests cover non-64-aligned shapes, stale tails, bounds safety, deterministic replay, and oracle agreement.

Capacity-aware route and scratch planning

Layer / File(s) Summary
Capacity-specific route planning
sparkinfer/moe/_shared/kernels/w4a16/host.py, sparkinfer/moe/ep_moe/_impl.py, sparkinfer/moe/fused_moe/_impl.py, tests/moe/test_ep_moe_api.py, tests/moe/test_w4a16_route_pack.py, tests/moe/test_w4a16_e2e.py
Route block sizes now derive from token capacity, top-k, and expert count. Fused planning accounts for direct-route and TC-decode slot requirements.
Scratch-size query and planner reuse
sparkinfer/moe/fused_moe/_impl.py, sparkinfer/moe/fused_moe/api.py, sparkinfer/moe/fused_moe/__init__.py, tests/moe/test_fused_moe_planning.py
The public required_nbytes API returns planned arena bytes. Scratch allocation reuses the shared caps-based arena layout helper. Tests compare size queries with planned storage and validate workspace dimensions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: lukealonso, brandonmmusic-max

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: bounding W4A16 scratch allocation and fixing tail correctness.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/w4a16-reachable-block-scratch-master-20260801

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@sparkinfer/moe/_shared/kernels/micro.py`:
- Around line 2485-2489: Update the w1_scales layout declarations around the
E8M0/W4A16 setup to use the same padded column extent as the kernel’s scale
stride, `_align_up(cfg.two_n, 64)`, rather than raw `cfg.two_n`. Keep the layout
and preparation allocation consistent for non-64-aligned widths, while
preserving the existing E8M0 and W4A16 dimension-specific behavior.

In `@sparkinfer/moe/_shared/kernels/w4a16/prepare.py`:
- Around line 1186-1191: Align padded_w13_scale_n in the preparation path with
W4A16GemmKernel.scale_size_n: apply the 64-row E8M0 padding only when
scale_format_e8m0_k32 and has_n_tile_tail, matching the kernel’s scale_n_groups
and stride calculation. Preserve the unpadded row count for tile-aligned
dimensions without a W2 compact K tail, including multi-chunk FC1.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 115b57fb-6662-461c-af6d-8bfe2c4630cb

📥 Commits

Reviewing files that changed from the base of the PR and between b0976b7 and f83e94f.

📒 Files selected for processing (11)
  • sparkinfer/moe/_shared/kernels/micro.py
  • sparkinfer/moe/_shared/kernels/w4a16/host.py
  • sparkinfer/moe/_shared/kernels/w4a16/prepare.py
  • sparkinfer/moe/ep_moe/_impl.py
  • sparkinfer/moe/fused_moe/__init__.py
  • sparkinfer/moe/fused_moe/_impl.py
  • sparkinfer/moe/fused_moe/api.py
  • tests/moe/test_ep_moe_api.py
  • tests/moe/test_fused_moe_planning.py
  • tests/moe/test_w4a16_e2e.py
  • tests/moe/test_w4a16_route_pack.py

Comment on lines +2485 to +2489
e8m0_w1_n_cols = _align_up(cfg.two_n, 64)
ebase_sf_packed = Int64(eid) * Int64((cfg.k_dim // 32) * e8m0_w1_n_cols)
ebase_sf_packed_e4m3 = Int64(eid) * Int64(
(cfg.k_dim // 16) * _align_up(cfg.two_n, 64)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Compare declared micro scale tensor extents against the padded FC1 scale stride.
set -euo pipefail

# Locate the padded-stride helper and every micro scale tensor declaration.
rg -n -C4 '_align_up\(\s*cfg\.two_n\s*,\s*64\s*\)' sparkinfer/moe/_shared/kernels/micro.py
rg -n -C6 'w1_scales\s*=\s*cute\.make_tensor' sparkinfer/moe/_shared/kernels/micro.py

# Confirm the preparation side actually allocates the padded width.
rg -n -C6 '_e8m0_logical_tail_scale_n|_PACKED_TILE_N_SIZE' sparkinfer/moe/_shared/kernels/w4a16/prepare.py

Repository: local-inference-lab/sparkinfer

Length of output: 7842


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the full FC1 padded stride definition and surrounding preparation validation/production.
sed -n '2460,2505p;5020,5050p' sparkinfer/moe/_shared/kernels/micro.py
sed -n '1,80p;1140,1205p;1205,1255p' sparkinfer/moe/_shared/kernels/w4a16/prepare.py

# Check whether declared scale extents are used to create layouts/tensors accessed later by the patched code.
python3 - <<'PY'
from pathlib import Path
p=Path('sparkinfer/moe/_shared/kernels/micro.py')
s=p.read_text()
for needle in ['w1_sf_rows * cfg.w1_sf_cols', 'cfg.two_n * cfg.k_half', 'cfg.weight_E * (cfg.k_dim // 32) * cfg.two_n', 'cfg.weight_E * (cfg.k_dim // 16) * cfg.two_n']:
    print(needle, s.count(needle))
PY

Repository: local-inference-lab/sparkinfer

Length of output: 11012


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the full FC1 padded stride definition and surrounding preparation validation/production.
sed -n '2460,2505p;5020,5050p' sparkinfer/moe/_shared/kernels/micro.py
sed -n '1,80p;1140,1205p;1205,1255p' sparkinfer/moe/_shared/kernels/w4a16/prepare.py

# Check whether declared scale extents are used to create layouts/tensors accessed later by the patched code.
python3 - <<'PY'
from pathlib import Path
p=Path('sparkinfer/moe/_shared/kernels/micro.py')
s=p.read_text()
for needle in ['w1_sf_rows * cfg.w1_sf_cols', 'cfg.two_n * cfg.k_half', 'cfg.weight_E * (cfg.k_dim // 32) * cfg.two_n', 'cfg.weight_E * (	cfg.k_dim // 16) * cfg.two_n']:
    print(needle, s.count(needle))
PY

Repository: local-inference-lab/sparkinfer

Length of output: 11013


Align w1_scales layout extents with the padded scale stride.

The kernel advances the scale base by _align_up(cfg.two_n, 64), but w1_scales layouts at lines 5036-5043 still use unpadded cfg.two_n. Preparation allocates the padded width for E8M0/W4A16, so the raw pointer reads are in bounds. The layout extent only matches if cfg.two_n is a multiple of 64; either align the declaration for non-64-aligned sizes or keep the layout size equal to the prepared padded column count.

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

In `@sparkinfer/moe/_shared/kernels/micro.py` around lines 2485 - 2489, Update the
w1_scales layout declarations around the E8M0/W4A16 setup to use the same padded
column extent as the kernel’s scale stride, `_align_up(cfg.two_n, 64)`, rather
than raw `cfg.two_n`. Keep the layout and preparation allocation consistent for
non-64-aligned widths, while preserving the existing E8M0 and W4A16
dimension-specific behavior.

Comment on lines +1186 to +1191
# Packed E8M0 scale rows are permuted in 64-row blocks independently of
# whether W2 has a compact K tail. Ungated 32-aligned intermediates such
# as I=224 therefore still need W13's 224 scale rows padded to 256; tying
# this padding to ``allow_w2_k_tail`` advertised the direct shape and then
# rejected it during preparation.
padded_w13_scale_n = _e8m0_logical_tail_scale_n(w13_rows)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Trace the main W4A16 GEMM's W13 scale stride derivation.
set -euo pipefail

rg -n -C6 '_e8m0_logical_tail_scale_n' sparkinfer/moe/_shared/kernels/w4a16/

# Inspect how the main GEMM sizes and strides the packed W13 E8M0 scale grid.
rg -n -C8 'w13_scales_i32_flat|w13_scale.*stride|two_n.*32|scale_format.*e8m0' sparkinfer/moe/_shared/kernels/w4a16/kernel.py | head -120

Repository: local-inference-lab/sparkinfer

Length of output: 11911


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## prepare.py relevant section"
sed -n '1140,1215p' sparkinfer/moe/_shared/kernels/w4a16/prepare.py

echo "## kernel.py W13 layout/type construction"
sed -n '650,720p' sparkinfer/moe/_shared/kernels/w4a16/kernel.py

echo "## kernel.py data preparation around scale tensors"
sed -n '778,855p' sparkinfer/moe/_shared/kernels/w4a16/kernel.py

echo "## stride/array accesses mentioning scale_size_n/scale_n_groups"
rg -n -C4 'scale_size_n|scale_n_groups|covered_size_n|self\.n_tiles|w1_scale|w13_scales_i32_flat|packed_w13_scale' sparkinfer/moe/_shared/kernels/w4a16/kernel.py

Repository: local-inference-lab/sparkinfer

Length of output: 20241


Align prepare.py’s padded_w13_scale_n with W4A16GemmKernel.scale_size_n.

prepare.py now always rounds W13 E8M0 scale rows up to 64, but W4A16GemmKernel only applies that padding when scale_format_e8m0_k32 and has_n_tile_tail. For I equal to a multiple of tile_k without a W2 compact K tail, the main kernel may use a smaller scale_n_groups/stride than the padded packed_w13_scale grid, especially with multi-chunk FC1. Use the same padding/stride calculation for both paths.

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

In `@sparkinfer/moe/_shared/kernels/w4a16/prepare.py` around lines 1186 - 1191,
Align padded_w13_scale_n in the preparation path with
W4A16GemmKernel.scale_size_n: apply the 64-row E8M0 padding only when
scale_format_e8m0_k32 and has_n_tile_tail, matching the kernel’s scale_n_groups
and stride calculation. Preserve the unpadded row count for tile-aligned
dimensions without a W2 compact K tail, including multi-chunk FC1.

@voipmonitor

Copy link
Copy Markdown
Contributor Author

Superseded by #110. Although #108 and #109 were individually mergeable against master, either merge order conflicted in their shared E2E test file. #110 preserves both commit series, resolves the single mechanical import conflict by retaining both imports, and passes the combined 89-test portable suite plus Ruff formatting.

@voipmonitor voipmonitor closed this Aug 1, 2026
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.

2 participants