Skip to content

feat(cuda): forward strided-batched tropical GEMM (one launch over the batch) - #62

Merged
isPANN merged 2 commits into
mainfrom
integrate-batched-to-main
Jun 14, 2026
Merged

feat(cuda): forward strided-batched tropical GEMM (one launch over the batch)#62
isPANN merged 2 commits into
mainfrom
integrate-batched-to-main

Conversation

@isPANN

@isPANN isPANN commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Rebased the perf/forward-batched-gemm stack onto current main (which already
has the async-launch change from #60) so it merges cleanly. The duplicate
924abb2 async commit is dropped here; this branch carries only the
forward-batched feature, its gridDim.z fix, and the macro/launch cleanup.

What's included

  • feat: forward strided-batched tropical GEMM — one launch with blockIdx.z
    selecting the batch element and per-batch strides, replacing omeinsum's
    host-side per-slice clone_dtod loop.
  • fix: chunk the batch over the gridDim.z 65535 cap (fix(cuda): chunk batched tropical GEMM over the gridDim.z 65535 cap #61); reject batched
    strides past i32::MAX instead of truncating.
  • refactor: dedupe the GEMM kernel macros into one shared TROPICAL_GEMM_BODY
    (was copy-pasted 8x across {f32,f64,i32,i64} × {single,batched}); reuse
    grid_dims_f32 instead of a hardcoded 64; collapse a dead grid-tuple param.
    Net tropical_gemm.cu −505 lines.

Validation (HKUST-GZ A800, sm_80, CUDA 12.1)

  • cargo test -p tropical-gemm-cuda --lib --release: 57/57 passed on this
    exact tree (rebased onto current main).
  • PTX/SASS diff of the macro dedup vs the pre-refactor source: 31 non-batched
    kernels byte-identical; 12 batched kernels have identical instruction
    histograms and register/smem usage — no correctness or performance regression.

CI does not run CUDA (no GPU), so the GPU paths above are validated on the
A800 rather than in CI.

🤖 Generated with Claude Code

isPANN and others added 2 commits June 14, 2026 23:04
…dx.z=batch)

Adds TROPICAL_GEMM_BATCHED_{F32,F64,I32,I64} forward kernels (no argmax),
mirroring the single-matrix forward macros plus blockIdx.z batch indexing and
per-batch strides, and wires them through CudaKernel::launch_gemm_batched +
launch_kernel_batched_impl (non-swapped column-major convention, raw CudaSlice
operands so callers feed already-contiguous device buffers with no copy).

Lets the omeinsum device path run a whole node's batch in ONE launch instead of
a host-side per-slice clone_dtod loop, and the output may be allocated
uninitialized since the kernel fully writes every element. Correctness test
test_tropical_gemm_batched_matches_single checks the batched kernel against the
trusted single-matrix path + a CPU max-plus reference, incl. a non-block-aligned
shape (edge tiles).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
)

* fix(cuda): chunk batched tropical GEMM over gridDim.z 65535 cap

The strided-batched kernels map the batch dimension to blockIdx.z, whose
grid extent CUDA caps at 65535 on all compute capabilities. A contraction
whose batch exceeds that launched with grid.z > 65535 and failed at launch
with CUDA_ERROR_INVALID_VALUE. Large tensor-network contractions (space
complexity >= ~30) routinely exceed it, so the failure surfaced as an
intermittent panic (the batch/m/n split depends on the contraction order).

Split batched launches into chunks of at most 65535 batch elements,
advancing each operand's base by the chunk start so blockIdx.z stays in
[0, chunk). Fixes both the value path (launch_kernel_batched_impl, used by
all four scalar-type macro impls) and the argmax path
(launch_gemm_external_batched_with_argmax_f32). No kernel (.cu) change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* cuda: reject batched strides past i32::MAX instead of truncating

Address Copilot review on PR #61. The chunked batched launches derive
operand base offsets from the usize per-batch stride, while the kernels
read the stride as i32. An `as i32` cast that wrapped would desynchronise
the two and silently corrupt addressing.

Add a shared `stride_to_i32` helper that converts fallibly and returns
DimensionMismatch on overflow, and apply it in both the value path
(launch_kernel_batched_impl) and the external argmax path
(launch_gemm_external_batched_with_argmax_f32). The kernel signature is
i32, so a stride past i32::MAX is unrepresentable on-device regardless;
fail loudly at the boundary. Also correct the argmax-path stride comment:
external A/B carry the (possibly padded) DLPack stride, not rows*cols.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* refactor(cuda): dedupe GEMM kernel macros and batched launch wiring

Quality cleanup of the strided-batched GEMM work (no behavior change):

kernels/tropical_gemm.cu
- Factor the tiled max-/min-plus / max-mul inner kernel into one shared
  TROPICAL_GEMM_BODY macro. It was previously copy-pasted 8x (4 scalar
  types x {single-matrix, batched}); the 8 kernel families are now thin
  wrappers that supply only the signature and operand base expressions
  (`A/B/C` vs `A + blockIdx.z*strideA`). Net -505 lines.
- Add add_f32/mul_f32/add_f64/mul_f64 helpers so the body takes MUL_FN in
  function form for every type (symmetric with the int helpers) instead of
  special-casing the float `+`/`*` operator.

src/kernels.rs
- launch_gemm_external_batched_with_argmax_f32: reuse CudaContext::
  grid_dims_f32 instead of re-deriving the tile count with a hardcoded 64
  (which would silently desync if the block size changed).
- launch_kernel_batched_impl: collapse the `grid: (u32,u32,u32)` parameter
  to a single `grid_xy: u32`. The caller-passed z (`batch as u32`) was dead
  (recomputed per chunk as the chunk size) and y was always 1.

Verified on A800 (sm_80, CUDA 12.1): 57/57 lib tests pass. PTX/SASS diff of
all 43 kernels vs the pre-refactor source — 31 non-batched kernels are
byte-identical; the 12 batched kernels have identical instruction histograms
and identical register/smem usage (only benign prologue scheduling differs).
No correctness or performance regression.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.29%. Comparing base (8613adc) to head (bbadc86).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #62   +/-   ##
=======================================
  Coverage   96.29%   96.29%           
=======================================
  Files          19       19           
  Lines         918      918           
=======================================
  Hits          884      884           
  Misses         34       34           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@isPANN
isPANN merged commit ec04a4a into main Jun 14, 2026
10 checks passed
@isPANN
isPANN deleted the integrate-batched-to-main branch June 14, 2026 15:11
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