Skip to content

Tiled shared-memory kernel for GPU index manipulations - #616

Draft
lkdvos wants to merge 3 commits into
mainfrom
gpu-tiled
Draft

lkdvos wants to merge 3 commits into
mainfrom
gpu-tiled

Conversation

@lkdvos

@lkdvos lkdvos commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Replaces the per-element unique/generic permute kernels of the GPUArrays extension with a single tiled KernelAbstractions kernel.

Design

  • Workgroups and tiles: one workgroup per tile. A tile covers a power-of-two region of a block and up to 32 consecutive destination trees of that block.
  • Gather and write-out: the tile is gathered into @localmem in source order, recoupled over the cols source trees. It is then written out in destination order, so both reads and writes are coalesced.
    • All trees of a tile share their source reads, and the coefficients U[i:i+r, j] they need are contiguous in memory.
    • This keeps blocks with tiny subblocks and large recoupling matrices (high multiplicities, SU(3)-like) from leaving most threads idle or re-reading every source tree once per destination tree.
  • Index arithmetic: tile coordinates are shifts and masks in Int32, with no integer division. Shared memory is padded once per dim-1 row to avoid bank conflicts.
  • Tile shapes:
    • Every block gets its own tile shape, chosen by greedily doubling extents (including the number of trees).
    • The cost model counts the 32 B sectors read and written, contiguous runs, coefficient reads and per-tile overhead.
    • The tile length (32, 64, 128 or 256) is chosen per transformer, as the one that minimizes the total cost.
  • Launches: unique blocks (rows = cols = 1) and recoupling blocks share one launch, which halves host overhead for non-abelian tensors. The diagonal paths use the same kernel with 1-D blocks.
  • Type stability: the tile length and β ≠ 0 are branched on statically. DeviceTreeTransformer therefore has a concrete type, and the @cached device constructors declare their return type (devicetransformertype).
  • Scheduling: tiles of blocks with more source trees are scheduled first.
  • Traces are unchanged.

Benchmarks (RTX A6000, old per-element kernels → tiled)

Throughput is back-to-back launches, in µs. All outputs match the old kernels.

category examples speedup
small abelian / multiplicity-free (MPS, PEPS D ≤ 6) Z2 PEPS D=6: 7.2 → 5.4, U1 r4 D=8: 7.0 → 5.7 1.0–1.3×
small with recoupling SU2 PEPS D=4: 12.6 → 5.4, SU2 r4 D=8: 13.8 → 5.7 2.3–2.4×
many small blocks U1 r6 deg 2: 83.7 → 27.5, SU2 r6 deg ≤ 2: 39 → 23, SU2 r4 j≤4: 21 → 11.3 1.3–3.0×
large recoupling matrices SU2 r8 deg 1 (U up to 91×91): 110 → 63, A₄ r6 deg ≤ 6: 12900 → 7100 1.0–1.8×
few large blocks Z2 7264² transpose: 1251 → 642 (copy 627), ℂ⁴⁸ r4: 628 → 139 1.5–4.5×, within 1.0–1.1× of copyto!
mixed U1 r4 D=128: 3052 → 1484, U1 large+tiny sectors: 9415 → 2146 1.3–4.4×

Known weak spots:

  • Large recoupling matrices with large blocks: these stay around 5× copyto! (SU2 r8 deg ≤ 4, A₄ r6 deg ≤ 6), because reads still scale with rows × cols divided by the number of trees per tile. A separate extract → batched GEMM → insert path would fix this.
  • Many tiny abelian blocks: these lose some occupancy, since the per-block tile shape costs registers (70 vs 54). U1 r4 with 21 charges is 51 → 40, where the variant with one tile shape per transformer reached 31.

Possible follow-ups

  • An extract → batched GEMM → insert path for very large recoupling matrices.
  • A byte-based maximum tile length, so Float32 can use larger tiles (not yet measured).

Tests

test/runtests.jl cuda: 125107 pass, 36 broken, 4 errors. The errors are IsingBimodule SpaceMismatchs raised while building the test spaces (test/cuda/planar.jl:80, test/cuda/tensors.jl:119), before any kernel runs. They are not caused by this PR, but I haven't confirmed they also fail on main.

🤖 Generated with Claude Code

Replace the per-element unique/generic permute kernels with a single tiled
KernelAbstractions kernel: each workgroup gathers one power-of-two tile of a
destination tree, recoupled over the source trees, into shared memory in source
order and writes it out in destination order, so reads and writes are both
coalesced. Unique and recoupling blocks share one launch, and the diagonal paths
use the same kernel with one-dimensional blocks.

- tile shapes are chosen per transformer with a sector-based cost model
- the tile length is branched on statically, so `DeviceTreeTransformer` has a
  concrete type and the device caches declare their return types
- tiles of blocks with more source trees are scheduled first
- split the GPUArrays extension into several files

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

codecov Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.61905% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
ext/TensorKitGPUArraysExt.jl 97.61% 4 Missing ⚠️
Files with missing lines Coverage Δ
ext/TensorKitGPUArraysExt.jl 95.62% <97.61%> (+0.29%) ⬆️

... and 7 files with indirect coverage changes

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

lkdvos and others added 2 commits November 9, 2026 12:09
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every block now gets its own tile shape, which includes the number of destination
trees a tile covers. The trees of a tile share their source reads, so blocks with
tiny subblocks and large recoupling matrices no longer leave most threads idle or
re-read every source tree per destination tree. The tile length is chosen per
transformer, and the cost model groups blocks by size and shape of `U`, which also
makes packing transformers with large `U` much cheaper.

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

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.

1 participant