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

Check and use only available FFTW libraries #278

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
2 changes: 2 additions & 0 deletions src/FFTW.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
devmotion marked this conversation as resolved.
Show resolved Hide resolved

export dct, idct, dct!, idct!, plan_dct, plan_idct, plan_dct!, plan_idct!

Expand Down
21 changes: 14 additions & 7 deletions src/providers.jl
Original file line number Diff line number Diff line change
@@ -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), ", "))]")

Check warning on line 23 in src/providers.jl

View check run for this annotation

Codecov / codecov/patch

src/providers.jl#L23

Added line #L23 was not covered by tests
provider = default_provider
end
return provider
Expand All @@ -34,8 +43,8 @@
`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), ", "))]"))

Check warning on line 47 in src/providers.jl

View check run for this annotation

Codecov / codecov/patch

src/providers.jl#L46-L47

Added lines #L46 - L47 were not covered by tests
end
set_preferences!(@__MODULE__, "provider" => provider; export_prefs, force = true)
if provider != fftw_provider
Expand All @@ -47,7 +56,6 @@

# 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

Expand Down Expand Up @@ -82,7 +90,6 @@

# If we're using MKL, load it in and set library paths appropriately.
@static if fftw_provider == "mkl"
import MKL_jll
Copy link
Member

@giordano giordano Sep 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not doing the test is_available here? People are not going to be happy to having to unconditionally download MKL, that was the whole point of #133 (which you seemed to agree with, judging by the 👍)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not aware of this issue. Mainly, I thought it would be more user-friendly to figure out the supported libraries in advance, before trying to set them. Only moving the check here won't help with my use case and the linked issue above.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any other way to check whether a library can be loaded apart from ..._jll.is_available()? Maybe checking the system architecture is an OKish workaround?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any other way to check whether a library can be loaded apart from ..._jll.is_available()?

No.

Maybe checking the system architecture is an OKish workaround?

That's going to hard-code answers which may potentially change over time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only moving the check here won't help with [...] the linked issue above.

Why not? Capture the fact that the artifact isn't available and throw a helpful error message to explain what to do, instead of getting a cryptic UndefVarError that some users don't know what to do with.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if I understand this implementation correctly this is automagically changing the provider if the requested one isn't actually available, which doesn't sound very deterministic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, switching to the supported default provider was the main point - changing the LocalPreferences.toml file manually on my end creates git conflicts when moving branches and pulling all the time (and if I forget to adjust it, compilation will fail). To some extent that's already done in the current code: If you specify an invalid provider other than fftw and mkl, FFTW will just display an @error and switch to the default provider (which is fixed to fftw currently). So basically I'm in the same situation, on my computer mkl is also an invalid provider so I would like to switch to the default one. And I guess you could hypothetically think about an analogous scenario where fftw is invalid and you would like to switch to the mkl as default provider.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Displaying a more descriptive error message is an improvement but I think a solution that just defines the (in)valid providers correctly would be much more convenient.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's going to hard-code answers which may potentially change over time.

Yes, a bit annoying. But since I didn't see any other alternative to define the valid providers correctly, I switched to hardcoding the supported platforms.

I guess the supported platforms could always be updated easily - and probably supported platforms for MKL won't change much at least? If we're more ambitious, probably we could even automatically extract it from the Artifacts.toml files in FFTW_jll and MKL_jll.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the supported platforms could always be updated easily - and probably supported platforms for MKL won't change much at least?

It did change.

libfftw3[] = MKL_jll.libmkl_rt_path
libfftw3f[] = MKL_jll.libmkl_rt_path
const _last_num_threads = Ref(Cint(1))
Expand Down
Loading