Add a TBLIS.jl package extension - #290
Draft
lkdvos wants to merge 2 commits into
Draft
Conversation
Adds `TBLISBackend`, which routes `tensoradd!`, `tensortrace!` and `tensorcontract!` through the TBLIS library via TBLIS.jl. TBLIS contracts strided tensors in place, so it avoids the permuted intermediates that the BLAS-based backend has to materialize. The backend is opt-in: loading TBLIS.jl does not register any `select_backend` method. Arguments TBLIS cannot express -- mixed or unsupported element types, non-strided arrays, `Diagonal` factors -- are delegated back to the regular backend selection, so a single `backend = TBLISBackend()` keeps working for a whole `@tensor` block. Two library quirks are worked around in the extension: * `tblis_tensor_mult` ignores the per-tensor conjugation flags (unlike `tblis_tensor_add`, which honours them). When both factors are conjugated this is resolved by conjugating the output in place; when only one is, that factor is materialized into a temporary from the allocator. * TBLIS.jl only exposes its tensor constructor for `StridedArray`, and offers no way to set the conjugation flag or to own the length/stride buffers, so the extension builds the `tblis_tensor` struct itself and keeps every referenced buffer rooted with `GC.@preserve`. Includes a benchmark script and measurements under `benchmarks/`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TBLIS.jl v0.3 regenerated its C bindings, so `tblis_tensor` is now an opaque 64-byte blob with pointer-based accessors rather than a struct with individual fields, and its high-level constructor only accepts `StridedArray`. Initialize the descriptor with `tblis_init_tensor_scaled_*` instead -- which works for any `StridedView` -- patch in the conjugation flag through the generated `setproperty!`, and hand the resulting `Ref` to the low-level `tblis_tensor_add` and `tblis_tensor_mult`. Benchmark numbers re-measured against the same release candidate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Adds
TensorOperationsTBLISExt, a package extension that provides aTBLISBackendon top of TBLIS.jl. This supersedes the standalone TensorOperationsTBLIS.jl.Important
This depends on TBLIS.jl v0.3, which is not registered yet (General has 0.1.0 and 0.2.0). CI will not resolve until it is released. Everything below was validated against
QuantumKitHub/TBLIS.jl@main(977ce94).What it does
TBLISBackend()routestensoradd!,tensortrace!andtensorcontract!through TBLIS, which contracts strided tensors in place rather than reshaping them into matrices, so it avoids the permuted intermediates the BLAS path has to materialize.It is opt-in: loading TBLIS.jl registers no
select_backendmethod. Arguments TBLIS cannot express — mixed or unsupported element types, non-strided arrays,Diagonalfactors — fall back to whateverselect_backendwould have chosen, so onebackend = TBLISBackend()keeps working for a whole@tensorblock.Things found while wiring this up
tblis_tensor_multignores the per-tensor conjugation flags, whiletblis_tensor_addhonours them. Verified directly against tblis 1.3. Worked around by conjugating the output in place when both factors are conjugated, and by materializing a temporary from the allocator when only one is.tblis_tensorconstructor is restricted toStridedArray, so it cannot take theStridedViews these kernels work with, and it offers no way to set the conjugation flag. The extension therefore initializes descriptors withtblis_init_tensor_scaled_*, patches the flag through the generatedsetproperty!, and keeps every referenced buffer rooted withGC.@preserve. Widening that constructor upstream (and letting it take a conjugation flag) would let this drop back to the public API.Tests
test/tblis.jl, wired intoruntests.jl. Compares againstStridedNativeover all four supported element types for add / trace / contract, every conjugation combination, non-contiguous views, outer products, scalar outputs, argument checking, the fallback paths,@tensor/nconintegration, a GC-pressure stress loop, and threading. All 20 testsets pass.β == 0is exercised withNaN-poisoned outputs: TBLIS does ignoreCin that case, in bothaddandmult, so noNaNleaks.Benchmarks
2× Xeon Gold 6244 (16 physical cores), 16 threads for both OpenBLAS and TBLIS, Julia 1.12.6, tblis_jll 1.3.0. Full tables in
benchmarks/README.md;speedup= fastest built-in backend / TBLIS.Float64:So: permutation-heavy contractions ~2× faster, adds and traces 3-9× faster, plain GEMM ~25% slower, small tensors dominated by descriptor overhead.
ComplexF64is a different story — contractions run at 0.05–0.15× of BLAS. That is thetblisbinaries, not this extension: a baretblis_tensor_multon a 1000³ complex matrix product reaches ~25 GFLOP/s against ~500 GFLOP/s formul!(ComplexF32 is worse still, ~12 vs ~1160 GFLOP/s), andtblis_jllv1.2.0 behaves identically, so it is not a regression from the v1.3 bump. Complexadd/traceare unaffected (6.6× and 4.4× wins). This is called out in theTBLISBackenddocstring and in the docs.🤖 Generated with Claude Code