feat: add packed kda decode#102
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a packed-QKV variant of the KDA decode kernel (kda_packed_decode) along with associated benchmarks and unit tests. This implementation allows feeding Q/K/V as strided views directly from a packed tensor, avoiding the overhead of separate tensor materialization and contiguous copies. Feedback on the changes points out a potential issue in the general path of kda_packed_decode where the normalized a_kernel and b_kernel are not guaranteed to be contiguous, which could lead to runtime issues since the compiled kernel expects contiguous layouts. Ensuring these tensors are contiguous before passing them to the kernel is recommended.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
This PR adds a packed-QKV KDA decode entry point (kda_packed_decode) that consumes a single mixed_qkv tensor and slices it into strided Q/K/V views to reuse the existing CuTe DSL KDA decode kernel without caller-side Q/K/V materialization.
Changes:
- Added
kda_packed_decode(fast path + general path) and a packed static-stride kernel compilation/cache path. - Exported
kda_packed_decodeundercula.kda. - Added thorough packed-vs-non-packed correctness tests and a microbenchmark.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
cula/ops/kda_decode.py |
Implements kda_packed_decode, adds packed fast path and packed static-stride kernel compilation/caching. |
cula/kda/__init__.py |
Exposes kda_packed_decode in the public cula.kda API. |
tests/test_kda_packed_decode.py |
Adds correctness tests for dense/varlen, KV state layout, dummy indices, padded row stride, and CUDA graph smoke coverage. |
benchmarks/bench_kda_packed_decode.py |
Adds a benchmark comparing packed vs realistic non-packed vs oracle (pre-split) decode overhead. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
icavan
left a comment
There was a problem hiding this comment.
LGTM, you need to fix the conflicts
69b1e32 to
fdc6d2d
Compare
fdc6d2d to
667416f
Compare
📌 Description
This PR adds a packed-QKV KDA decode entry point,
kda_packed_decode, for Ling V3-style decode workloads where the conv output is already laid out as:The packed path avoids per-call Q/K/V materialization by slicing
mixed_qkvinto static-stride views and launching the existing CuTe DSL KDA decode kernel with a packed static-stride specialization. This keeps the kernel body shared with the existing non-packed decode path while removing the caller-sidesplit -> view -> contiguousadapter cost.The implementation includes:
kda_packed_decodeexport undercula.kdamixed_qkvandstatevkandkvstate layout supportstate_indices[b] < 0dummy slot support by skipping state reads, state writes, and output writes🔍 Related Issues
Closes #101
🚀 Pull Request Checklist
Thank you for contributing to cuLA! Before we review your pull request, please make sure the following items are complete.
✅ Pre-commit Checks
pre-commitby runningpip install pre-commit(or used your preferred method).pre-commit install.pre-commit run --all-filesand fixed any reported issues.🧪 Tests
Added:
Validated on an H200 (HBM3e) environment:
⚡ Performance
This PR adds
benchmarks/bench_kda_packed_decode.pyto measure:non-packed (oracle): q/k/v pre-split once outside the timed loopnon-packed (realistic): per-callsplit + view + contiguouscula_packed: packed static-stride path with no q/k/v materializationThe expected benefit is reduced decode overhead from avoiding:
Validated on an H200 (HBM3e) environment:
Summary: packed decode matches the non-packed reference numerically (
out_diff=0,state_diff=0) across all measured configurations. ForN >= 2, speedup ranges from1.05xto1.48x, averaging about1.30x, with roughly12.6-19.6 ussaved versus realistic non-packed decode.N=1is roughly neutral/slightly slower because the avoided materialization cost is very small relative to fixed dispatch overhead.Column notes:
oracle ms: non-packed decode with q/k/v pre-split once outside the timed loop.non-packed ms: realistic non-packed decode with per-call q/k/v materialization.packed ms:kda_packed_decodestatic-stride packed path.save vs non us:(non-packed ms - packed ms) * 1000.diff: max numerical diff for both output and state; all measured rows are zero.K=128,V=128,warmup=30,rep=200.H=32, HV=32
H=64, HV=64
H=8, HV=16
H=16, HV=32