# Repeated allocations for fft in pseudospectral code

**URL:** <https://discourse.julialang.org/t/repeated-allocations-for-fft-in-pseudospectral-code/130472>\
**Category:** Performance\
**Tags:** fftw, fft\
**Created:** [July 4, 2025, 4:29pm UTC](https://discourse.julialang.org/t/repeated-allocations-for-fft-in-pseudospectral-code/130472 "2025-07-04T16:29:38Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![gideonsimpson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gideonsimpson/32/1928_2.png) [@gideonsimpson](https://discourse.julialang.org/u/gideonsimpson)\
**Post date:** [July 4, 2025, 4:29pm UTC](https://discourse.julialang.org/t/repeated-allocations-for-fft-in-pseudospectral-code/130472/1 "2025-07-04T16:29:39Z")

</div>

I’m trying to tune a pseudospectral PDE code which has calls to `fft` and `ifft` at every iteration. I was wondering if there was some way to reduce the repeated memory allocations (assuming this improves performance). By this I mean that if I run the code:

```julia
using FFTW    
using BenchmarkTools

function apply_n_fft(u, n)
    uhat = complex.(similar(u));
    for _ in 1:n
        uhat .= fft(u);
    end
end

u = randn(32);
@btime apply_n_fft(u, 5);
@btime apply_n_fft(u, 50);

```

I get:

```julia
  6.433 μs (49 allocations: 7.83 KiB)
  68.084 μs (454 allocations: 70.41 KiB)

```

That the time went up by a factor of 10 is not so surprising; it’s the memory allocations that surprise me.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [July 4, 2025, 4:37pm UTC](https://discourse.julialang.org/t/repeated-allocations-for-fft-in-pseudospectral-code/130472/2 "2025-07-04T16:37:44Z")

</div>

Use a plan:

```julia-repl
julia> using FFTW, LinearAlgebra, BenchmarkTools

julia> u = randn(32);

julia> function apply_n_fft(u, n)
           uhat = complex.(similar(u));
           for _ in 1:n
               uhat .= fft(u);
           end
       end
apply_n_fft (generic function with 1 method)

julia> @btime apply_n_fft($(u), 5);
  7.727 μs (49 allocations: 7.83 KiB)

julia> @btime apply_n_fft($(u), 50);
  81.314 μs (454 allocations: 70.41 KiB)

julia> function apply_n_fft_plan(u, n)
           uc = complex(u)
           uhat = similar(uc);
           plan = plan_fft(uc)
           for _ in 1:n
               mul!(uhat, plan, uc)
           end
       end
apply_n_fft_plan (generic function with 1 method)

julia> @btime apply_n_fft_plan($(u), 5);
  1.713 μs (8 allocations: 1.34 KiB)

julia> @btime apply_n_fft_plan($(u), 50);
  2.932 μs (8 allocations: 1.34 KiB)

julia> @btime apply_n_fft_plan($(u), 500);
  15.597 μs (8 allocations: 1.34 KiB)

```

Without a precomputed plan, `fft` internally needs to (a) re-compute the same plan all over again which is also a _very_ time-consuming task which you don’t really want to repeat, (b) convert the input array to complex, and (c) allocate the output array, every single time. With the pre-computed plan, and having the input array already as complex numbers, lets you save all these repeated allocations, and the `mul!` would be entirely in-place, with the number of total allocations not depending on `n`.
