diff --git a/.travis.yml b/.travis.yml index 814463e..dde7c26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,10 @@ os: - osx julia: - nightly +env: + matrix: + - JULIA_FFTW_PROVIDER=FFTW + - JULIA_FFTW_PROVIDER=MKL notifications: email: false # uncomment the following lines to override the default test script diff --git a/README.md b/README.md index 43c4173..4b3b7b3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # FFTW.jl This package provides Julia bindings to the [FFTW](http://www.fftw.org/) library for -fast Fourier transforms, as well as functionality useful for signal processing. +fast Fourier transforms (FFTs), as well as functionality useful for signal processing. These functions were formerly a part of Base Julia. -Users with a build of Julia based on Intel's Math Kernel Library (MKL) can take use MKL -for FFTs by setting an environment variable `JULIA_FFTW_PROVIDER` to `MKL` and running -`Pkg.build("FFTW")`. +Alternatively, the FFTs in Intel's Math Kernel Library (MKL) can be used +by setting an environment variable `JULIA_FFTW_PROVIDER` to `MKL` and running +`Pkg.build("FFTW")`. If Julia was built with MKL, then Julia's MKL will be +used for FFTs; otherwise the [Conda.jl package](https://github.com/JuliaPy/Conda.jl) +will be used to download MKL via the [mkl_fft Anaconda package](https://github.com/IntelPython/mkl_fft). Setting this environment variable only needs to be done for the first build of the package; after that, the package will remember to use MKL when building and updating. Note however that MKL provides only a subset of the functionality provided by FFTW. See diff --git a/REQUIRE b/REQUIRE index 58e6a08..3b69d8a 100644 --- a/REQUIRE +++ b/REQUIRE @@ -2,4 +2,5 @@ julia 0.7.0-DEV.3449 AbstractFFTs 0.3.0 Reexport Compat 0.62.0 -BinDeps 0.6.0 +BinaryProvider 0.3.0 +Conda diff --git a/deps/build.jl b/deps/build.jl index 9499fe5..943ce7d 100644 --- a/deps/build.jl +++ b/deps/build.jl @@ -1,4 +1,5 @@ -using Libdl +import Libdl +const depsfile = joinpath(@__DIR__, "deps.jl") # If BLAS was compiled with MKL and the user wants MKL-based FFTs, we'll oblige. # In that case, we have to do this little dance to get around having to use BinDeps @@ -13,26 +14,34 @@ else provider = "FFTW" open(f -> println(f, provider), settings, "w") end -if provider == "MKL" && Base.BLAS.vendor() === :mkl - mklpath = Libdl.dlpath("libmkl_rt") - depsfile = joinpath(@__DIR__, "deps.jl") +if provider == "MKL" + if Base.BLAS.vendor() === :mkl + mklpath = Libdl.dlpath("libmkl_rt") + else + using Conda + Conda.add("mkl_fft") + mklpath = joinpath(Conda.lib_dir(Conda.ROOTENV), "libmkl_rt") + end + mklpath = escape_string(mklpath) isfile(depsfile) && rm(depsfile, force=true) open(depsfile, "w") do f println(f, """ # This is an auto-generated file, do not edit - using Libdl - if Libdl.dlopen_e("$mklpath") == C_NULL - error("Unable to load MKL from '$mklpath'.\\n", - "Please rerun Pkg.build(\\"FFTW\\") and restart Julia.") + import Libdl + const libfftw3 = "$mklpath" + const libfftw3f = libfftw3 + function check_deps() + if Libdl.dlopen_e(libfftw3) == C_NULL + error("Unable to load MKL from '$mklpath'.\\n", + "Please rerun Pkg.build(\\"FFTW\\") and restart Julia.") + end end - const libfftw = "$mklpath" - const libfftwf = "$mklpath" """) end -elseif provider == "MKL" - error("MKL build requested for FFTW but Julia was not built with MKL.\n", - "To fix this, set ENV[\"JULIA_FFTW_PROVIDER\"] = \"FFTW\" and \n", - "rerun Pkg.build(\"FFTW\").") +elseif provider != "FFTW" + error("Unrecognized JULIA_FFTW_PROVIDER \"$provider\".\n", + "To fix this, set ENV[\"JULIA_FFTW_PROVIDER\"] to \"FFTW\" or \"MKL\"\n", + "and rerun Pkg.build(\"FFTW\").") else include("build_fftw.jl") end diff --git a/deps/build_fftw.jl b/deps/build_fftw.jl index 921acce..05a73ef 100644 --- a/deps/build_fftw.jl +++ b/deps/build_fftw.jl @@ -1,121 +1,47 @@ -using Libdl -using BinDeps -using BinDeps: builddir, depsdir, libdir - -# Binaries is not a recognized provider on Linux >:/ -modified_defaults = false -if !in(BinDeps.Binaries, BinDeps.defaults) - pushfirst!(BinDeps.defaults, BinDeps.Binaries) - modified_defaults = true -end - -BinDeps.@setup - -const FFTW_VER = v"3.3.6-pl2" - -if Sys.iswindows() - const libfftw_name = "libfftw3" - const libfftwf_name = "libfftw3f" -else - const libfftw_name = "libfftw3_threads" - const libfftwf_name = "libfftw3f_threads" -end - -# Why can't everyone just agree on what to call this library... -function makealiases(lib) - major = string(FFTW_VER.major) - nover = replace(lib, major => "") - return String[ - nover, - join([lib, Libdl.dlext, major], "."), - join([nover, Libdl.dlext, major], "."), - lib * "-" * major, - nover * "-" * major, - ] -end - -libfftw = library_dependency(libfftw_name, aliases=makealiases(libfftw_name)) -libfftwf = library_dependency(libfftwf_name, aliases=makealiases(libfftwf_name)) - -const URL = "https://github.com/ararslan/fftw-builder/releases/download/v$FFTW_VER/libfftw-$FFTW_VER" - -# Mapping of Sys.MACHINE to (url, sha) for precompiled binaries from fftw-builder -const downloads = Dict( - "x86_64-pc-linux-gnu" => ("$URL-linux-x86_64.tar.gz", - "43a049496d47dd1919283a981d21078942d04b067edd75b61cc6aef538098b53"), - "i686-pc-linux-gnu" => ("$URL-linux-i686.tar.gz", - "0b6ec1440ea76f72ed6e5d105a4d634e195b484e847c521ac0812092069f0c74"), - "x86_64-apple-darwin" => ("$URL-osx-x86_64.tar.gz", - "193f20bba844fd2524f70e941aa5203b153bdcd321df2f20fc3a9d15b4aae50a"), - "x86_64-w64-mingw32" => ("$URL-win-x86_64.zip", - "4e9bd1022c5980869b06bb9d10767fd2578dfe47f9323e6f572d0918da8c8a07"), - "i686-w64-mingw32" => ("$URL-win-i686.zip", - "60a65fd689495629a1558858f3a52011f9ce28df8aa756f5b315b17dd8dd8843"), +using BinaryProvider # requires BinaryProvider 0.3.0 or later + +# Parse some basic command-line arguments +const verbose = "--verbose" in ARGS +const prefix = Prefix(get([a for a in ARGS if a != "--verbose"], 1, joinpath(@__DIR__, "usr"))) +products = [ + LibraryProduct(prefix, String["libfftw3"], :libfftw3), + LibraryProduct(prefix, String["libfftw3f"], :libfftw3f), +] + +# Download binaries from hosted location +bin_prefix = "https://github.com/JuliaMath/FFTWBuilder/releases/download/v3.3.8+1" + +# Listing of files generated by BinaryBuilder: +download_info = Dict( + Linux(:aarch64, :glibc) => ("$bin_prefix/FFTW.aarch64-linux-gnu.tar.gz", "4296ad9af20d4441fd809c6aaa3ee5fa36818b7a2eb3372da7d2ead454b4e570"), + Linux(:aarch64, :musl) => ("$bin_prefix/FFTW.aarch64-linux-musl.tar.gz", "ef6d4e56bd9e405ef2895a857ffbc07cb7abcf450040a2335b83a95f4a431392"), + Linux(:armv7l, :glibc, :eabihf) => ("$bin_prefix/FFTW.arm-linux-gnueabihf.tar.gz", "8f8c69a6eca468465734e1fd58801519cea0f7a8f9e08bba93e39315758f7a7c"), + Linux(:armv7l, :musl, :eabihf) => ("$bin_prefix/FFTW.arm-linux-musleabihf.tar.gz", "48d137fddab6888bdc59893d22728f081578ff0884954f0f6f5df51afff53ece"), + Linux(:i686, :glibc) => ("$bin_prefix/FFTW.i686-linux-gnu.tar.gz", "76d85d81a81752a0e08bc2eec51a568a6000928a550c37a181b51340452b1b5f"), + Linux(:i686, :musl) => ("$bin_prefix/FFTW.i686-linux-musl.tar.gz", "5ee42df3aa002e9511c3cc808f728429e4930bb24df8b461dc137bf49aa71b8f"), + Windows(:i686) => ("$bin_prefix/FFTW.i686-w64-mingw32.tar.gz", "28b96cb5d78c87d16d305a63a838c5027d319c0292f00c925e14f21c744535a8"), + Linux(:powerpc64le, :glibc) => ("$bin_prefix/FFTW.powerpc64le-linux-gnu.tar.gz", "53d305eebb3a152df093d637fe8a4d6288a2b7175bf91ab9242dad62e5e0853a"), + MacOS(:x86_64) => ("$bin_prefix/FFTW.x86_64-apple-darwin14.tar.gz", "7562aed6279ea965435c8a388be1494b9a18f7e00058d0fa260a711bffde1bd5"), + Linux(:x86_64, :glibc) => ("$bin_prefix/FFTW.x86_64-linux-gnu.tar.gz", "70dcc7ad2697121564d5d91da9f2544b0e68b026779a45063039a39cd5585711"), + Linux(:x86_64, :musl) => ("$bin_prefix/FFTW.x86_64-linux-musl.tar.gz", "4bf1c1e7489241c38788bc061f2a091fe72605f67e58411b2933313fa0923877"), + FreeBSD(:x86_64) => ("$bin_prefix/FFTW.x86_64-unknown-freebsd11.1.tar.gz", "ad70aca12821f6df1c67da74fc2f1b4fa009ac14d8570ff1f912876e731185af"), + Windows(:x86_64) => ("$bin_prefix/FFTW.x86_64-w64-mingw32.tar.gz", "6726bff25faeca8e29dfce8be5b0fb7da0a380faa9fdb5a5a6c98ea76d009b2f"), ) -const machine = Sys.isapple() ? "x86_64-apple-darwin" : Sys.MACHINE - -if haskey(downloads, machine) - url, sha = downloads[machine] - provides(Binaries, URI(url), [libfftw, libfftwf], SHA=sha, os=BinDeps.OSNAME, - unpacked_dir=joinpath("usr", "lib"), installed_libpath=libdir(libfftw)) - scratch = false -elseif Sys.KERNEL === :FreeBSD - provides(BSDPkg, "fftw3", [libfftw, libfftwf], os=:FreeBSD) - scratch = false -else - info("No precompiled binaries found for your system. Building from scratch...") - scratch = true -end - -general_config = ["--prefix=" * abspath(builddir(libfftw)), - "--libdir=" * abspath(libdir(libfftw)), - "--bindir=" * abspath(bindir(libfftw))] - -fftw_config = ["--enable-shared", "--disable-fortran", "--disable-mpi", "--enable-threads"] -fftw_enable_single = "--enable-single" - -if Sys.ARCH === :ppc - append!(fftw_config, ["--enable-altivec", "--enable-fma"]) -elseif Sys.ARCH === :x86_64 - append!(fftw_config, ["--enable-sse2", "--enable-fma"]) -end - -if Sys.iswindows() - append!(fftw_config, ["--with-our-malloc", "--with-combined-threads"]) - Sys.ARCH === :x86_64 || push!(fftw_config, "--with-incoming-stack-boundary=2") -end - -# Make it harder to build from scratch -if scratch - provides(Sources, URI("http://www.fftw.org/fftw-$FFTW_VER.tar.gz"), [libfftw, libfftwf]) - - provides(BuildProcess, (@build_steps begin - GetSources(libfftw) - CreateDirectory(builddir(libfftw)) - @build_steps begin - ChangeDirectory(builddir(libfftw)) - FileRule(joinpath(libdir(libfftw), libfftw_name * "." * Libdl.dlext), @build_steps begin - CreateDirectory(libdir(libfftw)) - `$(joinpath(srcdir(libfftw), "fftw-$FFTW_VER", "configure")) $general_config $fftw_config` - `$MAKE_CMD` - `$MAKE_CMD install` - end) - FileRule(joinpath(libdir(libfftw), libfftwf_name * "." * Libdl.dlext), @build_steps begin - `$(joinpath(srcdir(libfftw), "fftw-$FFTW_VER", "configure")) $general_config $fftw_config $fftw_enable_single` - `$MAKE_CMD` - `$MAKE_CMD install` - end) - end - end), [libfftw, libfftwf]) -end - -if Sys.iswindows() - BinDeps.@install Dict([:libfftw3 => :libfftw, :libfftw3f => :libfftwf]) -else - BinDeps.@install Dict([:libfftw3_threads => :libfftw, :libfftw3f_threads => :libfftwf]) -end - -if modified_defaults - popfirst!(BinDeps.defaults) -end +# Install unsatisfied or updated dependencies: +unsatisfied = any(!satisfied(p; verbose=verbose) for p in products) +if haskey(download_info, platform_key()) + url, tarball_hash = download_info[platform_key()] + if unsatisfied || !isinstalled(url, tarball_hash; prefix=prefix) + # Download and install binaries + install(url, tarball_hash; prefix=prefix, force=true, verbose=verbose) + end +elseif unsatisfied + # If we don't have a BinaryProvider-compatible .tar.gz to download, complain. + # Alternatively, you could attempt to install from a separate provider, + # build from source or something even more ambitious here. + error("Your platform $(triplet(platform_key())) is not supported by this package!") +end + +# Write out a deps.jl file that will contain mappings for our products +write_deps_file(joinpath(@__DIR__, "deps.jl"), products) diff --git a/src/FFTW.jl b/src/FFTW.jl index ac0c5cb..ccacb37 100644 --- a/src/FFTW.jl +++ b/src/FFTW.jl @@ -2,9 +2,8 @@ __precompile__() module FFTW -using Compat -using LinearAlgebra -using Reexport +using Compat, LinearAlgebra, Reexport +import Libdl @reexport using AbstractFFTs import AbstractFFTs: Plan, ScaledPlan, @@ -26,28 +25,18 @@ else end # MKL provides its own FFTW -fftw_vendor() = BLAS.vendor() === :mkl ? :mkl : :fftw - -if fftw_vendor() === :mkl - const libfftw_name = "libmkl_rt" - const libfftwf_name = "libmkl_rt" -elseif Sys.iswindows() - const libfftw_name = "libfftw3" - const libfftwf_name = "libfftw3f" -else - const libfftw_name = "libfftw3_threads" - const libfftwf_name = "libfftw3f_threads" -end +const fftw_vendor = occursin("libmkl_rt", libfftw3) ? :mkl : :fftw -# Threads must be initialized before any FFTW planning routine. +# If FFTW was built with threads, then they must be initialized before any FFTW planning routine. # -- This initializes FFTW's threads support (defaulting to 1 thread). # If this isn't called before the FFTW planner is created, then # FFTW's threads algorithms won't be registered or used at all. # (Previously, we called fftw_cleanup, but this invalidated existing # plans, causing Base Julia issue #19892.) function __init__() - stat = ccall((:fftw_init_threads, libfftw), Int32, ()) - statf = ccall((:fftwf_init_threads, libfftwf), Int32, ()) + check_deps() + stat = ccall((:fftw_init_threads, libfftw3), Int32, ()) + statf = ccall((:fftwf_init_threads, libfftw3f), Int32, ()) if stat == 0 || statf == 0 error("could not initialize FFTW threads") end diff --git a/src/fft.jl b/src/fft.jl index 2c6ea35..9e07685 100644 --- a/src/fft.jl +++ b/src/fft.jl @@ -56,7 +56,7 @@ function plan_r2r end ## FFT: Implement fft by calling fftw. const version = VersionNumber(split(unsafe_string(cglobal( - (:fftw_version,libfftw), UInt8)), ['-', ' '])[2]) + (:fftw_version,libfftw3), UInt8)), ['-', ' '])[2]) ## Direction of FFT @@ -141,39 +141,39 @@ alignment_of(A::FakeArray) = Int32(0) function export_wisdom(fname::AbstractString) f = ccall(:fopen, Ptr{Cvoid}, (Cstring,Cstring), fname, :w) systemerror("could not open wisdom file $fname for writing", f == C_NULL) - ccall((:fftw_export_wisdom_to_file,libfftw), Cvoid, (Ptr{Cvoid},), f) + ccall((:fftw_export_wisdom_to_file,libfftw3), Cvoid, (Ptr{Cvoid},), f) ccall(:fputs, Int32, (Ptr{UInt8},Ptr{Cvoid}), " "^256, f) # no NUL, hence no Cstring - ccall((:fftwf_export_wisdom_to_file,libfftwf), Cvoid, (Ptr{Cvoid},), f) + ccall((:fftwf_export_wisdom_to_file,libfftw3f), Cvoid, (Ptr{Cvoid},), f) ccall(:fclose, Cvoid, (Ptr{Cvoid},), f) end function import_wisdom(fname::AbstractString) f = ccall(:fopen, Ptr{Cvoid}, (Cstring,Cstring), fname, :r) systemerror("could not open wisdom file $fname for reading", f == C_NULL) - if ccall((:fftw_import_wisdom_from_file,libfftw),Int32,(Ptr{Cvoid},),f)==0|| - ccall((:fftwf_import_wisdom_from_file,libfftwf),Int32,(Ptr{Cvoid},),f)==0 + if ccall((:fftw_import_wisdom_from_file,libfftw3),Int32,(Ptr{Cvoid},),f)==0|| + ccall((:fftwf_import_wisdom_from_file,libfftw3f),Int32,(Ptr{Cvoid},),f)==0 error("failed to import wisdom from $fname") end ccall(:fclose, Cvoid, (Ptr{Cvoid},), f) end function import_system_wisdom() - if ccall((:fftw_import_system_wisdom,libfftw), Int32, ()) == 0 || - ccall((:fftwf_import_system_wisdom,libfftwf), Int32, ()) == 0 + if ccall((:fftw_import_system_wisdom,libfftw3), Int32, ()) == 0 || + ccall((:fftwf_import_system_wisdom,libfftw3f), Int32, ()) == 0 error("failed to import system wisdom") end end function forget_wisdom() - ccall((:fftw_forget_wisdom,libfftw), Cvoid, ()) - ccall((:fftwf_forget_wisdom,libfftwf), Cvoid, ()) + ccall((:fftw_forget_wisdom,libfftw3), Cvoid, ()) + ccall((:fftwf_forget_wisdom,libfftw3f), Cvoid, ()) end # Threads function set_num_threads(nthreads::Integer) - ccall((:fftw_plan_with_nthreads,libfftw), Cvoid, (Int32,), nthreads) - ccall((:fftwf_plan_with_nthreads,libfftwf), Cvoid, (Int32,), nthreads) + ccall((:fftw_plan_with_nthreads,libfftw3), Cvoid, (Int32,), nthreads) + ccall((:fftwf_plan_with_nthreads,libfftw3f), Cvoid, (Int32,), nthreads) end # pointer type for fftw_plan (opaque pointer) @@ -186,11 +186,11 @@ const PlanPtr = Ptr{fftw_plan_struct} const NO_TIMELIMIT = -1.0 # from fftw3.h function set_timelimit(precision::fftwTypeDouble,seconds) - ccall((:fftw_set_timelimit,libfftw), Cvoid, (Float64,), seconds) + ccall((:fftw_set_timelimit,libfftw3), Cvoid, (Float64,), seconds) end function set_timelimit(precision::fftwTypeSingle,seconds) - ccall((:fftwf_set_timelimit,libfftwf), Cvoid, (Float64,), seconds) + ccall((:fftwf_set_timelimit,libfftw3f), Cvoid, (Float64,), seconds) end # Array alignment mod 16: @@ -204,16 +204,16 @@ end # function will be documented in FFTW 3.3.4. -if libfftw_name == "libmkl_rt" +@static if fftw_vendor == :mkl alignment_of(A::StridedArray{<:fftwDouble}) = convert(Int32, convert(Int64, pointer(A)) % 16) alignment_of(A::StridedArray{<:fftwSingle}) = convert(Int32, convert(Int64, pointer(A)) % 16) else alignment_of(A::StridedArray{T}) where {T<:fftwDouble} = - ccall((:fftw_alignment_of, libfftw), Int32, (Ptr{T},), A) + ccall((:fftw_alignment_of, libfftw3), Int32, (Ptr{T},), A) alignment_of(A::StridedArray{T}) where {T<:fftwSingle} = - ccall((:fftwf_alignment_of, libfftwf), Int32, (Ptr{T},), A) + ccall((:fftwf_alignment_of, libfftw3f), Int32, (Ptr{T},), A) end # FFTWPlan (low-level) @@ -253,21 +253,21 @@ size(p::FFTWPlan) = p.sz unsafe_convert(::Type{PlanPtr}, p::FFTWPlan) = p.plan destroy_plan(plan::FFTWPlan{<:fftwDouble}) = - ccall((:fftw_destroy_plan,libfftw), Cvoid, (PlanPtr,), plan) + ccall((:fftw_destroy_plan,libfftw3), Cvoid, (PlanPtr,), plan) destroy_plan(plan::FFTWPlan{<:fftwSingle}) = - ccall((:fftwf_destroy_plan,libfftwf), Cvoid, (PlanPtr,), plan) + ccall((:fftwf_destroy_plan,libfftw3f), Cvoid, (PlanPtr,), plan) cost(plan::FFTWPlan{<:fftwDouble}) = - ccall((:fftw_cost,libfftw), Float64, (PlanPtr,), plan) + ccall((:fftw_cost,libfftw3), Float64, (PlanPtr,), plan) cost(plan::FFTWPlan{<:fftwSingle}) = - ccall((:fftwf_cost,libfftwf), Float64, (PlanPtr,), plan) + ccall((:fftwf_cost,libfftw3f), Float64, (PlanPtr,), plan) function arithmetic_ops(plan::FFTWPlan{<:fftwDouble}) # Change to individual Ref after we can allocate them on stack ref = Ref{NTuple{3,Float64}}() ptr = Ptr{Float64}(Base.unsafe_convert(Ptr{NTuple{3,Float64}}, ref)) - ccall((:fftw_flops,libfftw), Cvoid, + ccall((:fftw_flops,libfftw3), Cvoid, (PlanPtr,Ptr{Float64},Ptr{Float64},Ptr{Float64}), plan, ptr, ptr + 8, ptr + 16) (round(Int64, ref[][1]), round(Int64, ref[][2]), round(Int64, ref[][3])) @@ -276,7 +276,7 @@ function arithmetic_ops(plan::FFTWPlan{<:fftwSingle}) # Change to individual Ref after we can allocate them on stack ref = Ref{NTuple{3,Float64}}() ptr = Ptr{Float64}(Base.unsafe_convert(Ptr{NTuple{3,Float64}}, ref)) - ccall((:fftwf_flops,libfftwf), Cvoid, + ccall((:fftwf_flops,libfftw3f), Cvoid, (PlanPtr,Ptr{Float64},Ptr{Float64},Ptr{Float64}), plan, ptr, ptr + 8, ptr + 16) (round(Int64, ref[][1]), round(Int64, ref[][2]), round(Int64, ref[][3])) @@ -302,23 +302,30 @@ function showfftdims(io, sz::Dims, istride::Dims, T) end end -# The sprint_plan function was released in FFTW 3.3.4 -sprint_plan_(plan::FFTWPlan{<:fftwDouble}) = - ccall((:fftw_sprint_plan,libfftw), Ptr{UInt8}, (PlanPtr,), plan) -sprint_plan_(plan::FFTWPlan{<:fftwSingle}) = - ccall((:fftwf_sprint_plan,libfftwf), Ptr{UInt8}, (PlanPtr,), plan) -function sprint_plan(plan::FFTWPlan) - p = sprint_plan_(plan) - str = unsafe_string(p) - Libc.free(p) - return str +# The sprint_plan function was released in FFTW 3.3.4, but MKL versions +# claiming to be FFTW 3.3.4 still don't seem to have this function. +const has_sprint_plan = version >= v"3.3.4" && fftw_vendor == :fftw + +@static if has_sprint_plan + sprint_plan_(plan::FFTWPlan{<:fftwDouble}) = + ccall((:fftw_sprint_plan,libfftw3), Ptr{UInt8}, (PlanPtr,), plan) + sprint_plan_(plan::FFTWPlan{<:fftwSingle}) = + ccall((:fftwf_sprint_plan,libfftw3f), Ptr{UInt8}, (PlanPtr,), plan) + function sprint_plan(plan::FFTWPlan) + p = sprint_plan_(plan) + str = unsafe_string(p) + Libc.free(p) + return str + end +else + sprint_plan(plan::FFTWPlan) = "" end function show(io::IO, p::cFFTWPlan{T,K,inplace}) where {T,K,inplace} print(io, inplace ? "FFTW in-place " : "FFTW ", K < 0 ? "forward" : "backward", " plan for ") showfftdims(io, p.sz, p.istride, T) - version >= v"3.3.4" && print(io, "\n", sprint_plan(p)) + has_sprint_plan && print(io, "\n", sprint_plan(p)) end function show(io::IO, p::rFFTWPlan{T,K,inplace}) where {T,K,inplace} @@ -326,7 +333,7 @@ function show(io::IO, p::rFFTWPlan{T,K,inplace}) where {T,K,inplace} K < 0 ? "real-to-complex" : "complex-to-real", " plan for ") showfftdims(io, p.sz, p.istride, T) - version >= v"3.3.4" && print(io, "\n", sprint_plan(p)) + has_sprint_plan && print(io, "\n", sprint_plan(p)) end function show(io::IO, p::r2rFFTWPlan{T,K,inplace}) where {T,K,inplace} @@ -343,7 +350,7 @@ function show(io::IO, p::r2rFFTWPlan{T,K,inplace}) where {T,K,inplace} end print(io, " plan for ") showfftdims(io, p.sz, p.istride, T) - version >= v"3.3.4" && print(io, "\n", sprint_plan(p)) + has_sprint_plan && print(io, "\n", sprint_plan(p)) end # Check whether a FFTWPlan is applicable to a given input array, and @@ -381,49 +388,49 @@ colmajorstrides(sz) = isempty(sz) ? () : (1,cumprod(Int[sz[1:end-1]...])...) # Execute unsafe_execute!(plan::FFTWPlan{<:fftwDouble}) = - ccall((:fftw_execute,libfftw), Cvoid, (PlanPtr,), plan) + ccall((:fftw_execute,libfftw3), Cvoid, (PlanPtr,), plan) unsafe_execute!(plan::FFTWPlan{<:fftwSingle}) = - ccall((:fftwf_execute,libfftwf), Cvoid, (PlanPtr,), plan) + ccall((:fftwf_execute,libfftw3f), Cvoid, (PlanPtr,), plan) unsafe_execute!(plan::cFFTWPlan{T}, X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwDouble} = - ccall((:fftw_execute_dft,libfftw), Cvoid, + ccall((:fftw_execute_dft,libfftw3), Cvoid, (PlanPtr,Ptr{T},Ptr{T}), plan, X, Y) unsafe_execute!(plan::cFFTWPlan{T}, X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwSingle} = - ccall((:fftwf_execute_dft,libfftwf), Cvoid, + ccall((:fftwf_execute_dft,libfftw3f), Cvoid, (PlanPtr,Ptr{T},Ptr{T}), plan, X, Y) unsafe_execute!(plan::rFFTWPlan{Float64,FORWARD}, X::StridedArray{Float64}, Y::StridedArray{Complex{Float64}}) = - ccall((:fftw_execute_dft_r2c,libfftw), Cvoid, + ccall((:fftw_execute_dft_r2c,libfftw3), Cvoid, (PlanPtr,Ptr{Float64},Ptr{Complex{Float64}}), plan, X, Y) unsafe_execute!(plan::rFFTWPlan{Float32,FORWARD}, X::StridedArray{Float32}, Y::StridedArray{Complex{Float32}}) = - ccall((:fftwf_execute_dft_r2c,libfftwf), Cvoid, + ccall((:fftwf_execute_dft_r2c,libfftw3f), Cvoid, (PlanPtr,Ptr{Float32},Ptr{Complex{Float32}}), plan, X, Y) unsafe_execute!(plan::rFFTWPlan{Complex{Float64},BACKWARD}, X::StridedArray{Complex{Float64}}, Y::StridedArray{Float64}) = - ccall((:fftw_execute_dft_c2r,libfftw), Cvoid, + ccall((:fftw_execute_dft_c2r,libfftw3), Cvoid, (PlanPtr,Ptr{Complex{Float64}},Ptr{Float64}), plan, X, Y) unsafe_execute!(plan::rFFTWPlan{Complex{Float32},BACKWARD}, X::StridedArray{Complex{Float32}}, Y::StridedArray{Float32}) = - ccall((:fftwf_execute_dft_c2r,libfftwf), Cvoid, + ccall((:fftwf_execute_dft_c2r,libfftw3f), Cvoid, (PlanPtr,Ptr{Complex{Float32}},Ptr{Float32}), plan, X, Y) unsafe_execute!(plan::r2rFFTWPlan{T}, X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwDouble} = - ccall((:fftw_execute_r2r,libfftw), Cvoid, + ccall((:fftw_execute_r2r,libfftw3), Cvoid, (PlanPtr,Ptr{T},Ptr{T}), plan, X, Y) unsafe_execute!(plan::r2rFFTWPlan{T}, X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwSingle} = - ccall((:fftwf_execute_r2r,libfftwf), Cvoid, + ccall((:fftwf_execute_r2r,libfftw3f), Cvoid, (PlanPtr,Ptr{T},Ptr{T}), plan, X, Y) # NOTE ON GC (garbage collection): @@ -480,8 +487,8 @@ end # low-level FFTWPlan creation (for internal use in FFTW module) -for (Tr,Tc,fftw,lib) in ((:Float64,:(Complex{Float64}),"fftw",libfftw), - (:Float32,:(Complex{Float32}),"fftwf",libfftwf)) +for (Tr,Tc,fftw,lib) in ((:Float64,:(Complex{Float64}),"fftw",libfftw3), + (:Float32,:(Complex{Float32}),"fftwf",libfftw3f)) @eval function cFFTWPlan{$Tc,K,inplace,N}(X::StridedArray{$Tc,N}, Y::StridedArray{$Tc,N}, region, flags::Integer, timelimit::Real) where {K,inplace,N} diff --git a/test/runtests.jl b/test/runtests.jl index 106f1c8..938a3b8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -14,7 +14,7 @@ let a = randn(10^5,1), p1 = plan_rfft(a, flags=FFTW.ESTIMATE) @test p1*a ≈ p2*a # make sure threads are actually being used for p2 # (tests #21163). - if FFTW.version >= v"3.3.4" + if FFTW.has_sprint_plan @test !occursin("dft-thr", string(p1)) @test occursin("dft-thr", string(p2)) end @@ -145,7 +145,7 @@ for (f,fi,pf,pfi) in ((fft,ifft,plan_fft,plan_ifft), # The following capabilities are FFTW only. # They are not available in MKL, and hence do not test them. - if fftw_vendor() != :mkl + if fftw_vendor != :mkl ifft3_fft3_m3d = fi(f(m3d)) fftd3_m3d = f(m3d,3) @@ -182,7 +182,7 @@ for (f,fi,pf,pfi) in ((fft,ifft,plan_fft,plan_ifft), @test pfft!d3_m3d[i] ≈ true_fftd3_m3d[i] @test pifft!d3_fftd3_m3d[i] ≈ m3d[i] end - end # if fftw_vendor() != :mkl + end # if fftw_vendor != :mkl end @@ -260,7 +260,7 @@ for i = 1:length(m4) @test pirfftn_rfftn_m4_prealloc[i] ≈ m4[i] end -if fftw_vendor() != :mkl +if fftw_vendor != :mkl rfftn_m3d = rfft(m3d) rfftd3_m3d = rfft(m3d,3) @test size(rfftd3_m3d) == size(true_fftd3_m3d) @@ -401,7 +401,7 @@ a16 = convert(Vector{Float16}, a) # Discrete cosine transform (DCT) tests -if fftw_vendor() != :mkl +if fftw_vendor != :mkl a = rand(8,11) + im*rand(8,11) @test norm(idct(dct(a)) - a) < 1e-8 @@ -484,7 +484,7 @@ if fftw_vendor() != :mkl @test sXdct![i] ≈ true_Xdct[i] @test psXdct![i] ≈ true_Xdct[i] end -end # fftw_vendor() != :mkl +end # fftw_vendor != :mkl # test UNALIGNED flag let A = rand(Float32, 35), Ac = rand(Complex{Float32}, 35)