-
Notifications
You must be signed in to change notification settings - Fork 49
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
WIP: enable reusing fft plans #271
base: master
Are you sure you want to change the base?
Changes from all commits
25dbbbe
a948fae
6ef477e
2988c21
270e59f
9a290c9
7ff1a55
9db8caf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -826,7 +826,7 @@ function _imfilter_fft!(r::AbstractCPU{FFT}, | |
for I in CartesianIndices(axes(kern)) | ||
krn[I] = kern[I] | ||
end | ||
Af = filtfft(A, krn) | ||
Af = filtfft(A, krn, r.settings.plan1, r.settings.plan2, r.settings.plan3) | ||
if map(first, axes(out)) == map(first, axes(Af)) | ||
R = CartesianIndices(axes(out)) | ||
copyto!(out, R, Af, R) | ||
|
@@ -837,13 +837,67 @@ function _imfilter_fft!(r::AbstractCPU{FFT}, | |
src = view(FFTView(Af), axes(dest)...) | ||
copyto!(dest, src) | ||
end | ||
out | ||
return out | ||
end | ||
|
||
function buffered_planned_rfft(a::AbstractArray{T}) where {T} | ||
buf = RealFFTs.RCpair{T}(undef, size(a)) | ||
plan = RealFFTs.plan_rfft!(buf; flags=FFTW.MEASURE) | ||
return function (arr::AbstractArray{T}) where {T} | ||
copy!(buf, OffsetArrays.no_offset_view(arr)) | ||
return plan(buf) | ||
end | ||
end | ||
function buffered_planned_irfft(a::AbstractArray{T}) where {T} | ||
buf = RealFFTs.RCpair{T}(undef, size(a)) | ||
plan = RealFFTs.plan_irfft!(buf; flags=FFTW.MEASURE) | ||
return function (arr::AbstractArray{T}) where {T} | ||
copy!(buf, OffsetArrays.no_offset_view(arr)) | ||
return plan(buf) | ||
end | ||
end | ||
|
||
function planned_fft(A::AbstractArray{T,N}, | ||
kernel::ProcessedKernel, | ||
border::BorderSpecAny=Pad(:replicate) | ||
) where {T<:AbstractFloat,N} | ||
bord = border(kernel, A, Algorithm.FFT()) | ||
_A = padarray(T, A, bord) | ||
bfp1 = buffered_planned_rfft(_A) | ||
kern = samedims(_A, kernelconv(kernel...)) | ||
krn = FFTView(zeros(eltype(kern), map(length, axes(_A)))) | ||
bfp2 = buffered_planned_rfft(krn) | ||
bfp3 = buffered_planned_irfft(_A) | ||
return Algorithm.FFT(bfp1, bfp2, bfp3) | ||
end | ||
planned_fft(A::AbstractArray, kernel, border::AbstractString) = planned_fft(A, kernel, borderinstance(border)) | ||
planned_fft(A::AbstractArray, kernel::Union{ArrayLike,Laplacian}, border::BorderSpecAny) = planned_fft(A, factorkernel(kernel), border) | ||
|
||
function filtfft(A, krn, planned_rfft1::Function, planned_rfft2::Function, planned_irfft::Function) | ||
B = complex(planned_rfft1(A)) | ||
B .*= conj!(complex(planned_rfft2(krn))) | ||
return real(planned_irfft(complex(B))) | ||
end | ||
# TODO: this Colorant method does not work. See TODO below | ||
function filtfft(A::AbstractArray{C}, krn, planned_rfft1::Function, planned_rfft2::Function, planned_irfft::Function) where {C<:Colorant} | ||
Av, dims = channelview_dims(A) | ||
kernrs = kreshape(C, krn) | ||
B = complex(planned_rfft1(Av, dims)) # TODO: dims is not supported by planned_rfft1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added this comment to the TODO. I think I'd prefer to fix this in a follow on PR, if that sounds ok |
||
# Quoting Tim Holy in https://github.com/JuliaImages/ImageFiltering.jl/pull/271/files#r1559210348 | ||
# I don't think dims can be a point of flexibility: these plans are specific to the | ||
# memory layout of the array. (The planning explores various implementations and picks | ||
# the fastest discovered; performance is strongly dependent on memory layout, so the | ||
# choice for one layout may not be the same as another.) You'd have to create a plan | ||
# specifically to the colorant array-type. | ||
B .*= conj!(complex(planned_rfft2(kernrs))) | ||
Avf = real(planned_irfft(complex(B))) | ||
return colorview(base_colorant_type(C){eltype(Avf)}, Avf) | ||
end | ||
filtfft(A, krn, ::Nothing, ::Nothing, ::Nothing) = filtfft(A, krn) | ||
function filtfft(A, krn) | ||
B = rfft(A) | ||
B .*= conj!(rfft(krn)) | ||
irfft(B, length(axes(A, 1))) | ||
return irfft(B, length(axes(A, 1))) | ||
end | ||
function filtfft(A::AbstractArray{C}, krn) where {C<:Colorant} | ||
Av, dims = channelview_dims(A) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No test coverage here and below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I hadn't noticed this. Sadly it turns out the new functionality isn't passing yet..