test(linalg): benchmark per-block transpose naive vs HPTT - #456
Conversation
The block-sparse contract and permute paths transpose each block with a naive per-element kernel that bypasses HPTT. Whether HPTT wins is block-shape dependent and was not measurable: rank-2 permuted contraction takes the GEMM trans-flag path, so no existing bench drives the physical per-block transpose. Add a block_transpose group sweeping representative block shapes (rank-3 and rank-4 folds over per-sector degeneracy d) through the public ComputeBackend::transpose, so the naive kernel (default build) and HPTT (--features hptt) can be compared per shape via criterion baselines.
State on the benchmark that it times ComputeBackend::transpose (native naive vs HPTT), not the in-tree transpose_block_data the block-sparse paths currently call, and why the native-vs-HPTT ratio still stands in for the routing payoff (same cost class). Prevents a reader from taking the numbers as the current call path's cost.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a new Criterion benchmark file section introducing a ChangesBlock Transpose Benchmark
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
Pull request overview
This PR adds a Criterion micro-benchmark to isolate and measure the cost of per-block tensor transposes via ComputeBackend::transpose, enabling direct comparison of the native naive transpose kernel vs the HPTT implementation (--features hptt) across representative block shapes and permutations.
Changes:
- Introduces a
block_transposebenchmark group that sweeps representative rank-3 and rank-4 block shapes overd ∈ {16, 32, 64, 128}. - Benchmarks sequential transpose for all cases and adds a parallel-policy variant only for the largest
dto limit total benchmark runtime. - Reuses per-benchmark input/output buffers to avoid measuring allocation overhead instead of transpose cost.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
The block-sparse contract and permute paths transpose each block with a naive per-element kernel that bypasses HPTT. Whether HPTT would win is block-shape dependent and was not measurable: rank-2 permuted contraction takes the GEMM trans-flag path, so no existing benchmark drives the physical per-block transpose.
This adds an isolating micro-benchmark that times
ComputeBackend::transposeacross representative block shapes, so the native naive kernel (default build) and HPTT (--features hptt) can be compared per shape via criterion baselines.Refs #311 — this satisfies that issue's "needs a benchmark" prerequisite; routing the block-sparse sites through the backend is a separate follow-up (see Notes).
Changes
crates/ariadnetor-linalg/benches/block_sparse_ops.rs: add ablock_transposegroup sweeping rank-3(d, 2, d)and rank-4(d, 2, 2, d)folds over per-sector degeneracydin{16, 32, 64, 128}, each perm chosen to reach the physical transpose rather than the GEMM trans-flag fast path. Sequential across the whole sweep, plus a parallel variant at the largestd.Test plan
cargo clippy --benches -- -D warnings: clean.Both configs compile and run; measured with
--save-baseline naive(default build) then--features hptt --baseline naive.Result: HPTT beats the naive kernel at every representative shape, the margin growing with block size. Times are single-machine criterion medians; the load-bearing result is the relative naive-vs-HPTT ratio, not the absolute values.
Parallel at d=128 is far slower than sequential (~55 us vs ~6-12 us): Rayon overhead dominates at these block sizes, so the per-block transpose should stay sequential.
Notes
ComputeBackend::transpose(native naive vs HPTT), not the in-treetranspose_block_datathe block-sparse paths call today. The two are the same cost class (both O(n), output-driven, stride-indexed), so the native-vs-HPTT ratio stands in for the payoff of routing those sites through the backend; it is not a measurement of the current call path.transpose_block_datasites throughComputeBackend::transposeand hoist the redundant rhs re-transpose out of the contraction's inner loop, keeping the per-block transpose sequential.Summary by CodeRabbit