Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of lazy JLLs for LinearAlgebra #57719

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

staticfloat
Copy link
Member

@staticfloat staticfloat commented Mar 11, 2025

This alters CompilerSupportLibraries_jll, OpenBLAS_jll and
libblastrampoline_jll to use LazyLibrary objects and thereby be loaded
only upon first dlopen() or ccall() to the individual library
objects. Note that this is one of the more complicated cases, as
libblastrampoline must have OpenBLAS_jll added as a dynamic dependency
(as it does not actually have it listed in its shared object headers)
and also has some on-load callbacks that must be invoked.

Long-term, I would like to replace the bespoke JLLs here with actual JLL
source code, and vendor a version of LazyJLLWrappers in-tree to do the
actual code generation even for Base. That is left as future work.

[0] JuliaLang/LinearAlgebra.jl#1235

staticfloat added a commit to JuliaLang/LinearAlgebra.jl that referenced this pull request Mar 11, 2025
This alters CompilerSupportLibraries_jll, OpenBLAS_jll and
libblastrampoline_jll to use `LazyLibrary` objects and thereby be loaded
only upon first `dlopen()` or `ccall()` to the individual library
objects.  Note that this is one of the more complicated cases, as
`libblastrampoline` must have OpenBLAS_jll added as a dynamic dependency
(as it does not actually have it listed in its shared object headers)
and also has some on-load callbacks that must be invoked.

This must be paired with the appropriate base Julia changes [0].

[0] JuliaLang/julia#57719
@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch from 85eb73d to d537c45 Compare March 11, 2025 13:51
staticfloat added a commit to JuliaLang/LinearAlgebra.jl that referenced this pull request Mar 11, 2025
This alters CompilerSupportLibraries_jll, OpenBLAS_jll and
libblastrampoline_jll to use `LazyLibrary` objects and thereby be loaded
only upon first `dlopen()` or `ccall()` to the individual library
objects.  Note that this is one of the more complicated cases, as
`libblastrampoline` must have OpenBLAS_jll added as a dynamic dependency
(as it does not actually have it listed in its shared object headers)
and also has some on-load callbacks that must be invoked.

This must be paired with the appropriate base Julia changes [0].

[0] JuliaLang/julia#57719
@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch from d537c45 to b43712b Compare March 11, 2025 14:42
@topolarity topolarity force-pushed the sf/lazy_linear_algebra branch from b43712b to 3db34a3 Compare March 11, 2025 14:59
@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch 2 times, most recently from d21736d to 24bdde7 Compare March 11, 2025 21:02
@staticfloat staticfloat requested a review from topolarity March 11, 2025 21:07
@staticfloat
Copy link
Member Author

This is working locally now, I can confirm that Libdl.dllist() shows that libgfortran, libopenblas64_ and libblastrampoline are all not loaded until the first Linear Algebra call!

Note that this is attempting to conform to the LazyJLLWrappers API, which includes things like eager_mode(), which is called by JLLWrappers.jl. This is to provide backwards-compatibility with JLLs that expect all dependencies from all dependent JLLs to have already dlopen()'ed their libraries.

What this means is that for any realistic workload where there are JLLs that depend on LBT/OpenBLAS, everything is going to get eagerly loaded upon loading of that JLL anyway, until those JLLs are built to use LazyJLLWrappers instead of JLLWrappers, which functionally means waiting for BB2 to be ready, as it contains the new analysis passes that track things like library interdependencies, etc... However, for workloads that never use linear algebra workloads, this will be a nice savings, as the libraries will now never get loaded!

@topolarity
Copy link
Member

The --trim failure should be fixed up by #57734

@topolarity topolarity added the backport 1.12 Change should be backported to release-1.12 label Mar 11, 2025
@staticfloat staticfloat marked this pull request as draft March 11, 2025 23:56
@staticfloat
Copy link
Member Author

I've converted this to draft because I realized that while "real" JLLs that use JLLWrappers will correctly call eager_mode() on these lazy stdlib JLLs, other stdlib JLLs that are not lazy yet but that depend on any of these new lazy stdlib JLLs won't, I need to add that in here.

staticfloat added a commit to JuliaLang/LinearAlgebra.jl that referenced this pull request Mar 12, 2025
This alters CompilerSupportLibraries_jll, OpenBLAS_jll and
libblastrampoline_jll to use `LazyLibrary` objects and thereby be loaded
only upon first `dlopen()` or `ccall()` to the individual library
objects.  Note that this is one of the more complicated cases, as
`libblastrampoline` must have OpenBLAS_jll added as a dynamic dependency
(as it does not actually have it listed in its shared object headers)
and also has some on-load callbacks that must be invoked.

This must be paired with the appropriate base Julia changes [0].

[0] JuliaLang/julia#57719
@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch 3 times, most recently from b85e778 to 6109346 Compare March 12, 2025 00:25
@staticfloat staticfloat marked this pull request as ready for review March 12, 2025 00:30
@topolarity
Copy link
Member

It's also worth noting that once we land this PR, --trim will not support loading BLAS until we fix #57707

@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch 4 times, most recently from 94382bd to afc71c7 Compare March 12, 2025 15:36
@topolarity
Copy link
Member

I think you might need a rebase for the trimming test to pass, and the following patch:

diff --git i/base/libdl.jl w/base/libdl.jl
index 77f608e77e..d94a2fd0e2 100644
--- i/base/libdl.jl
+++ w/base/libdl.jl
@@ -333,7 +333,7 @@ struct LazyLibraryPath
     pieces::Tuple{Vararg{Any}}
     LazyLibraryPath(pieces...) = new(pieces)
 end
-Base.string(llp::LazyLibraryPath) = joinpath(String[string(p) for p in llp.pieces])
+@inline Base.string(llp::LazyLibraryPath) = joinpath(String[string(p) for p in llp.pieces])
 Base.cconvert(::Type{Cstring}, llp::LazyLibraryPath) = Base.cconvert(Cstring, string(llp))
 # Define `print` so that we can wrap this in a `LazyString`
 Base.print(io::IO, llp::LazyLibraryPath) = print(io, string(llp))

The robust solution to this will require a callable of some kind, but for now massaging is required to make sure that the components of the path are visible to the optimizer

@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch from 7dcb242 to b4cc2f8 Compare March 12, 2025 21:10
staticfloat added a commit to JuliaLang/LinearAlgebra.jl that referenced this pull request Mar 13, 2025
This alters CompilerSupportLibraries_jll, OpenBLAS_jll and
libblastrampoline_jll to use `LazyLibrary` objects and thereby be loaded
only upon first `dlopen()` or `ccall()` to the individual library
objects.  Note that this is one of the more complicated cases, as
`libblastrampoline` must have OpenBLAS_jll added as a dynamic dependency
(as it does not actually have it listed in its shared object headers)
and also has some on-load callbacks that must be invoked.

This must be paired with the appropriate base Julia changes [0].

[0] JuliaLang/julia#57719
@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch 2 times, most recently from 44bd276 to 41e8fb4 Compare March 13, 2025 14:28
@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch 3 times, most recently from 4919c69 to a127439 Compare March 14, 2025 22:03
staticfloat and others added 4 commits March 14, 2025 22:10
This alters CompilerSupportLibraries_jll, OpenBLAS_jll and
libblastrampoline_jll to use `LazyLibrary` objects and thereby be loaded
only upon first `dlopen()` or `ccall()` to the individual library
objects.  Note that this is one of the more complicated cases, as
`libblastrampoline` must have OpenBLAS_jll added as a dynamic dependency
(as it does not actually have it listed in its shared object headers)
and also has some on-load callbacks that must be invoked.

Long-term, I would like to replace the bespoke JLLs here with actual JLL
source code, and vendor a version of `LazyJLLWrappers` in-tree to do the
actual code generation even for Base.  That is left as future work.

This must be paired with the appropriate `LinearAlgebra.jl` changes [0].

[0] JuliaLang/LinearAlgebra.jl#1235
This makes more sense, reduces work, and avoids that perennial thorn in
my side, that in-tree builds store libraries in `${prefix}/lib`, whereas
installed builds store libraries in `${prefix}/lib/julia`.

Co-authored-by: Cody Tapscott <84105208+topolarity@users.noreply.github.com>
We can no longer depend on the fact that these libraries will be eagerly
loaded (huzzah!) so we must teach these helper functions to either
inspect the lazy CSL JLL for the necessary information, or just directly
load the library.
@staticfloat staticfloat force-pushed the sf/lazy_linear_algebra branch from a127439 to 3433d57 Compare March 15, 2025 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport 1.12 Change should be backported to release-1.12
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants