feat(gdn): adopt the CuTe-DSL disk cache for TVM-FFI GDN kernels - #4912
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughGDN CuTe DSL decode and Blackwell prefill compilation now uses named, source-invalidated disk caching. A shared naming utility encodes specialization parameters into safe, bounded names. Tests cover naming coverage, uniqueness, cache reuse, and compile-count behavior. ChangesGDN CuTe DSL kernel caching
Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: ⚪ Minimal · up to GDN CuTe-DSL kernels now reuse source-invalidated disk-cached specializations across processes. Compile-count tests retain their intended behavior with persistent caching disabled, leaving no current merge-blocking risk. Sequence Diagram(s)sequenceDiagram
participant GDNKernel
participant build_and_load_cute_dsl_kernel
participant DiskCache
participant cute_compile
GDNKernel->>build_and_load_cute_dsl_kernel: provide module and specialization name
build_and_load_cute_dsl_kernel->>DiskCache: check source-invalidated artifact
alt cache miss
DiskCache->>cute_compile: invoke compilation callback
cute_compile-->>DiskCache: return compiled kernel
DiskCache-->>build_and_load_cute_dsl_kernel: store artifact
else cache hit
DiskCache-->>build_and_load_cute_dsl_kernel: load artifact
end
build_and_load_cute_dsl_kernel-->>GDNKernel: return compiled kernel
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
c575ed9 to
58609a0
Compare
|
@flashinfer-bot run |
|
/bot run tests/gdn |
|
[FAILED] Pipeline #66311518 — 6/17 executed test jobs passed Compared with nightly #66202435. Unit Tests
✅ Pass · 🟡 Old failure · ❌ New failure · ⏱ Test timeout · Multi-GPU and Multi-Node Tests — 6/6 passed
Failure detailsNew relative to nightly (attribution uncertain)
Could not compare
Timeouts, infrastructure, or incomplete jobs
|
|
Hi @bkryu Thanks for running the pipeline. The |
|
Thanks @elwhyjay, was going to followup on the failure but seems like you got to it first. I'll retrigger the pipeline |
|
@flashinfer-bot run |
|
/bot run tests/gdn |
…ackend (#5104) <!-- .github/pull_request_template.md --> ## 📌 Description <!-- What does this PR do? Briefly describe the changes and why they’re needed. --> `tests/gdn/test_cute_dsl_kernel_cache.py::test_nontranspose_disk_cache_round_trip` fails deterministically on SM100/SM103 (B200, GB200, GB300) with `AssertionError: expected one exported artifact, got []`. Root cause is a cross-PR dispatch interaction, not a disk-cache bug: the test (added in #4912, merged Sept 8) calls `gated_delta_rule_decode` with the default `backend="auto"` and asserts the CuTe-DSL nontranspose kernel exports one artifact. #4581 (merged Sept 9 — the day the failures began) added the Cake GDN backend, which `auto` now tries *first* on SM100/103; it handles the test's BF16 decode and returns, so the CuTe-DSL kernel under test never compiles and nothing is exported. This also explains the arch fingerprint: the test fails on B200/GB200/GB300 (Cake-eligible) and passes on H100 (SM90, where Cake falls through to the CuTe-DSL kernel). Each PR was green alone; composed they are red. Fix: pin both `gated_delta_rule_decode` calls in the test to `backend="flashinfer"` (the dispatcher's explicit Cake bypass), so the test exercises the backend whose cache it verifies — robust to future `auto`-dispatch changes. ## 🔍 Related Issues <!-- Link any related issues here --> Fixes #5091. Interaction between #4912 and #4581. ## 🚀 Pull Request Checklist Thank you for contributing to FlashInfer! Before we review your pull request, please make sure the following items are complete. ### ✅ Pre-commit Checks - [x] I have installed `pre-commit` by running `pip install pre-commit` (or used your preferred method). - [x] I have installed the hooks with `pre-commit install`. - [x] I have run the hooks manually with `pre-commit run --all-files` and fixed any reported issues. > If you are unsure about how to set up `pre-commit`, see [the pre-commit documentation](https://pre-commit.com/). ## 🧪 Tests - [ ] Tests have been added or updated as needed. - [ ] All tests are passing (`unittest`, etc.). ## 🔬 Experimental Track <!-- Only for PRs submitted under the experimental policy (CONTRIBUTING.md → "Experimental APIs and Backends"). Leave this section untouched for normal PRs. --> - [ ] This PR is **experimental**: it adds or changes code under `flashinfer/experimental/` and/or an `@flashinfer_experimental_api`. Tracking issue: # - [ ] The tracking issue names an owner, the reason for the experimental path, and a graduation plan with a target release. - [ ] Core changes are limited to a thin entry point (signature, shared validation, feature-gate check, backend selection, handoff). - [ ] Tests live in `tests/experimental/` and were validated on the intended hardware; a runnable example is included. - [ ] Nothing is registered in `flashinfer/aot.py`, and no experimental backend is reachable from `backend="auto"` without `FLASHINFER_ALLOW_EXPERIMENTAL_AUTO_BACKENDS=1`. (Calling an `@flashinfer_experimental_api` or naming a backend explicitly is itself the opt-in and needs no environment variable.) - [ ] **Test scope declared below.** The experimental CI lane runs exactly these targets, so keep them as narrow as the change allows. <!-- Required for experimental PRs. Replace the commented lines below with your targets. Do not delete the fence or change its `experimental-tests` tag — the experimental-track watcher reads it verbatim to decide which targets to ask CI for. --> ```experimental-tests # One target per line: a directory or a file. (A pytest ::selector is not # supported -- the sharding runner cannot consume one.) Must be under # tests/experimental/ and must exist. Delete these comment lines and add yours, e.g. # # tests/experimental/test_my_backend.py # tests/experimental/my_backend/ # # Declaring the whole tree (tests/experimental/) is allowed but means every # experimental PR pays for every other feature's tests, in every matrix cell. ``` ## Reviewer Notes <!-- Optional: anything you'd like reviewers to focus on, concerns, etc. --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Updated kernel cache round-trip coverage to explicitly use the FlashInfer backend for both decode operations. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…ackend (#5104) <!-- .github/pull_request_template.md --> ## 📌 Description <!-- What does this PR do? Briefly describe the changes and why they’re needed. --> `tests/gdn/test_cute_dsl_kernel_cache.py::test_nontranspose_disk_cache_round_trip` fails deterministically on SM100/SM103 (B200, GB200, GB300) with `AssertionError: expected one exported artifact, got []`. Root cause is a cross-PR dispatch interaction, not a disk-cache bug: the test (added in #4912, merged Sept 8) calls `gated_delta_rule_decode` with the default `backend="auto"` and asserts the CuTe-DSL nontranspose kernel exports one artifact. #4581 (merged Sept 9 — the day the failures began) added the Cake GDN backend, which `auto` now tries *first* on SM100/103; it handles the test's BF16 decode and returns, so the CuTe-DSL kernel under test never compiles and nothing is exported. This also explains the arch fingerprint: the test fails on B200/GB200/GB300 (Cake-eligible) and passes on H100 (SM90, where Cake falls through to the CuTe-DSL kernel). Each PR was green alone; composed they are red. Fix: pin both `gated_delta_rule_decode` calls in the test to `backend="flashinfer"` (the dispatcher's explicit Cake bypass), so the test exercises the backend whose cache it verifies — robust to future `auto`-dispatch changes. ## 🔍 Related Issues <!-- Link any related issues here --> Fixes #5091. Interaction between #4912 and #4581. ## 🚀 Pull Request Checklist Thank you for contributing to FlashInfer! Before we review your pull request, please make sure the following items are complete. ### ✅ Pre-commit Checks - [x] I have installed `pre-commit` by running `pip install pre-commit` (or used your preferred method). - [x] I have installed the hooks with `pre-commit install`. - [x] I have run the hooks manually with `pre-commit run --all-files` and fixed any reported issues. > If you are unsure about how to set up `pre-commit`, see [the pre-commit documentation](https://pre-commit.com/). ## 🧪 Tests - [ ] Tests have been added or updated as needed. - [ ] All tests are passing (`unittest`, etc.). ## 🔬 Experimental Track <!-- Only for PRs submitted under the experimental policy (CONTRIBUTING.md → "Experimental APIs and Backends"). Leave this section untouched for normal PRs. --> - [ ] This PR is **experimental**: it adds or changes code under `flashinfer/experimental/` and/or an `@flashinfer_experimental_api`. Tracking issue: # - [ ] The tracking issue names an owner, the reason for the experimental path, and a graduation plan with a target release. - [ ] Core changes are limited to a thin entry point (signature, shared validation, feature-gate check, backend selection, handoff). - [ ] Tests live in `tests/experimental/` and were validated on the intended hardware; a runnable example is included. - [ ] Nothing is registered in `flashinfer/aot.py`, and no experimental backend is reachable from `backend="auto"` without `FLASHINFER_ALLOW_EXPERIMENTAL_AUTO_BACKENDS=1`. (Calling an `@flashinfer_experimental_api` or naming a backend explicitly is itself the opt-in and needs no environment variable.) - [ ] **Test scope declared below.** The experimental CI lane runs exactly these targets, so keep them as narrow as the change allows. <!-- Required for experimental PRs. Replace the commented lines below with your targets. Do not delete the fence or change its `experimental-tests` tag — the experimental-track watcher reads it verbatim to decide which targets to ask CI for. --> ```experimental-tests # One target per line: a directory or a file. (A pytest ::selector is not # supported -- the sharding runner cannot consume one.) Must be under # tests/experimental/ and must exist. Delete these comment lines and add yours, e.g. # # tests/experimental/test_my_backend.py # tests/experimental/my_backend/ # # Declaring the whole tree (tests/experimental/) is allowed but means every # experimental PR pays for every other feature's tests, in every matrix cell. ``` ## Reviewer Notes <!-- Optional: anything you'd like reviewers to focus on, concerns, etc. --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Updated kernel cache round-trip coverage to explicitly use the FlashInfer backend for both decode operations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> (cherry picked from commit 82090ee)
📌 Description
Migrate the GDN CuTe-DSL call sites that already compile with
--enable-tvm-ffitobuild_and_load_cute_dsl_kernel, so each specialization is exported to the on-disk kernel cache and later processes JITLink it instead of recompiling.Covered call sites (8 compile sites in 5 files):
gdn_decode_nontranspose.pygdn_decode_nontransposegdn_decode_pretranspose.pygdn_decode_pretransposegdn_decode_mtp.pygdn_decode_mtpgdn_decode_bf16_state.pygdn_decode_bf16_stateblackwell/gdn_prefill.pygdn_blackwell_prefillHow it works:
cute.compile(...)call is wrapped in acompile_fnclosure. Every in-process cache structure (getter dicts,defaults_by_B, aux buffers) is unchanged, and on a disk hit the closure never runs.num_sm, which the compile bakes in asmax_active_clusters.gdn_kernels/cute_dsl_cache_naming.py) keeps names symbol-safe and caps their length.Measurements with fresh processes and an isolated cache dir:
🔍 Related Issues
#4214 (GDN-P1, PR 4 of the suggested implementation sequence)
🚀 Pull Request Checklist
Thank you for contributing to FlashInfer! 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
unittest, etc.).Ran on RTX PRO 6000 (SM120) and B200 (SM100):
tests/gdn/test_cute_dsl_kernel_cache.py(new, modeled ontests/jit/test_cute_dsl_cache.py): 68 passed on both GPUs. Naming contracts plus a disk-cache round trip (reload withcute.compileforbidden, bit-identical results).tests/jit/test_cute_dsl_cache.py: 42 passedtests/gdn/test_decode_delta_rule.py(SM120): passed cold, warm, and withFLASHINFER_CUTE_DSL_DISABLE_CACHE=1tests/gdn/test_multistream_overlap.py: 4 passed on B200 (1 of them skipped on SM120)test_prefill_kernel_state_dtypecases) fail identically on unmodified main on the same machine, i.e. pre-existing in my environment.Reviewer Notes
Out of scope, as follow-ups:
gdn_decode.pydispatch and not TVM-FFI yet (persisting them needs a calling-convention change first).delta_rule_dslkernels: use explicitcute.compile[gpu_arch]targets, which the disk cache's arch keying does not reflect yet (documented limitation).Open to adjusting the split if a different scope was intended for GDN-P1.
Summary by CodeRabbit