Skip to content

cute ops: probe nvvm.fmax signature instead of sniffing CUDA_VERSION (fixes engine init on PyPI DSL 4.6.0)#70

Merged
lukealonso merged 1 commit into
local-inference-lab:masterfrom
davidsyoung:fmax-dsl46-signature-probe
Jul 23, 2026
Merged

cute ops: probe nvvm.fmax signature instead of sniffing CUDA_VERSION (fixes engine init on PyPI DSL 4.6.0)#70
lukealonso merged 1 commit into
local-inference-lab:masterfrom
davidsyoung:fmax-dsl46-signature-probe

Conversation

@davidsyoung

@davidsyoung davidsyoung commented Jul 22, 2026

Copy link
Copy Markdown

Standalone fix on master (single commit, +21/−15 in sparkinfer/attention/_shared/cute/ops.py). Also unblocks #49, which requires nvidia-cutlass-dsl ≥ 4.6.0 — the stack currently cannot run on the only public 4.6.0 wheel.

The DSL wheels disagree about both the fmax ABI and what cutlass.CUDA_VERSION means:

DSL build reports nvvm.fmax existing sniff picks result
PyPI 4.5.2 12.9 legacy (T.f32(), a, b, …) legacy ok
PyPI 4.6.0 12.9 unified (a, b, *, c=None, …) legacy TypeError: fmax() takes 2 positional arguments but 3 … were given — every attention JIT fails at engine init
CTK-13.3 build (published EXL3 runtime image) 13.3 unified modern ok

Since fmax sits under every attention softmax reduction (fmax_reduce, indexer quad-max, paged/extend running max), PyPI-4.6.0 users can't boot at all.

Fix: probe inspect.signature(nvvm.fmax) once at import (first parameter named a/b ⇒ unified form) and pick the call shape from the actual ABI instead of a version proxy. Verified on all three builds above — legacy form preserved on 4.5.2, attention JIT compiles clean on PyPI 4.6.0, and the 13.3 build takes the same branch it already does. No numerical or behavioral change.

@davidsyoung

Copy link
Copy Markdown
Author

Companion vLLM prefill PR measured on this stack: local-inference-lab/vllm#163

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The PR adds a full-rotation EXL3 Trellis MoE API and W4A16 execution path, including native weight preparation, Trellis dequantization, routing, scratch binding, CUDA graph-safe execution, and GPU correctness tests. It also adds device-aware compile cache formats, updates cache validators, adds Triton, and makes NVVM fmax signature handling runtime-dependent.

Trellis MoE

Layer / File(s) Summary
Trellis contracts and preparation
pyproject.toml, sparkinfer/moe/trellis_moe/*, sparkinfer/moe/_shared/kernels/w4a16/prepare.py, sparkinfer/moe/_shared/kernels/w4a16/__init__.py
Defines the lazy public API, capability/weight/plan types, native Trellis weight preparation, codebook validation, and exported preparation symbols.
Trellis dequantization and W4A16 kernels
sparkinfer/_lib/intrinsics.py, sparkinfer/moe/_shared/kernels/w4a16/{host.py,kernel.py,route_pack.py}
Adds Trellis FP16/BF16 decode intrinsics, rotation-aware buffers, expert-count workspace reuse, and Trellis-aware W4A16 compilation and launch paths.
Planning, binding, and end-to-end validation
tests/moe/test_trellis_moe.py
Validates capability and preparation constraints, reconstructs reference Trellis weights, and tests full-rotation correctness, routing maps, allocation stability, and CUDA graph replay.

Compile cache format

Layer / File(s) Summary
Device-aware cache payloads
sparkinfer/_lib/compiler.py
Adds device architecture fingerprints and updates explicit and non-explicit cache payload construction, parsing, and manifest generation.
Cache manifest validation
validation/cutlass_migration/..., tests/_lib/test_compile_cache.py
Updates v6 explicit-spec payload validation and tests device-architecture cache-key behavior.

NVVM compatibility

Layer / File(s) Summary
Runtime fmax signature detection
sparkinfer/attention/_shared/cute/ops.py
Detects whether nvvm.fmax requires a result-type argument and constructs calls accordingly.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant trellis_moe
  participant W4A16Kernels
  participant ScratchArena
  participant Output

  Caller->>trellis_moe: prepare_weights
  trellis_moe->>W4A16Kernels: plan and compile Trellis kernels
  Caller->>ScratchArena: provide scratch storage
  trellis_moe->>ScratchArena: bind typed workspace views
  Caller->>trellis_moe: run
  trellis_moe->>W4A16Kernels: dispatch fused MoE and top-k sum
  W4A16Kernels->>Output: write rotated routed output
Loading

Possibly related PRs

Suggested reviewers: voipmonitor

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main Cute DSL fix and is concise enough for a teammate scanning history.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

Unblocks building the trellis3_t256 stack from local-inference-lab/
b12x#49 (@brandonmusic) on the public PyPI nvidia-cutlass-dsl 4.6.0
wheel, which local-inference-lab#49 requires (>= 4.6.0) but currently cannot run on.

The DSL wheels disagree about both the fmax ABI and what
cutlass.CUDA_VERSION means: the PyPI 4.6.0 wheel reports its bundled
CTK as DSLCudaVersion(12, 9) while exposing the unified
nvvm.fmax(a, b, *, c=None, ...) signature, so the existing
"major == 12 and minor == 9" branch calls the removed
nvvm.fmax(T.f32(), a, b) form and every attention JIT fails at engine
init with "fmax() takes 2 positional arguments but 3 ... were given".
The CTK-13.3 DSL build used by the published runtime image sidesteps
the sniff by reporting 13.3; PyPI users hit it every time.

Probe the actual signature once at import (first parameter named "a"
or "b" means the unified form) and pick the call shape from that.
Verified on PyPI 4.5.2 (legacy result-type form preserved), PyPI
4.6.0 (unified; attention JIT compiles clean), and the CTK-13.3 build
(unified; same branch it already takes).
@davidsyoung
davidsyoung force-pushed the fmax-dsl46-signature-probe branch from 5ea5503 to 0611af8 Compare July 22, 2026 12:00

@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.

🧹 Nitpick comments (3)
tests/_lib/test_compile_cache.py (1)

56-79: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the v6 explicit-spec payload branch.

The new test exercises the non-explicit (v3, 9-field) _compile_disk_cache_payload path with device_arch at index 4, but there's no test for the explicit-spec (v6_explicit_spec, 11-field) branch that also shifted indices in this PR (_compile_disk_cache_payload with compile_spec set, _compile_cache_payload_log_value, _is_explicit_spec_payload, _build_compile_manifest).

Want me to draft a test that constructs a KernelCompileSpec, calls _compile_disk_cache_payload(..., compile_spec=spec), and asserts payload[0] == "sparkinfer_cute_compile_cache_v6_explicit_spec" with payload[4] holding the device-arch tuple?

🤖 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 `@tests/_lib/test_compile_cache.py` around lines 56 - 79, Add a test alongside
test_disk_cache_key_includes_device_arch that constructs a KernelCompileSpec,
calls _compile_disk_cache_payload with compile_spec=spec, and verifies the
explicit-spec payload uses the "sparkinfer_cute_compile_cache_v6_explicit_spec"
marker at payload[0] and stores the device-architecture tuple at payload[4].
sparkinfer/moe/_shared/kernels/w4a16/kernel.py (1)

6494-6528: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Duplicated _had128_quad across W4A16FusedMoeKernel and W4A16TopKSumKernel.

This blockwise-128 Walsh–Hadamard helper (lines 6494–6528) is byte-identical to W4A16FusedMoeKernel._had128_quad (lines 5540–5578), including the 0.088388347648 scale. Consider hoisting it to a shared @cute.jit free function to keep the two rotation paths from drifting.

🤖 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/kernel.py` around lines 6494 - 6528,
Hoist the duplicated _had128_quad implementation out of W4A16FusedMoeKernel and
W4A16TopKSumKernel into one shared `@cute.jit` free function, then update both
rotation paths to call it. Preserve the existing butterfly computation, lane
handling, return tuple, and 0.088388347648 scaling exactly.
sparkinfer/moe/_shared/kernels/w4a16/prepare.py (1)

1564-1565: 📐 Maintainability & Code Quality | 🔵 Trivial

Prefer unpacking over tuple concatenation (RUF005).

Minor readability/idiom nit flagged by Ruff.

♻️ Proposed change
-    expected_i16_shape = expected_prefix_shape + (16 * trellis_bits,)
-    expected_i32_shape = expected_prefix_shape + (8 * trellis_bits,)
+    expected_i16_shape = (*expected_prefix_shape, 16 * trellis_bits)
+    expected_i32_shape = (*expected_prefix_shape, 8 * trellis_bits)
🤖 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 1564 - 1565,
Update the expected_i16_shape and expected_i32_shape assignments to use iterable
unpacking for expected_prefix_shape instead of tuple concatenation, preserving
the existing trailing dimensions and resulting shapes.

Source: Linters/SAST tools

🤖 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.

Nitpick comments:
In `@sparkinfer/moe/_shared/kernels/w4a16/kernel.py`:
- Around line 6494-6528: Hoist the duplicated _had128_quad implementation out of
W4A16FusedMoeKernel and W4A16TopKSumKernel into one shared `@cute.jit` free
function, then update both rotation paths to call it. Preserve the existing
butterfly computation, lane handling, return tuple, and 0.088388347648 scaling
exactly.

In `@sparkinfer/moe/_shared/kernels/w4a16/prepare.py`:
- Around line 1564-1565: Update the expected_i16_shape and expected_i32_shape
assignments to use iterable unpacking for expected_prefix_shape instead of tuple
concatenation, preserving the existing trailing dimensions and resulting shapes.

In `@tests/_lib/test_compile_cache.py`:
- Around line 56-79: Add a test alongside
test_disk_cache_key_includes_device_arch that constructs a KernelCompileSpec,
calls _compile_disk_cache_payload with compile_spec=spec, and verifies the
explicit-spec payload uses the "sparkinfer_cute_compile_cache_v6_explicit_spec"
marker at payload[0] and stores the device-architecture tuple at payload[4].

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 45ab270f-78a1-4aa0-8a42-a14d85aa94fa

📥 Commits

Reviewing files that changed from the base of the PR and between d4f82a6 and 5ea5503.

📒 Files selected for processing (19)
  • pyproject.toml
  • sparkinfer/__init__.py
  • sparkinfer/_lib/compiler.py
  • sparkinfer/_lib/intrinsics.py
  • sparkinfer/attention/_shared/cute/ops.py
  • sparkinfer/moe/__init__.py
  • sparkinfer/moe/_shared/kernels/w4a16/__init__.py
  • sparkinfer/moe/_shared/kernels/w4a16/host.py
  • sparkinfer/moe/_shared/kernels/w4a16/kernel.py
  • sparkinfer/moe/_shared/kernels/w4a16/prepare.py
  • sparkinfer/moe/_shared/kernels/w4a16/route_pack.py
  • sparkinfer/moe/trellis_moe/__init__.py
  • sparkinfer/moe/trellis_moe/_impl.py
  • sparkinfer/moe/trellis_moe/api.py
  • tests/_lib/test_compile_cache.py
  • tests/moe/test_trellis_moe.py
  • validation/cutlass_migration/acceptance/corpus/ptx_capture.py
  • validation/cutlass_migration/acceptance/e2e/contract.py
  • validation/cutlass_migration/evidence/kernel_resources.py

@davidsyoung davidsyoung changed the title cute ops: probe nvvm.fmax signature instead of sniffing CUDA_VERSION (PyPI DSL 4.6.0 compat, stacked on #49) cute ops: probe nvvm.fmax signature instead of sniffing CUDA_VERSION (fixes engine init on PyPI DSL 4.6.0) Jul 22, 2026
@lukealonso
lukealonso merged commit a934d87 into local-inference-lab:master Jul 23, 2026
1 check passed
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