Repository navigation
ENH: enable ILP64 linear algebra - #10784
Conversation
|
Note that the CI run does not really probe this new ILP64 mode, since that needs scipy built from source. Am happy to add a CI run if wanted! Meanwhile to test it locally, one needs something like |
|
Thanks for the patch @ev-br. The Numba team discussed this at the last internal meeting and it was decided to not rely on having scipy as a build-time dependency as this might require additional steps on our side. Could you adapt your patch to use only the env var |
|
Updated to the suggestion. The updated variant does not inspect SciPy at build time, thus to use ILP64 linear algebra, users must both set |
|
I think this approach is more complex than it needs to be since we decided there is no need to compile both variants and select the backend dynamically. (Practically, no one can build a working ILP environment with wheels from PyPI, so there is no situation where dynamic detection is needed.) I think we instead want the existing |
|
Updated to the suggestion: |
guilhermeleobas
left a comment
There was a problem hiding this comment.
Code LGTM @ev-br. Before we merge this one, you need to include a release notes file
https://github.com/numba/numba/blob/main/docs/upcoming_changes/README.rst
| @needs_lapack | ||
| @unittest.skipIf( | ||
| not has_lapack or not _LAPACK_ILP64 |
There was a problem hiding this comment.
Minor nit: no need for not has_lapack if @needs_lapack is used
|
And sorry, I just realized my |
To use ILP64 linear algebra, you *must* set `NUMBA_LAPACK_ILP64=1` environment variable at build time, *and* have the ILP64-enabled SciPy at runtime. Any other combination is an error at run time: - `NUMBA_LAPACK_ILP64=1 python setup.py build_ext -i` and SciPy is LP64 - `python setup.py build_ext -i` and SciPy is ILP64 both of will error out at run time. Internally, typedef the F_INT variable to be either int32 or int64, depending on the build mode. The rest is unchanged: numba pulls pointers to lapack functions from scipy's cython_lapack. These functions *must* have the matching ABI, thus check it once and erorr out on the ABI mismatch. While at it, fix a small latent bug: two workspace-size scratch variables in rsyevd/cheevd were plain `int` instead of `F_INT`. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Guilherme Leobas <guilhermeleobas@gmail.com>
|
Thanks @guilhermeleobas , I added a tentative release note snippet, and addressed your review comments. And merged main again, so that the PR is squeaky clean :-). |
|
Thank you for patch and review. |
Intends to close #10777 : enable using ILP64 LAPACK ABI (64-but integers) if scipy exports this ABI. (The latter requires that scipy is built from source.)
User-visible UI largely follows #10777 (comment) : a new
NUMBA_LAPACK_ILP64environment variable selects the target BLAS/LAPACK ABI; if not set, the build system queries the ABI thatscipy.linalg.cython_blas exports; if scipy is not available, then falls back to backwards-compatible LP64.The summary of precise behavior for various combinations is under the fold (Claude generated)
Details
Numba LP64/ILP64 build and runtime matrix
Table 1 — what Numba is built for
NUMBA_LAPACK_ILP64(if set) overrides the build-environment scipy outright, so these collapse to one effective build width:NUMBA_LAPACK_ILP641(or any value not in0/false/no/empty)0/false/no/ emptyTable 2 — what happens at runtime, given what Numba was built for
Checked lazily, only the first time a jitted function actually touches
np.linalg/BLAS (ensure_lapack()/ensure_blas()) — plainimport numbaand non-linalg jitted code are unaffected in every row below.numba_*_32symbols bound, widths matchRuntimeError(clean refusal, no C call made)ImportError: scipy 0.16+ is required for linear algebraRuntimeError(clean refusal, no C call made)numba_*_64symbols bound, widths matchImportError: scipy 0.16+ is required for linear algebraOnly the two diagonal cells (build width == runtime width) actually execute BLAS/LAPACK; every off-diagonal case fails loudly and safely before any C call, rather than corrupting memory.
Caveat
"scipy at runtime" here means what
scipy.__config__reports, which is scipy's own static self-description -- it's what the mismatch check in Table 2 actually reads.That can itself be misleading for an MKL-SDL-linked scipy (
libmkl_rt.so) ifMKL_INTERFACE_LAYERis overridden in the environment: MKL's dynamic dispatch can be forced to a different actual widththan
__config__reports, and neither Numba nor scipy currently have visibility into that at runtime.That failure mode sits outside what this table (or the current runtime check) can see.
The implementation also follows #10777 (comment) : the ABI is decided once at Numba build time, and at runtime the scipy-exported ABI is checked against the build-time expectation.
Internally, there two symbol sets, suffixed with
_32 / _64, and the correct one is picked at runtime.The patch is actually smaller than it looks: there's a large chunk of code moved verbatim from
lapack.ctolapack_width.hto avoid code duplication for the two ABI modes. To ease review, the PR is organized into three commits:lapack.ctolapack_width.hThe patch is generated with heavy assistance from Claude. That said, there is a human in the loop (me), who read, modified and tweaked claude's generated code, is accountable for the contribution (per the linked AI policy) and is happy to discuss details or modify the PR per review requests.
What this PR does not fix are OP usage examples from #10777. Bear with me: if
mkl_rt, andMKL_INTERFACE_LAYER=ILP64,GNUthen the ABI choice is being made inside MKL itself, and numba has no knowledge of it, thus running into an ABI mismatch.
I believe this is a user error, and the way to find it is clearly visible from
numba -soutput, which reports LP64:While this is a footgun, it requires a deliberate user action, and will not happen if scipy is built in the recommended way, against
mkl-ilp64-...library, as done in e.g. https://github.com/scipy/scipy/blob/main/.github/workflows/linux_blas.yml#L117-L120Unless the user manually fiddles with
MKL_INTERFACE_LAYER, everything I believe either just works correctly, or fails with a clear RuntimeError.