From 453aa114f1e867b58670a7ed47fecf72c97ad652 Mon Sep 17 00:00:00 2001 From: David Widmann Date: Thu, 28 Sep 2023 14:38:06 +0200 Subject: [PATCH 1/3] Check which FFTW libraries are available --- Project.toml | 2 +- src/FFTW.jl | 2 ++ src/providers.jl | 21 ++++++++++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Project.toml b/Project.toml index e53ebb6..65dbd37 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "FFTW" uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" -version = "1.7.1" +version = "1.7.2" [deps] AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c" diff --git a/src/FFTW.jl b/src/FFTW.jl index 4366ee7..7b6ac39 100644 --- a/src/FFTW.jl +++ b/src/FFTW.jl @@ -11,6 +11,8 @@ import AbstractFFTs: Plan, ScaledPlan, fftshift, ifftshift, rfft_output_size, brfft_output_size, plan_inv, normalization +import FFTW_jll +import MKL_jll export dct, idct, dct!, idct!, plan_dct, plan_idct, plan_dct!, plan_idct! diff --git a/src/providers.jl b/src/providers.jl index 58817b1..372cd69 100644 --- a/src/providers.jl +++ b/src/providers.jl @@ -1,17 +1,26 @@ +const valid_fftw_providers = if FFTW_jll.is_available() && MKL_jll.is_available() + ("fftw", "mkl") +elseif FFTW_jll.is_available() + ("fftw",) +elseif MKL_jll.is_available() + ("mkl",) +else + error("no valid FFTW library available") +end function get_provider() # Note: we CANNOT do something like have the `default` value be `get(ENV, "JULIA_FFTW_PROVIDER", "fftw")` here. # This is because the only way the Julia knows that a default has changed is if the values on-disk change; so # if your "default" value can be changed from the outside, you quickly run into cache invalidation issues. # So the default here _must_ be a constant. - default_provider = "fftw" + default_provider = first(valid_fftw_providers) # Load the preference provider = @load_preference("provider", default_provider) # Ensure the provider matches one of the ones we support - if provider ∉ ("fftw", "mkl") - @error("Invalid provider setting \"$(provider)\"; valid settings include [\"fftw\", \"mkl\"], defaulting to \"fftw\"") + if provider ∉ valid_fftw_providers + @error("Invalid provider setting \"$(provider)\"; valid settings include [$(join(map(x -> '"' * x * '"', valid_fftw_providers), ", "))]") provider = default_provider end return provider @@ -34,8 +43,8 @@ Also supports `Preferences` sentinel values `nothing` and `missing`; see the doc `Preferences.set_preferences!()` for more information on what these values mean. """ function set_provider!(provider; export_prefs::Bool = false) - if provider !== nothing && provider !== missing && provider ∉ ("fftw", "mkl") - throw(ArgumentError("Invalid provider value '$(provider)'")) + if provider !== nothing && provider !== missing && provider ∉ valid_fftw_providers + throw(ArgumentError("Invalid provider value \"$(provider)\"; valid settings include [$(join(map(x -> '"' * x * '"', valid_fftw_providers), ", "))]")) end set_preferences!(@__MODULE__, "provider" => provider; export_prefs, force = true) if provider != fftw_provider @@ -47,7 +56,6 @@ end # If we're using fftw_jll, load it in @static if fftw_provider == "fftw" - import FFTW_jll libfftw3[] = FFTW_jll.libfftw3_path libfftw3f[] = FFTW_jll.libfftw3f_path @@ -82,7 +90,6 @@ end # If we're using MKL, load it in and set library paths appropriately. @static if fftw_provider == "mkl" - import MKL_jll libfftw3[] = MKL_jll.libmkl_rt_path libfftw3f[] = MKL_jll.libmkl_rt_path const _last_num_threads = Ref(Cint(1)) From 9a3850b5cafa35696e94d2a80f88b478b09acfcf Mon Sep 17 00:00:00 2001 From: David Widmann Date: Thu, 28 Sep 2023 16:31:07 +0200 Subject: [PATCH 2/3] Do not unconditionally load MKL_jll but match platforms --- src/FFTW.jl | 2 -- src/providers.jl | 42 +++++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/FFTW.jl b/src/FFTW.jl index 7b6ac39..4366ee7 100644 --- a/src/FFTW.jl +++ b/src/FFTW.jl @@ -11,8 +11,6 @@ import AbstractFFTs: Plan, ScaledPlan, fftshift, ifftshift, rfft_output_size, brfft_output_size, plan_inv, normalization -import FFTW_jll -import MKL_jll export dct, idct, dct!, idct!, plan_dct, plan_idct, plan_dct!, plan_idct! diff --git a/src/providers.jl b/src/providers.jl index 372cd69..383176a 100644 --- a/src/providers.jl +++ b/src/providers.jl @@ -1,10 +1,26 @@ -const valid_fftw_providers = if FFTW_jll.is_available() && MKL_jll.is_available() - ("fftw", "mkl") -elseif FFTW_jll.is_available() - ("fftw",) -elseif MKL_jll.is_available() - ("mkl",) -else +# Hardcoded list of supported platforms +# In principle, we could check FFTW_jll.is_available() and MKL_jll.is_available() +# but then we would have to load MKL_jll which we want to avoid (lazy artifacts!) +const platforms_providers = Dict( + Base.BinaryPlatforms.Platform("aarch64", "macos") => ("fftw",), + Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("i686", "linux"; libc = "glibc") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("i686", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("i686", "windows") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("powerpc64le", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "macos") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "freebsd") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "windows") => ("fftw", "mkl"), +) +const valid_fftw_providers = Base.BinaryPlatforms.select_platform(platforms_providers, Base.BinaryPlatforms.HostPlatform()) +if valid_fftw_providers === nothing error("no valid FFTW library available") end @@ -56,6 +72,12 @@ end # If we're using fftw_jll, load it in @static if fftw_provider == "fftw" + import FFTW_jll + if !FFTW_jll.is_available() + # more descriptive error message if FFTW is not available + # (should not be possible to reach this) + error("FFTW library cannot be loaded: please switch to the `mkl` provider for FFTW.jl") + end libfftw3[] = FFTW_jll.libfftw3_path libfftw3f[] = FFTW_jll.libfftw3f_path @@ -90,6 +112,12 @@ end # If we're using MKL, load it in and set library paths appropriately. @static if fftw_provider == "mkl" + import MKL_jll + if !MKL_jll.is_available() + # more descriptive error message if MKL is not available + # (should not be possible to reach this) + error("MKL library cannot be loaded: please switch to the `fftw` provider for FFTW.jl") + end libfftw3[] = MKL_jll.libmkl_rt_path libfftw3f[] = MKL_jll.libmkl_rt_path const _last_num_threads = Ref(Cint(1)) From 9db530cfc76335f3dcc9da45a84215cf7f9f7ddf Mon Sep 17 00:00:00 2001 From: David Widmann Date: Fri, 6 Oct 2023 00:36:30 +0200 Subject: [PATCH 3/3] Apply suggestions --- src/providers.jl | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/providers.jl b/src/providers.jl index 383176a..1fbaff6 100644 --- a/src/providers.jl +++ b/src/providers.jl @@ -1,25 +1,27 @@ -# Hardcoded list of supported platforms -# In principle, we could check FFTW_jll.is_available() and MKL_jll.is_available() -# but then we would have to load MKL_jll which we want to avoid (lazy artifacts!) -const platforms_providers = Dict( - Base.BinaryPlatforms.Platform("aarch64", "macos") => ("fftw",), - Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "glibc") => ("fftw",), - Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "musl") => ("fftw",), - Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), - Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), - Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), - Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), - Base.BinaryPlatforms.Platform("i686", "linux"; libc = "glibc") => ("fftw", "mkl"), - Base.BinaryPlatforms.Platform("i686", "linux"; libc = "musl") => ("fftw",), - Base.BinaryPlatforms.Platform("i686", "windows") => ("fftw", "mkl"), - Base.BinaryPlatforms.Platform("powerpc64le", "linux"; libc = "glibc") => ("fftw",), - Base.BinaryPlatforms.Platform("x86_64", "macos") => ("fftw", "mkl"), - Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "glibc") => ("fftw",), - Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "musl") => ("fftw",), - Base.BinaryPlatforms.Platform("x86_64", "freebsd") => ("fftw",), - Base.BinaryPlatforms.Platform("x86_64", "windows") => ("fftw", "mkl"), -) -const valid_fftw_providers = Base.BinaryPlatforms.select_platform(platforms_providers, Base.BinaryPlatforms.HostPlatform()) +const valid_fftw_providers = let + # Hardcoded list of supported platforms + # In principle, we could check FFTW_jll.is_available() and MKL_jll.is_available() + # but then we would have to load MKL_jll which we want to avoid (lazy artifacts!) + platforms_providers = Dict( + Base.BinaryPlatforms.Platform("aarch64", "macos") => ("fftw",), + Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("i686", "linux"; libc = "glibc") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("i686", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("i686", "windows") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("powerpc64le", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "macos") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "freebsd") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "windows") => ("fftw", "mkl"), + ) + Base.BinaryPlatforms.select_platform(platforms_providers, Base.BinaryPlatforms.HostPlatform()) +end if valid_fftw_providers === nothing error("no valid FFTW library available") end @@ -76,7 +78,7 @@ end if !FFTW_jll.is_available() # more descriptive error message if FFTW is not available # (should not be possible to reach this) - error("FFTW library cannot be loaded: please switch to the `mkl` provider for FFTW.jl") + @error("FFTW library cannot be loaded: Run `FFTW.set_provider!(\"mkl\")` to switch to MKL") end libfftw3[] = FFTW_jll.libfftw3_path libfftw3f[] = FFTW_jll.libfftw3f_path @@ -116,7 +118,7 @@ end if !MKL_jll.is_available() # more descriptive error message if MKL is not available # (should not be possible to reach this) - error("MKL library cannot be loaded: please switch to the `fftw` provider for FFTW.jl") + @error("MKL cannot be loaded: Run `FFTW.set_provider!(\"fftw\")` to switch to the FFTW library") end libfftw3[] = MKL_jll.libmkl_rt_path libfftw3f[] = MKL_jll.libmkl_rt_path