Reuse direct BLAS LU workspaces during refactorization#1099
Reuse direct BLAS LU workspaces during refactorization#1099ChrisRackauckas-Claude wants to merge 8 commits into
Conversation
|
Implementation/validation scratchpad:
The upstream allocation contract is now verified on all three macOS lanes. The downstream <48-byte continuation claim remains intentionally pending a NonlinearSolve retest against the merged/released dependency. |
|
macOS LTS failure analysis and follow-up at
A replacement CI run is now required to verify the real Accelerate ccall on macOS LTS/stable/pre. |
|
Current-head CI classification for
Every failing job is now reproduced or traced independently of this PR's Apple Accelerate changes, with focused fixes or tracking linked above. |
2a997ad to
fe6283c
Compare
|
Implemented the follow-up request, “Do similar changes on those v1.12 failures,” in The OpenBLAS and BLIS direct LU paths now follow the Apple Accelerate cache design: factors, pivots, and the LAPACK status reference remain in stable mutable caches, and internal Because the cache no longer stores a permanent Local verification on the final tree:
The branch was rebased onto |
|
Follow-up commit The job's refactorization path passed, but the newly tested transient generic factorization view failed because Accelerate stores LAPACK pivots as I added an unguarded regression that constructs an Apple cache with
Separately, the required clean-main Julia 1.10 KLU investigation is complete. It confirms #1095 is not causal and records the Julia 1.10 logging-dispatch limitation in #1098; no unrelated code or weakened test was added here. |
|
Final current-head CI classification for
Three checks are red, with exact independent classifications:
No further code change to this focused PR is indicated by the completed CI. |
|
Follow-up for the cache-convention review, commit
Local verification on Julia 1.12.6:
The PR remains draft and should be ignored until reviewed by @ChrisRackauckas. |
|
CI follow-up for Implementation-relevant lanes pass:
The remaining red checks are independently classified:
Local final verification also passed on Julia 1.12.6 ( Please continue to ignore this draft until reviewed by @ChrisRackauckas. |
|
Implemented the follow-up factorization audit in 12c4197.\n\n- Replaced the broad AbstractFactorization cache-shape convention with an explicit per-algorithm reuse policy. The direct/tuple cache layout remains only as a documented implementation fallback after a solver family opts in.\n- Audited all 52 package-owned concrete factorization families. Every family now declares direct, extracted, normal-equations, custom, or no reuse; a recursive test rejects future unregistered families.\n- 36 families reuse cached numeric work: 22 direct layouts, 5 extracted layouts, 2 normal-equations layouts, and 7 custom backends.\n- The 16 explicit non-reuse families either have no numeric factorization to reuse or lack a public cache-compatible adjoint solve. Generic reverse rules preserve A and refactorize adjoint(A); AD backends without that fallback report unsupported.\n- NormalCholeskyFactorization and NormalBunchKaufmanFactorization correctly reuse the cached factorization of AᴴA. Their reverse RHS operator solves with that cached factor and then multiplies by A, including rectangular full-column-rank systems.\n- ChainRules, Mooncake, and Enzyme share one cached-adjoint entry point. Krylov reverse solves are also centralized on adjoint(A); this fixes Enzyme's previous transpose(A) behavior for complex matrices.\n- Added custom cached reverse solves for SimpleLU, SparseColumnPivotedQR, Butterfly, MUMPS, Pardiso, HSL MA57, and HSL MA97.\n\nLocal verification:\n- Julia 1.10 GROUP=Core: passed; Adjoint Sensitivity 106/106, Butterfly 44/44.\n- Julia 1.12 GROUP=AD: passed; Mooncake 46/46, Enzyme 49/49, with existing broken-allocation markers unchanged.\n- Julia 1.12 GROUP=QA: QA 15 pass / 2 existing broken; JET 29 pass / 6 existing broken.\n- Julia 1.12 GROUP=LinearSolveMUMPS: 13/13.\n- Julia 1.12 GROUP=LinearSolvePardiso: 91/91, including real and complex cached adjoint solves.\n- Julia 1.12 GROUP=LinearSolveHSL: extension compiled; runtime tests followed the existing skip because the locally installed HSL library is unavailable.\n- Runic 1.7 check and git diff --check: clean. |
|
CI follow-up for 12c4197: all 57 completed non-skipped code/test checks passed, including AD release/LTS, Core release/LTS/pre, GPU, MUMPS, Pardiso, Apple Accelerate, downstream integration, QA, and formatting. Four matrix entries were intentionally skipped.\n\nThe sole failed check is Documentation. Its log shows Documenter linkcheck received HTTP 429 from https://pyamg.readthedocs.io three times and then exited on linkcheck. This is external rate limiting, not a code or documentation error from this change. I attempted to rerun the failed workflow, but GitHub rejected the request because the connected account does not have repository-admin permission. Please rerun Documentation when convenient. |
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Keep factor, pivot, and status storage stable across direct BLAS refactorizations, and expose transient factorization views to reverse-mode rules. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Convert Accelerate's Int32 pivots only when constructing the transient generic LU view used by reverse-mode rules. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
12c4197 to
139902c
Compare
|
Added allocation QA in
Local verification:
Full |
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
|
Follow-up in
Local verification on the final commit:
The new CI run is in progress. The separate clean-main QA reexport failure remains isolated in draft #1106. Please continue to ignore this draft until reviewed by @ChrisRackauckas. |
|
One-hour CI follow-up for
The three red checks are independently classified:
The branch is clean and synchronized with the pushed commit. Please continue to ignore this draft until reviewed by @ChrisRackauckas. |
Ignore this PR until it has been reviewed by @ChrisRackauckas.
Summary
getrf!/getrs!wrappers, avoiding repeatedLU, tuple,Ref, and keyword-argument constructionInt32pivots to the stdlibBlasInttype only when its transient genericLUview is requestedmacos-latestfor LTS, stable, and pre-release JuliaThis changes no public API.
Motivation and root cause
Allocation profiling for SciML/NonlinearSolve.jl#1072 first isolated Apple Accelerate continuation allocations to repeated direct-LU refactorizations. Julia 1.12 testing then exposed the same cache-layout problem in the OpenBLAS and BLIS implementations: each fresh factorization rebuilt
LUand tuple wrappers around buffers that already existed, while defaulted keyword arguments could also construct fresh pivot/status objects.The hot paths now retain the factor matrix, pivot vector, and status reference directly in algorithm-specific caches. Factorization mutates those buffers and returns only the scalar LAPACK status. On Julia 1.12, warmed square refactorizations through both OpenBLAS and BLIS now meet the zero-allocation regression ceiling used by the new tests.
Regression coverage
The direct-BLAS tests exercise OpenBLAS and BLIS for
Float32,Float64,ComplexF32, andComplexF64, including:Failureand recovery on the next nonsingular matrixThe Apple Accelerate regression tests check the same factorization view and explicitly emulate its
Cintpivot storage on every platform. Zygote/ChainRules, Mooncake, and Enzyme tests compare direct OpenBLAS reverse-mode results against finite differences. Core tests also load the BLIS extension directly so its solver and verbosity paths run in the normal group.Local verification
GROUP=Core: passed, including Direct BLAS Refactorization Reuse 130/130, Basic 600/600, LU Refactorization Reuse 53/53, Adjoint 26/26, FixedSizeArrays 47/47, ComponentArrays 10/10, ForwardDiff 119/119, Verbosity 66/66, and all remaining Core groupsGROUP=AD: passed; Mooncake 44/44, Static Arrays 23 passed / 1 pre-existing broken, Caching 49 passed / 23 pre-existing broken, Enzyme 49/49GROUP=QA: passed; Aqua/ExplicitImports 15 passed / 2 pre-existing broken, JET 29 passed / 6 pre-existing brokenGROUP=AppleAccelerateafter the generic-view pivot fix: refactorization 55/55; mixed precision 14 passed / 2 pre-existing brokenGROUP=AppleAccelerateafter the generic-view pivot fix: refactorization 51/51; mixed precision 14 passed / 2 pre-existing broken--check .: passedgit diff --check: passedThe first expanded CI head exposed that Accelerate stores pivots as
Int32, while Julia 1.10's genericLUsolve expects stdlibBlasInt(Int64). Commit27278b6econverts pivots only while constructing the transient AD view, leaving the allocation-free refactorization hot path unchanged.Current-head CI
The pushed head is terminal with 55 passing checks and 4 intentional skips. Relevant passing lanes include:
The three red checks are independently classified and do not report a failure in this change:
https://pyamg.readthedocs.io. A clean-main workflow has the identical strict-linkcheck failure, while a later clean-main run passes, confirming intermittent external rate limiting. Separate draft Use stable PyAMG project links #1103 retargets the five project links to PyAMG's official GitHub repository; its full strict local docs build passes without changinglinkcheck,warnonly, or ignore settings.Julia 1.10 QA baseline
The dense default-solver JET assertion still reports stdlib/Krylov fallback dispatch on Julia 1.10, so the existing unconditional broken expectation is narrowed to Julia versions before 1.12. Julia 1.12 passes that assertion normally.
A separate clean-main investigation also reproduced the KLU JET failure under Julia 1.10. It bisected the first mandatory failure to
45944595(#1083), which removed the prior broken expectation; #1095 is not causal. Rewriting KLU's extraction call positionally removes its two reports but immediately exposes the same Julia 1.10NamedTuple/pairs dispatch in required Base/SciMLLogging failure logging, even for standalone@warn. The incomplete code patch was reverted rather than weakening or silencing the assertion. Full evidence is recorded in #1098.