perf(linalg): route cross-order reorder through the backend transpose - #458
Merged
Conversation
A cross-order reorder at fixed logical shape (RowMajor<->ColumnMajor) is a physical axis-reversal permutation, byte-identical to backend.transpose with the reverse perm under the source order. The naive reorder_data is a backend-less sequential element loop that never reaches HPTT; routing the conversion through the transpose uses HPTT for f64/f32/complex under --features hptt and the parallelizable native kernel otherwise. Add reorder_via_backend and route the dense row-major-sandwich sites (decomposition, contract, expm, solve, eigen, einsum) and the block-sparse trace result reorder through it. A criterion bench (reorder_sandwich) shows HPTT beats the naive loop at every representative shape (1.5-8.5x, no small-2D regression), the native kernel parallelizes large reorders even without HPTT, and a rank-3 SVD moves 4-14% end to end under --features hptt. Clarify that ComputeBackend::transpose honors desc.order per call (transpose is layout-parametric), sanctioning the source-order transpose. Collapse a redundant normalize-then-RowMajor step in batched einsum. to_vec_in_order stays on reorder_data (its callers pass a no-op order).
There was a problem hiding this comment.
Pull request overview
This PR improves linalg “row-major sandwich” performance by routing cross-memory-order reorders through ComputeBackend::transpose, enabling HPTT acceleration when built with --features hptt, and using the backend’s native transpose kernel otherwise.
Changes:
- Introduces
reorder_via_backend(newreorder_routemodule) and routes multiple linalg sites (decomposition/contract/expm/solve/eigen/einsum and a block-sparse trace reorder) through it. - Makes
reshape_for_backend/prepare_for_gemmbackend-aware and fallible to propagate backend transpose errors. - Adds a Criterion benchmark (
reorder_sandwich) and clarifiesComputeBackend::transpose’s per-call layout contract.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| crates/ariadnetor-linalg/src/solve.rs | Switches solve/inverse reorders to reorder_via_backend and propagates errors. |
| crates/ariadnetor-linalg/src/reorder_route.rs | Adds the reorder-via-transpose helper and byte-identity tests. |
| crates/ariadnetor-linalg/src/lib.rs | Registers the new reorder_route module. |
| crates/ariadnetor-linalg/src/expm/mod.rs | Routes expm’s reorder steps through the backend transpose path. |
| crates/ariadnetor-linalg/src/einsum.rs | Removes redundant normalization and routes batch/slice reorders through the backend. |
| crates/ariadnetor-linalg/src/eigen.rs | Routes eigen decomposition reorders through reorder_via_backend. |
| crates/ariadnetor-linalg/src/decomposition/mod.rs | Makes reshape helper backend-aware/fallible and updates decomposition callers. |
| crates/ariadnetor-linalg/src/decomposition/lq.rs | Updates LQ path to the fallible backend-aware reshape helper. |
| crates/ariadnetor-linalg/src/contract.rs | Routes GEMM prep and result reconstruction reorders through the backend transpose path. |
| crates/ariadnetor-linalg/src/block_sparse_trace.rs | Routes per-block trace-result reorder through reorder_via_backend. |
| crates/ariadnetor-linalg/Cargo.toml | Registers the new reorder_sandwich benchmark target. |
| crates/ariadnetor-linalg/benches/reorder_sandwich.rs | Adds microbench + end-to-end SVD probe to measure naive vs routed reorder. |
| crates/ariadnetor-core/src/backend.rs | Documents that transpose must honor desc.order per call (layout-parametric). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The rank<=1 fast path in reorder_via_backend copied the whole buffer via to_vec. DenseStorage is Arc-backed, so re-tag the order by cloning the storage Arc and rebuilding the layout instead of moving the data.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The linalg row-major sandwich (decomposition, contract, expm, solve, eigen, einsum) normalizes rank>2 operands across memory order with
reorder_data, a backend-less per-element loop that never reaches HPTT. A cross-order reorder at fixed logical shape is a physical axis-reversal permutation, byte-identical toComputeBackend::transposewith the reverse permutation under the source order. This routes those reorders through the transpose, so builds with--features hpttuse HPTT and the default build uses the parallelizable native kernel.Closes #310
Changes
reorder_via_backend(reorder_route.rs): a reverse-perm transpose under the source order, re-wrapped at the original logical shape; early exits forfrom == to, rank <= 1, and empty tensors.reshape_for_backend/prepare_for_gemmgain a backend argument and become fallible.reorder_sandwichcriterion bench: a per-shape micro comparison of naivereorder_datavs the routed transpose, plus a rank-3 SVD end-to-end probe.ComputeBackend::transposehonorsdesc.orderper call (transpose is layout-parametric), sanctioning the source-order transpose.Impact
to_vec_in_orderstays onreorder_data; its callers pass a no-op order, so routing would only add setup to a clone.Test plan
reorder_via_backend == reorder_dataacross ranks 1-4 (including an empty shape), both order directions, and all four scalars, under both the default and--features hpttbuilds.cargo test --workspaceis green (73 binaries, 0 failures).Performance
Criterion medians (f64; absolute times are hardware-dependent, the ratios less so). Speedup is relative to the always-sequential
reorder_data; the routed path followspar_for_transpose(parallel for large shapes, sequential for small).Reorder kernel,
--features hptt(microseconds):reorder_data[256, 8][512, 512][128, 16, 128][64, 8, 8, 64]f32 reaches about 8.5x; complex is about 1.5x to 2.5x. No shape regresses.
Reorder kernel, default build (no HPTT) — the native kernel's auto-parallelism vs the sequential loop (microseconds):
reorder_data[512, 512][128, 16, 128][64, 8, 8, 64]Small reorders below the parallel threshold stay roughly neutral.
End-to-end rank-3 SVD, default vs
--features hptt(milliseconds):[64, 8, 64][128, 4, 128]The operation-level gain is diluted by the faer SVD; reorder-dominated operations (large rank>2 contract or permute) benefit more.
@coderabbitai ignore