Skip to content

Grouped gemm for mul! of CUDA tensors - #611

Draft
lkdvos wants to merge 1 commit into
mainfrom
batched-gemm
Draft

lkdvos wants to merge 1 commit into
mainfrom
batched-gemm

Conversation

@lkdvos

@lkdvos lkdvos commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

⚠️ vibe-coded, not meant for merging, mostly to get an idea of how much this matters vs the current approach.


Replaces the per-block loop in mul! for CUDA tensors by a single grouped gemm call (cublasGemmGroupedBatchedEx, cuBLAS ≥ 12.5) for all small blocks, and individual gemm calls for the few large ones.

  • Grouped gemm is real-only, so complex element types use the 1m embedding: α * op(A) is expanded into real 2m × 2k blocks [ar -ai; ai ar] by a small kernel, while B and C are simply reinterpreted as real. Complex β is applied upfront.
  • Blocks with m * n * k above TensorKitCUDAExt.GROUPED_GEMM_THRESHOLD[] (1024^3 real, 256^3 complex) use individual cublasGemmEx calls, since tensor-core gemm beats the grouped (SIMT) kernel there. These calls upload α and β once, instead of once per block as in CUDA.jl's mul!.
  • Complex products with an adjoint B, and cuBLAS < 12.5, use only the individual gemm calls.
  • The block structure and all host-side arguments are cached per pair of spaces in a GroupedGemmPlan.
  • The grouped call always uses plain 32F/64F compute types: TF32 crashes on H100 with a misaligned-address error for unaligned blocks.

Benchmarks

C = A * B, with the old mul! as baseline.

  • RTX A6000: 24–190× faster for tensors with many small or medium blocks (U(1), SU(2), U(1)×U(1), Float32/ComplexF32).
  • H100: 10–140× faster for many small blocks. With few, very large blocks the timings are within a few % of the old implementation (2–3% slower on the largest blocks, up to ~11% for ComplexF32 under TF32 math mode, where the direct cublasGemmEx path is slower than CUDA.jl's gemmEx! for reasons I haven't pinned down).
  • Under TF32 math mode, a lower real threshold (~256³) would be better; the current default is tuned for the default math mode.

Tests

The existing "Multiplication and inverse: test via CPU" testset covers the grouped path (the test spaces have small blocks). A new testset covers the direct path and real/complex β for every combination of adjoints.

🤖 Generated with Claude Code

Small blocks are multiplied in a single `cublasGemmGroupedBatchedEx` call,
using the real 1m embedding for complex element types. Large blocks use
individual `cublasGemmEx` calls with the scalars uploaded once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kshyatt
kshyatt self-requested a review November 5, 2026 15:01
@kshyatt

kshyatt commented Nov 5, 2026

Copy link
Copy Markdown
Member

It can certainly be on a separate PR, but it looks like rocBLAS now has support for this too.

@@ -0,0 +1,226 @@
const CuStoredTensorMap{T} = TensorMap{T, S, N₁, N₂, A} where {S, N₁, N₂, A <: CuVector{T}}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

don't we already have this in the cutensormap.jl file?

@lkdvos

lkdvos commented Nov 5, 2026 •

Copy link
Copy Markdown
Member Author

For context, this isn't really something that should actually be merged, and I would much rather have this all go through MAK instead. @jack-dunham was playing around with our kernels compared to the cuTENSORBlockSparse stuff, and I just wanted to add something to see if this actually matters, so see this more as a prototype.

It's also very unreviewed 🙃

Complex blocks benefit from individual calls much earlier, since the grouped call works on their
real 1m embedding.
"""
const GROUPED_GEMM_THRESHOLD = Ref((real = 1024^3, complex = 256^3))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could some of these move into TensorKit src so we can extend them for ROCm too?

This branch has not been deployed

No deployments
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