[Perf] Tiles 5: add Cholesky benchmark demo#483
Conversation
TypeCheck has allow_undefined_visitor=true, so removing this override is a no-op. The original code was actively wrong (overwriting correct ret_type with i32), but nothing downstream relied on ret_type from the type_check pass for InternalFuncStmt, so the bug was latent. Removing the override eliminates the misleading TODO and prevents a future pass from accidentally depending on the wrong type.
…tests - Parametrize ger_sub and cholesky tests over f32/f64 dtypes - Use tighter tolerance (1e-10) for f64, 1e-5 for f32 - Parametrize cholesky over src_offset (0, 5, 32) and dst_delta (0, 3, 16) - Verify untouched regions of dst array remain at sentinel value
…olesky_ _ger_sub: 34 lines → 4 lines cholesky_: 224 lines → 22 lines
Quadrants DSL types don't carry operator overloads in their stubs, so pyright can't verify +=, *, /, > on shuffled values.
Fix scipy reference computation: solve X @ L^T = B requires solve_triangular(L, B.T) not solve_triangular(L, B, trans='T'). Add type: ignore[reportOperatorIssue] for DSL operator expressions in _trsm that pyright can't verify.
…_eye_
Replace 16-way explicit register access with loop-based _get_col/_set_col
helpers, eliminating ~145 lines of boilerplate. Also fix trsm test reference
computation (was computing B^T @ L^{-1} instead of B @ L^{-T}).
…e16x16 - Slice-based load/store: arr[r0:r1, c0:c1] for 2D and arr[b, r0:r1, c0:c1] for 3D - qd.outer(a, b) deferred proxy for augmented assignment (t -= qd.outer(a, b)) - _TileSliceProxy, _VecSliceProxy, _TileRefProxy for deferred subscript evaluation - AST purity exemptions for quadrants-internal code - _quadrants_internal flag on Tile struct
The purity checker only flags int/float/Field attribute accesses inside kernels. Tile() and Tile.zeros() don't trigger this, and Tile.SIZE is only accessed in plain Python, not inside kernels.
Add tile16.md covering tile creation, slice load/store, rank-1 updates, Cholesky, and triangular solve. Remove the unused _quadrants_internal getattr escape hatch from the purity checker (file-level check suffices). Add test for Tile.SIZE access inside a kernel.
…top in slices Update tile16 doc examples to use Tile.SIZE. Enforce that both start and stop indices are provided in tile/vec slice syntax (previously stop defaulted to start+16 when omitted). Reorder _TileSliceProxy.__init__ args to match (row_start, row_stop, col_start, col_stop).
The if-condition checking all four slice indices was too long for black. The test_tile16_load_missing_start_raises regex didn't match the updated error message after requiring both start and stop indices.
- test_tile16_outer_symmetric_same_variable: passes same variable for both args to qd.outer(v, v) - test_tile16_vec_proxy_ger_sub_3d: column vector load from 3D array via arr[batch, r0:r1, col] - test_outer_composition_raises: verifies qd.outer(a,b) + qd.outer(c,d) raises TypeError
…errors Only intercept 2D/1D array slices for tile proxy creation when _tile16_cache is non-empty (i.e., _make_tile16x16 has been called). Non-tile programs now get the original "does not support slice" error. Add _DeferredProxyMixin with __add__, __sub__, __mul__, __getitem__, and __repr__ that raise clear TypeErrors explaining the proxy is only valid in tile operations.
Check isinstance(value, t) against cached tile types before creating a _TileRefProxy for struct[:] subscripts. Non-tile structs now fall through to normal subscript handling.
The early return on cache hit was bypassing the CPU backend guard, so after a GPU init the cache would let a subsequent CPU init skip the QuadrantsSyntaxError. Move the cache check after the arch guard.
|
Opus actions to address 'bad points' in the description: User: modify the demo to work on qd.gpuAssistant: Done. Changed User: add a unit test to qaudrants unit tests that smoke tests that cholesksy_blocked.md runs to completion without crashing …add a unit test to qaudrants unit tests that smoke tests that cholesksy_blocked.md runs to completion without crashing (exit code 0). This should run on qd.gpu Assistant: Let me find existing test patterns and see if there are any subprocess-based smoke tests already. User: sorry, cholesky_blocked.pyAssistant: Let me check how the existing test file for tile16 is structured and see test_utils.test() usage: Let me check how Now let me check how The demo uses module-level Now add the smoke test at the end of the file: Done. Added User: run hte test, hceck it passesAssistant: Passes on both CUDA and Vulkan. 15 seconds total. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bfa3c81965
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| def test_tile16_cholesky_blocked_demo(): | ||
| """Smoke-test that misc/demos/cholesky_blocked.py runs to completion.""" | ||
| demo = Path(__file__).resolve().parents[2] / "misc" / "demos" / "cholesky_blocked.py" | ||
| result = subprocess.run([sys.executable, str(demo)], capture_output=True, text=True, timeout=300) |
There was a problem hiding this comment.
Pass selected test backend into demo subprocess
This test is parametrized with @test_utils.test(arch=qd.gpu), but the subprocess command does not pass the active req_arch to the child. The demo then initializes with qd.init(arch=qd.gpu), so on multi-backend machines the vulkan/metal parametrizations can still run on a different backend (typically CUDA), which makes this test miss backend-specific regressions. Pass the current backend name to the script and initialize that exact arch in the child process.
Useful? React with 👍 / 👎.
| def test_tile16_cholesky_blocked_demo(): | ||
| """Smoke-test that misc/demos/cholesky_blocked.py runs to completion.""" | ||
| demo = Path(__file__).resolve().parents[2] / "misc" / "demos" / "cholesky_blocked.py" | ||
| result = subprocess.run([sys.executable, str(demo)], capture_output=True, text=True, timeout=300) |
There was a problem hiding this comment.
Keep smoke test from executing full benchmark workload
The smoke test currently invokes the benchmark script with its hardcoded heavy settings (N_ENVS=4096, WARMUP=50, ITERS=200), which means one unit test run performs hundreds of large GPU launches and allocates several large fields. Because this test is not marked run_in_serial and runs in a separate subprocess, it bypasses the per-test CUDA memory throttling used in tests/python/conftest.py, increasing the chance of OOM/timeouts when xdist runs tests concurrently. Add a lightweight test mode (or CLI/env overrides) and use that here.
Useful? React with 👍 / 👎.
| H[i0 + r, k0 + c] = (H[i0 + r, k0 + c] - dot) / H[k0 + c, k0 + c] | ||
| qd.simt.block.sync() | ||
|
|
||
| # Write result to global memory | ||
| for row in range(N): | ||
| c = tid | ||
| while c <= row: | ||
| L_blocked_field[env, row, c] = H[row, c] | ||
| c += TILE | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Kernel 3: Tile16x16 blocked Cholesky (16 threads, no shared memory) |
There was a problem hiding this comment.
🟡 The guard 'if r < TILE' in the triangular solve section of cholesky_blocked() is vacuously true and never skips any thread. Since tid = idx % TILE with TILE=16, r = tid is always in [0, 15], so 'if r < TILE' is always True. The dead conditional can be removed; it may mislead readers by analogy with the meaningful 'if row < TILE' guard in the Crout diagonal section above, where row = col + 1 + tid can genuinely exceed TILE.
Extended reasoning...
What the bug is: In the triangular solve loop inside cholesky_blocked() (lines 180-192 of misc/demos/cholesky_blocked.py), the code sets r = tid and then guards the body with 'if r < TILE'. Since tid = idx % TILE (with TILE=16), tid is always in the range [0, 15]. Setting r = tid means r is always in [0, 15], so 'if r < TILE' — i.e. 'if r < 16' — is always True and the guard never prevents execution of the body.
The specific code path: In cholesky_blocked(), the outer loop sets tid = idx % TILE (TILE=16), so tid is in {0, 1, ..., 15}. In the off-diagonal block triangular solve:
for c in range(TILE):
r = tid
if r < TILE: # always True
dot = qd.f32(0.0)
...
qd.simt.block.sync()
Since r = tid and tid is always < 16 = TILE, the branch condition is never False.
Why existing code does not prevent it: The condition looks structurally similar to the meaningful guard in the Crout diagonal factorization just above:
row = col + 1 + tid # col ranges 0..15, so row can be 16+
if row < TILE: # meaningful guard, can be False
Here row can exceed TILE (when col + 1 + tid >= 16), so that guard does real work. The triangular solve was likely written by analogy with the Crout section, but the analogy breaks down because r = tid directly (not shifted by col + 1), so it can never reach TILE.
Step-by-step proof: Take TILE=16, tid=15 (maximum). In the Crout section, row = col + 1 + 15; when col=0, row=16 >= TILE, so 'if row < TILE' is False and that thread is skipped. In the triangular solve, r = tid = 15 < 16 = TILE, so 'if r < TILE' is True — the guard never fires for any value of tid.
Impact: The code is algorithmically correct; all 16 threads need to execute the triangular solve body for all 16 rows of the off-diagonal block. The dead guard is purely misleading: a reader may infer (by analogy with the diagonal Crout section) that some threads conditionally skip work, when in fact all threads always execute. This is a nit in a demo script.
How to fix: Remove the 'if r < TILE:' guard (and the corresponding indentation change), leaving only the unconditional body plus the sync.
| print("Compiling blocked (scalar Crout, 16 threads, shared mem)...") | ||
| cholesky_blocked() | ||
| qd.sync() | ||
| verify("blocked", L_blocked_field, A_np) | ||
|
|
||
| print("Compiling Tile16x16 (blocked, 16 threads, no shared memory)...") | ||
| cholesky_tile16() | ||
| qd.sync() | ||
| verify("tile16", L_tile16_field, A_np) | ||
| print() | ||
|
|
||
| t_baseline = benchmark(cholesky_baseline, WARMUP, ITERS) | ||
| t_blocked = benchmark(cholesky_blocked, WARMUP, ITERS) | ||
| t_tile16 = benchmark(cholesky_tile16, WARMUP, ITERS) | ||
|
|
There was a problem hiding this comment.
🟡 In verify(), detecting NaN/inf prints 'FAILED (nan/inf)' and returns float('inf') but does not raise or call sys.exit(); main() ignores all three return values. As a result, the smoke test added in this PR (test_tile16_cholesky_blocked_demo) can only detect crashes, not correctness failures — a kernel silently producing NaN/inf would print a FAILED message but exit 0, causing CI to pass.
Extended reasoning...
What the bug is: In misc/demos/cholesky_blocked.py, the verify() function (lines 267–280) detects NaN/inf by printing a failure message and returning float('inf'). It never raises an exception or calls sys.exit(1). In main() (lines 294, 299, 304), all three calls to verify() discard the return value entirely. Consequently, a correctness failure in any kernel exits with code 0.
Specific code path: verify() hits if np.isnan(err) or np.isinf(err) → prints → return float('inf'). main() calls verify(...) with no assignment or check. The script reaches its normal end and exits 0.
Why existing code doesn't prevent it: The smoke test in test_tile16.py checks only result.returncode \!= 0. Since the script exits 0 in all correctness-failure scenarios, the test always passes regardless of whether the kernels produced correct output.
Impact: The smoke test was explicitly added to address the PR's stated "bad point" — that the demo "could silently break if the Tile16x16 API changes." A Tile16x16 API regression that causes NaN/inf output would: print "FAILED (nan/inf)" to stdout, exit 0, and pass CI. The test catches outright crashes (import errors, kernel compile failures, exceptions) but not the more subtle case of a kernel producing garbage output.
Addressing the refutation: The refutation argues that the smoke test is intentionally checking only API stability (exit code 0), not correctness, and that individual operations are unit-tested in isolation. This is a reasonable position — the test docstring says "runs to completion" and the unit tests in test_tile16.py do cover individual tile primitives. However, the multi-tile blocked composition itself is not unit-tested (as noted in Q11 of the review), so the demo serves as the only exercise of the end-to-end blocked algorithm. A regression that passes all unit tests but corrupts the composition (e.g. a change to solve_triangular_()'s interaction with outer() in the Schur complement loop) would go undetected by CI.
Step-by-step proof: (1) Suppose a future change causes cholesky_tile16 to write NaN into L_tile16_field. (2) verify("tile16", L_tile16_field, A_np) computes err = np.max(np.abs(...)) → np.nan. (3) np.isnan(err) is True → prints "tile16 env 0: FAILED (nan/inf)", returns float('inf'). (4) Back in main(), no assignment: the return value is dropped. (5) Script prints benchmark numbers (which may still run since the kernel doesn't crash) and exits normally with code 0. (6) subprocess.run returns returncode=0. (7) pytest.fail is never reached. CI passes.
Fix: Check verify's return value in main() and call sys.exit(1) if it is infinite, or raise an exception inside verify() on failure.
The demo uses SharedArray which isn't supported on Metal/Vulkan backends, causing all Mac CI jobs to fail. Made-with: Cursor
The GPU clock ratio assertion (tolerance < 1) was too tight—observed deviation of 1.25 on CI runners. Widen to < 2 to accommodate normal GPU scheduling variance while still verifying proportionality. Made-with: Cursor
The per-branch concurrency group allowed parallel deploys to gh-pages, causing push rejections when another branch updated gh-pages first. Use a global concurrency group with cancel-in-progress: false so deployments queue instead of racing. Made-with: Cursor
This reverts commit 90eb029.
# Conflicts: # tests/python/test_tile16.py
* [Misc] Warn user to disable caching when print_ir/QD_DUMP_IR enabled (Genesis-Embodied-AI#425) Co-authored-by: v01dxyz <v01dxyz@v01d.xyz> * [Build] Pin torch version to CUDA 12.8 for CUDA tests (Genesis-Embodied-AI#428) * [Misc] Fixing up taichi-dev urls (Genesis-Embodied-AI#429) * [Perf] Rename cuda_graph to gpu_graph across the codebase (Genesis-Embodied-AI#430) * Misc: fix typo integeral -> integral (Genesis-Embodied-AI#434) Co-authored-by: v01dxyz <v01dxyz@v01d.xyz> * [Perf] CUDA graph 4: call from multiple locations (Genesis-Embodied-AI#420) * [Bug] Fix fastcache not restoring graph_do_while_arg (Genesis-Embodied-AI#435) * [Perf] Cache last-call result in perf_dispatch for single-compatible case (Genesis-Embodied-AI#438) * Fix gpu_graph fallback on old Nvidia GPU. (Genesis-Embodied-AI#443) * Fix shared memory offset not reset between CUDA kernels. (Genesis-Embodied-AI#442) * [Misc] Allow disabling GPU graph via QD_GPU_GRAPH=0 env var (Genesis-Embodied-AI#439) * [Misc] Add named top-level loops (Genesis-Embodied-AI#440) * [Misc] Rename gpu_graph to graph (Genesis-Embodied-AI#446) * [Misc] Add cross-platform shuffle (Genesis-Embodied-AI#447) * [Bug] Fix graph_do_while on Windows: search for cudadevrt.lib (Genesis-Embodied-AI#456) * [Bug] Also search default CUDA toolkit install location on Windows (Genesis-Embodied-AI#461) * [SPIRV] Feature Parity Atomics & Shared Array (Genesis-Embodied-AI#432) * [Misc] Change clang format to 120 characters (Genesis-Embodied-AI#463) * [Misc] CUDA graph 5 Add fatbin (Genesis-Embodied-AI#464) * [Bug] Reuse VkInstance across init/reset cycles (Genesis-Embodied-AI#465) * [Perf] Tiles 1: _load, _store, _eye_ (Genesis-Embodied-AI#466) * [Misc] Remove dead InternalFuncStmt type_check override (Genesis-Embodied-AI#471) * [Perf] Tiles 2: add cholesky and ger (Genesis-Embodied-AI#472) * [Perf] Tiles 2b: add triangular solve (Genesis-Embodied-AI#474) * [Misc] Refactor: use _get_col/_set_col in tiles load/store/init (Genesis-Embodied-AI#475) * [Build] Fix flaky test_clock_accuracy (Genesis-Embodied-AI#436) * Fix AARCH64 emitting invalid asm in CUDA kernels. (Genesis-Embodied-AI#473) Co-authored-by: Hugh Perkins <hughperkins@gmail.com> * [AMDGPU] Enable HIP memory pool and surface pool-exhaustion errors. (Genesis-Embodied-AI#485) * [AMDGPU] Scope hsaco tmp dir per-user to avoid collisions. (Genesis-Embodied-AI#484) * [Perf] Tiles 3: Add slice syntax, qd.outer() and initial doc (Genesis-Embodied-AI#477) * [AMDGPU] Fix gradient computation. (Genesis-Embodied-AI#486) * Enable all backends that are supported in unit tests. (Genesis-Embodied-AI#488) * Fix SPIRV ID overflow for large kernels due to autodiff. (Genesis-Embodied-AI#489) * [Misc] Fix purity checker to allow accessing constants from quadrants modules (Genesis-Embodied-AI#487) * [Misc] Increase tolerance for clock monotonic test (Genesis-Embodied-AI#492) * [CI] Serialize api doc workflow (Genesis-Embodied-AI#494) * [CI] Increase tolerance for clock test (Genesis-Embodied-AI#506) * [CI] Increase clock test tolerance to 20% (Genesis-Embodied-AI#509) * [Perf] Add tensor_type parametrization to tile16 tests (Genesis-Embodied-AI#504) * [Perf] Tiles 4b: Migrate tiles16 tests to enable fastcache (Genesis-Embodied-AI#505) * [Perf] Tiles 4c: add Tiles16x16 proxy (Genesis-Embodied-AI#507) * [Perf] Tiles 4d: Consolidate slice error tests using parametrize (Genesis-Embodied-AI#508) * [Perf] Tiles 4: add SharedArray slice support (Genesis-Embodied-AI#482) * [Perf] Tiles 5: add Cholesky benchmark demo (Genesis-Embodied-AI#483) * [Doc] Add user guide page for subgroup shuffle (Genesis-Embodied-AI#512) * [Perf] Implement cross-platform shuffle_down (Genesis-Embodied-AI#510) * [Perf] Add portable subgroup reduce_add and reduce_all_add (Genesis-Embodied-AI#511) * [Perf] Add first warmup config to perf dispatch (Genesis-Embodied-AI#422) * [AutoDiff] Autodiff 1: Add baseline adstack regression test for unary_collections (Genesis-Embodied-AI#500) * [AutoDiff] Autodiff 2: Implement derivative for tan (Genesis-Embodied-AI#501) * [AutoDiff] Autodiff 3: Recompute tanh/exp on the operand in the reverse pass (Genesis-Embodied-AI#502) * [AutoDiff] Autodiff 4: Mark rsqrt as non-linear for adstack promotion (Genesis-Embodied-AI#503) * [AutoDiff] Autodiff 5: Fix adjoint-alloca placement for GlobalLoads outside the current range-for (Genesis-Embodied-AI#496) * [AutoDiff] Autodiff 6: Adstack regression tests (Genesis-Embodied-AI#491) * [AutoDiff] Autodiff 7: Fix header size in AdStackAllocaStmt to match u64 runtime layout (Genesis-Embodied-AI#534) * [AutoDiff] Autodiff 8: Surface LLVM adstack push/pop overflow as a Python exception (Genesis-Embodied-AI#535) * [AutoDiff] Autodiff 9: Guard against LLVM worker-thread stack overflow from large per-task adstack budget (Genesis-Embodied-AI#495) * [AutoDiff] Autodiff 10: Implement adstack for SPIR-V (Genesis-Embodied-AI#490) * [AutoDiff] Autodiff 11: Latent adstack-adjacent fixes (AMDGPU hipFree, flush() keeps ctx_buffers_, always-preallocate) (Genesis-Embodied-AI#536) * [Doc] Add AGENTS.md with instructions for AI agents (Genesis-Embodied-AI#541) * [Bug] Abort kernel execution on assertion failure instead of segfaulting (Genesis-Embodied-AI#419) * [Type] ndarray typing 1: Add eval_str=True to inspect.signature() calls (Genesis-Embodied-AI#411) * [CI] Suppress reportPrivateImportUsage in torch-using files (Genesis-Embodied-AI#552) * [Misc] QD_DUMP_IR dumps to files with the task_id added to the filename (Genesis-Embodied-AI#441) * [Type] ndarray typing 2: Fix NDArray single-arg subscript crash (Genesis-Embodied-AI#412) * [Test] Flush xdist channel before worker exit so test failure reports are visible (Genesis-Embodied-AI#555) * [CI] Reduce test retries on CI from 3 to 1. (Genesis-Embodied-AI#554) * [AutoDiff] Autodiff 12: Heap-backed adstack on LLVM backends (CPU/CUDA/AMDGPU) (Genesis-Embodied-AI#537) * [AutoDiff] Autodiff 13: Heap-backed adstack on SPIR-V backends (Metal, Vulkan) (Genesis-Embodied-AI#493) * [AutoDiff] Autodiff 14: Resolve bounded-inner-loop adstacks without default_ad_stack_size fallback (Genesis-Embodied-AI#539) * [SPIRV] Vulkan SPIR-V correctness: atomic-view aliasing, PSB stride, narrow storage caps, u1 cast, per-init layer recheck (Genesis-Embodied-AI#513) * [Build] Autodiff 15: Replace 2022 MoltenVK pin with LunarG Vulkan SDK fetch and sanitise MoltenVK cap advertisement (Genesis-Embodied-AI#551) * [Test] Suppress stock pytest-timeout to avoid conflict with pytest_hardtle (Genesis-Embodied-AI#557) * [Vulkan] Use SDK validation layer for debugPrintf instead of apt package (Genesis-Embodied-AI#562) * [Test] Fix flaky perf_dispatch tests by increasing work amounts (Genesis-Embodied-AI#559) * [Test] Add --maxfail CLI option to run_tests.py (default 20) (Genesis-Embodied-AI#558) * [CI] Vulkan debug printf fix to address flaky tests (Genesis-Embodied-AI#563) * [Docs] Add a new page to help for first time contributors (Genesis-Embodied-AI#426) Authored-by: v01dxyz <v01dxyz@v01d.xyz> * [AutoDiff] Autodiff 16: Resolve reverse-mode adstack depths per-launch via runtime-evaluated SizeExpr (Genesis-Embodied-AI#543) * Fix: raise error if device memory allocation fails (Genesis-Embodied-AI#451) (Genesis-Embodied-AI#453) Co-authored-by: v01dxyz <v01dxyz@v01d.xyz> Co-authored-by: Hugh Perkins <hughperkins@gmail.com> * [CI] Add CI job to check line wrapping of comments and docs (Genesis-Embodied-AI#564) * [Misc] Add coverage report to PRs, including kernels (Genesis-Embodied-AI#470) * [CI] CI wrap check feeds only diffs to agent (Genesis-Embodied-AI#567) * Skip 'flaky' test on MacOS CI. (Genesis-Embodied-AI#573) * [Test] Fix missing `import sys` in test_fail_device_memory_allocation (Genesis-Embodied-AI#574) * [CI] Fix Vulkan debugPrintf flake with session-scoped warmup (Genesis-Embodied-AI#571) * [AutoDiff] determine_ad_stack_size: replace whole-CFG Bellman-Ford with SCC + DAG DP (Genesis-Embodied-AI#575) * [Test] Fix macOS OOM skip reason to describe actual root cause (Genesis-Embodied-AI#576) * [Lang] whole_kernel_cse: 2.5x compile time speedup on large kernels (Genesis-Embodied-AI#577) * [CI] Add CI check for unnecessarily deleted comments (Genesis-Embodied-AI#570) * [CI] Migrate coverage report to github Check page (Genesis-Embodied-AI#566) * [Lang] Skip IR verifier between passes unless debug=true (Genesis-Embodied-AI#579) * [Lang] Inline AdStack ops on release LLVM codegen: dramatically reduces compile time for adstack-enabled reverse-mode kernels (Genesis-Embodied-AI#584) * [CUDA] Honor offline_cache=False end-to-end so QD_OFFLINE_CACHE=0 actually gives a cold compile (Genesis-Embodied-AI#580) * [Type] Tensor 24 (Genesis-Embodied-AI#561) Co-authored-by: hugh <hugh@slurm-login-0.slurm-login.tenant-slurm.svc.cluster.local> * [Lang] auto_diff host-walk reductions: dramatically faster front-end compile time on adstack-enabled reverse-mode kernels (Genesis-Embodied-AI#587) * [AutoDiff] Speed up reverse-mode kernel launches on GPU backends (Genesis-Embodied-AI#578) * [Vulkan] Move adstack-sizer scratch out of Function-scope memory to fix SPIR-V pipeline build failures (Genesis-Embodied-AI#588) * [AutoDiff] Improve diagnosis of unsupported reverse-mode AD patterns (Genesis-Embodied-AI#590) * [Bug] Fix: promote Ndarray to AnyArray in build_Name for flattened struct fields (Genesis-Embodied-AI#592) * [SPIR-V] Shrink reverse-grad kernel MSL by ~50% (Genesis-Embodied-AI#591) * [CI] Add CI check that PR changes have test coverage (Genesis-Embodied-AI#596) * [Perf] Enable zero-copy in to_torch() and to_numpy() (Genesis-Embodied-AI#450) * Add BufferView: safe sub-range ndarray access for kernels (Genesis-Embodied-AI#585) Co-authored-by: alanray-tech <alanray-tech@users.noreply.github.com> Co-authored-by: Hugh Perkins <hughperkins@gmail.com> * [Doc] Add user-facing fastcache documentation (Genesis-Embodied-AI#597) Co-authored-by: hugh <hugh@slurm-login-0.slurm-login.tenant-slurm.svc.cluster.local> * [Misc] Upgrade to enable v1 dlpack so to_numpy(copy=False) writable (Genesis-Embodied-AI#598) Co-authored-by: root <root@rtx-209-201.slurm-compute.tenant-slurm.svc.cluster.local> * [AutoDiff] Cut reverse-mode adstack memory usage 10x on all backends (Genesis-Embodied-AI#599) * [Misc] Add CI check for feature file factorization (Genesis-Embodied-AI#606) * [Perf] Skip _recursive_set_args for all-Field frozen dataclass structs (Genesis-Embodied-AI#607) Co-authored-by: Cursor <cursoragent@cursor.com> * [AutoDiff] SNode-arm bound-expr capture rejects fold-attack gate indices (Genesis-Embodied-AI#610) * [Misc] Suppress field fastcache warning for qd.Tensor (Genesis-Embodied-AI#615) Co-authored-by: Cursor <cursoragent@cursor.com> * [AutoDiff] Adstack heap: clip reducer count by per-task loop trip count (compile-time and SizeExpr-evaluated) (Genesis-Embodied-AI#611) * [Misc] Forward copy= through qd.Tensor, add copy=None option (Genesis-Embodied-AI#616) Co-authored-by: Cursor <cursoragent@cursor.com> * [Doc] Update README (Genesis-Embodied-AI#617) Co-authored-by: Cursor <cursoragent@cursor.com> * [CI] Fix coverage report showing def lines as uncovered (Genesis-Embodied-AI#623) Co-authored-by: Cursor <cursoragent@cursor.com> * [Perf] Generic launcher: persistent context, JIT-pointer reuse, Metal compute encoder, LLVM-GPU async memory ops (Part 1/2) (Genesis-Embodied-AI#619) * [CI] Encode Python-first testing policy in coverage-check prompt (Genesis-Embodied-AI#622) Co-authored-by: Cursor <cursoragent@cursor.com> * [CI] Add PR Line change report (Genesis-Embodied-AI#624) Co-authored-by: Cursor <cursoragent@cursor.com> * [CI] Disable quadrants pytest plugin during quadrants internal coverage runs (Genesis-Embodied-AI#629) Co-authored-by: Cursor <cursoragent@cursor.com> * [AutoDiff] Adstack load+store eliminations: EliminateRecomputableAdStackPushes pass + leaf extensions (Genesis-Embodied-AI#621) * [CI] Simplify coverage PR comment to a single linked line (Genesis-Embodied-AI#630) * [CUDA] Add AGX Thor, SM_110 (Genesis-Embodied-AI#631) Co-authored-by: Johnny Nunez and Hugh Perkins * [CI] Lines changed report: collapse PR comment to a single linked totals line (Genesis-Embodied-AI#632) * [FEATURE] Support external Metal command queue via qd.init (Genesis-Embodied-AI#618) Co-authored-by: Cursor <cursoragent@cursor.com> * [Perf] Cache adstack-sizer metadata per task across SPIR-V + LLVM-GPU; per-snode / DeviceAllocation invalidation (Part 2/2) (Genesis-Embodied-AI#620) * [AutoDiff] Disable EliminateRecomputableAdStackPushes pending mutated-SNode chain-leaf fix (Genesis-Embodied-AI#633) * [AutoDiff] Adstack chain-clone safety: mutated-SNode leaf reject + load_top consumer-aware guard (Genesis-Embodied-AI#634) * [Docs] Add user-guide page for qd.simt.block.* primitives (Genesis-Embodied-AI#638) * [Docs] Expand qd.simt.subgroup user-guide page to cover every op (Genesis-Embodied-AI#639) * [Perf] Streams 1-4 (Genesis-Embodied-AI#410) * [Docs] Add user-guide page for matrix decompositions and solvers (Genesis-Embodied-AI#643) * [Bug] Revert "[Perf] Streams 1-4 (Genesis-Embodied-AI#410)" (Genesis-Embodied-AI#650) * [Docs] Add user-guide page for atomics and bit operations (Genesis-Embodied-AI#640) * [Docs] Add user-guide page for qd.simt.grid.* primitives (Genesis-Embodied-AI#641) * [AutoDiff] Adstack max-reducer: parallel multi-axis MaxOverRange dispatch (Genesis-Embodied-AI#635) * [AMDGPU] Fix amdgpu parallel rand init (Genesis-Embodied-AI#658) * [Perf] Adstack: skip max-reducer recognizer on CPU + lift host-eval cap (Genesis-Embodied-AI#655) * [Perf] Re-land Streams 1-4 with bug fixes (Genesis-Embodied-AI#653) * [AMDGPU] Apply device_memory_GB=0.3 cap to AMDGPU tests (Genesis-Embodied-AI#659) * [Perf] Per-launch host sync: drop wait_idle on SPIR-V, pin stream and drop stream_synchronize on CUDA/AMDGPU (Genesis-Embodied-AI#654) * [AMDGPU] Unload hipModule_t in JITModuleAMDGPU destructor (Genesis-Embodied-AI#660) * [AMDGPU] Trim default mempool on qd.reset() (Genesis-Embodied-AI#669) * [AMDGPU] Hoist rand-state buffer to process lifetime (Genesis-Embodied-AI#668) * [Streams] Use events for streams serialization on AMDGPU and CUDA (Genesis-Embodied-AI#667) * [Perf] Adstack max-reducer: launch cache + zero-copy result map; content-stable registry_id (Genesis-Embodied-AI#671) * [SPIR-V] dispatch_max_reducers: register each task with the real kernel name (Genesis-Embodied-AI#675) * [AutoDiff] Debug-mode field/grad/dual: dtype, layout, and access-time invariants (Genesis-Embodied-AI#677) * [Docs] Add user-guide page for qd.algorithms.* device-wide algorithms (Genesis-Embodied-AI#642) Co-authored-by: alanray-tech <alan.ray@genesis-ai.company> * [Docs] Doc for existing atomics: switch support table to per-backend columns (Genesis-Embodied-AI#657) Co-authored-by: alanray-tech <alan.ray@genesis-ai.company> * [GPU] Cross gpu atomics (Genesis-Embodied-AI#666) Co-authored-by: alanray-tech <alan.ray@genesis-ai.company> * [GPU] Make block operations portable cross-gpu (Genesis-Embodied-AI#664) * [Perf] CPU LLVM adstack-cache: skip per-launch bump-writes + ndarray_shapes capture on forward-only handles (Genesis-Embodied-AI#685) * [GPU] Cross-GPU for grid ops (Genesis-Embodied-AI#670) * [Math] Make bitop operations portable cross-gpu (Genesis-Embodied-AI#662) * [AMDGPU] Always use wave64, on both RDNA and CDNA (Genesis-Embodied-AI#687) * [AMDGPU] Use syncscope("agent") for atomix xor to avoid CAS livelock (Genesis-Embodied-AI#672) * [GPU] New bit ops for QIPC (Genesis-Embodied-AI#679) * [GPU] Subgroup ops cross-gpu (Genesis-Embodied-AI#665) * [Graph] Rename CUDA Graph to Graph in docs (Genesis-Embodied-AI#691) * [SPIR-V] Fix FIFO-queue ordering when sharing command queue. (Genesis-Embodied-AI#694) * [Atomics] New QIPC ops for atomics (Genesis-Embodied-AI#690) * Pass dataclass sub-structs into qd.func (Genesis-Embodied-AI#698) * [AMDGPU] HIP graph runtime support for @qd.kernel(graph=True) (Genesis-Embodied-AI#692) * [CI] Add per-file timing report to Mac Metal test job (Genesis-Embodied-AI#695) Co-authored-by: Cursor <cursoragent@cursor.com> * [CI] Enable kernel disk cache during tests (Genesis-Embodied-AI#696) * [Math] New QIPC ops for single-threaded linalg (Genesis-Embodied-AI#683) * [BREAKING][GPU] New QIPC ops for subgroups (Genesis-Embodied-AI#676) * [GPU] New QIPC ops for block (Genesis-Embodied-AI#684) * [GPU] New device-level ops for QIPC (Genesis-Embodied-AI#693) * [algorithms] PrefixSumExecutor: drop unused GRID_SZ local (Genesis-Embodied-AI#701) * [block] sync(): fix unsupported-arch error message (Genesis-Embodied-AI#700) * [volatile_load] add qd.volatile_load primitive (closes Genesis-Embodied-AI#648) (Genesis-Embodied-AI#702) * [AutoDiff] Reject recycled identity_key in AdStackCache::register_adstack_sizing_info (Genesis-Embodied-AI#708) * [Vulkan] Declare GroupNonUniform SPIR-V caps and enable shaderSubgroupExtendedTypes (Genesis-Embodied-AI#707) * Fix duplicate HIP graph driver-function declarations after v1.0.0 merge The amd-integration fork had cherry-picked the HIP graph driver functions (graph_create / graph_destroy / graph_add_kernel_node / graph_instantiate / graph_exec_destroy / graph_launch), and upstream v1.0.0 added the same set. The per-file 3-way merge appended both copies into amdgpu_driver_functions.inc.h, producing redeclaration errors that broke the AMDGPU RHI/runtime compile. Drop the upstream duplicate block; the signatures are identical to the fork's existing declarations. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix AMDGPU launcher coherence and num_instructions visibility after v1.0.0 merge - kernel_launcher.cpp: the 3-way merge spliced upstream v1.0.0's launch_llvm_kernel rewrite (ephemeral arg/context buffers, explicit-stream path, AmdgpuDefaultStream PinGuard) onto the AMD fork's kernarg-by-value + persistent-scratch design, leaving references to undefined `ephemeral_context_ptr`. Restore the fork's coherent launch_llvm_kernel verbatim; it calls the (already merged) enhanced launch_offloaded_tasks, which keeps the max-reducer dispatch and stream-parallel groups adapted onto the AMD launch path. - llvm_context.h: both the fork and upstream added `num_instructions`; the merge kept upstream's private placement, but the AMDGPU codegen force-inline heuristic calls it statically from outside the class. Move it back to the public section. Co-authored-by: Cursor <cursoragent@cursor.com> * Restore async result D2H and hoist kernarg vectors in AMDGPU launcher The v1.0.0 merge resolution regressed two amd-integration baseline optimizations in launch_llvm_kernel / launch_offloaded_tasks: - The per-launch result-buffer copy was a blocking memcpy_device_to_host, forcing a host stall on every value-returning launch and serializing the GPU pipeline. Restore the async D2H (the caller synchronizes lazily when it needs the value); external-array transfers still stream_synchronize once before reading back. - launch_task constructed the kernarg std::vectors from initializer lists ({kernarg_payload} / {kernarg_size}) on every dispatch (heap alloc + free per launch). Hoist arg_ptrs/arg_sizes out of the per-task launch and reuse. Co-authored-by: Cursor <cursoragent@cursor.com> * amdgpu: default to LDS permlane64 emulation; drop host-x86 barrier asm on retarget Two AMDGPU JIT-compile crashes surfaced after the v1.0.0 merge pulled in the QIPC subgroup ops (Genesis-Embodied-AI#676), which made the rigid constraint solver's wave-cooperative reductions route through `amdgpu_cross_half_shuffle_i32`. Both manifested as a SIGSEGV inside `llvm::SIInstrInfo::getInstSizeInBytes` during `JITSessionAMDGPU::compile_module_to_hsaco` (i.e. at first kernel launch), and reproduce on gfx942 / MI300X. Baseline 0.4.6 never emitted these constructs, which is why it was unaffected. 1. Native `llvm.amdgcn.permlane64` lowering crashes the bundled LLVM 22.1.0 AMDGPU backend. Default `amdgpu_permlane64` to the existing LDS-roundtrip software emulation on every target (it produces identical results). Add `QD_AMDGPU_USE_NATIVE_PERMLANE64=1` to opt back into the native instruction once the backend bug is fixed; the old `QD_AMDGPU_FORCE_PERMLANE64_FALLBACK` is now the default and still honored. This is the actual crash fix. 2. The runtime module is compiled by the host x86_64 clang and only retargeted to amdgcn here, so `amdgpu_cross_half_shuffle_i32`'s `__asm__ volatile("" : "+v"(byte))` optimization barrier carries x86 flag clobbers (`~{dirflag},~{fpsr},~{flags}`) that are meaningless on AMDGPU. The IR verifies but the empty-body INLINEASM is invalid on the amdgcn target. Neutralize empty-body barrier asm during retarget (forward the tied value, then erase) so no stale host asm reaches codegen. On the wave64 targets we ship `ds_bpermute` already addresses the full wave, so the hint is a no-op. Co-authored-by: Cursor <cursoragent@cursor.com> * style: apply clang-format (v19.1.7) to AMDGPU fn_attrs and launcher sources CI pre-commit's clang-format hook reformatted these files (long declarations/lambda signatures collapsed onto single lines per the repo's clang-format config). Apply the same formatting so the hook passes. No functional changes. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(amdgpu): use CreateNeg for branchless i32 sgn instead of CreateSub(0, input) clang-tidy (modernize-use-nullptr, -warnings-as-errors) flagged `builder->CreateSub(0, input)` in the i32 sgn path: the literal `0` binds to the `llvm::Value*` LHS parameter as a null pointer, not an integer zero. Replace with `builder->CreateNeg(input)`, which emits `0 - input` with a proper zero constant -- identical intended semantics, and clang-tidy clean. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Robert Dazi <14996868+v01dXYZ@users.noreply.github.com> Co-authored-by: v01dxyz <v01dxyz@v01d.xyz> Co-authored-by: Hugh Perkins <hughperkins@gmail.com> Co-authored-by: Alexis DUBURCQ <alexis.duburcq@gmail.com> Co-authored-by: hugh <hugh@slurm-login-0.slurm-login.tenant-slurm.svc.cluster.local> Co-authored-by: alanray-tech <alan.ray@genesis-ai.company> Co-authored-by: alanray-tech <alanray-tech@users.noreply.github.com> Co-authored-by: root <root@rtx-209-201.slurm-compute.tenant-slurm.svc.cluster.local> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Johnny <johnnynuca14@gmail.com>
Issue: #
Brief Summary
Summary
Adds a complete blocked Cholesky factorization demo (
misc/demos/cholesky_blocked.py) that benchmarks register-resident Tile16x16 against two scalar-Crout baselines, andlinks it from the Tile16x16 user guide.
What's in this PR
misc/demos/cholesky_blocked.py(323 lines) — a self-contained benchmark script that implements and compares three batched 92×92 Cholesky kernels across 4096environments:
block.sync()calls.Tile16x16, no shared memory, zero syncs, 16 threads.The script loads SPD test matrices, runs warmup + timed iterations, verifies reconstruction error, and prints a results table.
docs/source/user_guide/tile16.md— adds a "Example: blocked Cholesky" section at the end with a link to the demo and a results table (5.19× speedup on Blackwell).Good points
memory and sync barriers).
python misc/demos/cholesky_blocked.py— generates its own test data, verifies correctness, and benchmarks.Bad points
qd.init(arch=qd.cuda)and won't run on Vulkan/Metal.misc/demos/and isn't exercised by CI, so it could silently break if the Tile16x16 API changes.copilot:summary
Walkthrough
copilot:walkthrough