# Scaled FFT implementation seems to only use one thread despite setting no. of threads to 8

**URL:** <https://discourse.julialang.org/t/scaled-fft-implementation-seems-to-only-use-one-thread-despite-setting-no-of-threads-to-8/89396>\
**Category:** New to Julia\
**Tags:** fftw, multithreading\
**Created:** [October 27, 2022, 7:32pm UTC](https://discourse.julialang.org/t/scaled-fft-implementation-seems-to-only-use-one-thread-despite-setting-no-of-threads-to-8/89396 "2022-10-27T19:32:23Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Thaegy](https://avatars.discourse-cdn.com/v4/letter/t/7c8e57/32.png) [@Thaegy](https://discourse.julialang.org/u/Thaegy)\
**Post date:** [October 27, 2022, 7:32pm UTC](https://discourse.julialang.org/t/scaled-fft-implementation-seems-to-only-use-one-thread-despite-setting-no-of-threads-to-8/89396/1 "2022-10-27T19:32:23Z")

</div>

Hi there,

I have been trying to implement a form of the scaled FFT for use in optical propagation. The code was also rewritten in MATLAB to act as a comparison. My Julia implementation seems much slower than what I was expecting. MATLAB for reference takes around 0.38 s compared to ~0.95 s in Julia to run for identical parameters used in the Julia script (MATLAB cpu usage is significantly higher throughout). I have used the built-in profiler to try and analyse the situation and it seems to indicate that Julia is only using 1 thread despite me setting the environment variable in vscode to use 8 threads. I have also tried running in a standalone instance of Julia where I have set the number of threads to 8 before launching (-t 8). Does anyone have any insight into the possible slowdown?

If all is working with the multithreading then does anyone have any ideas as to why my code is noticeably slower in Julia? Am I missing an obvious trick that is causing wild inefficiencies in Julia?

Thanks in advance for any help!

```julia
using FFTW
using GridCreation
using IJulia
using LazyGrids
using ProfileView
# notebook()

N = 1024;
M = 1024;
alpha = 1.0;
beta = 1.0;

dx = 0.1; # Sampling unit for function 
dy = 0.1;

Y_array, X_array = ndgrid(-N/2 : N/2 -1,-M/2 : M/2 -1);

typX = typeof(X_array);
typY = typeof(Y_array);

f = @. cis(pi * (dx*X_array + dy*Y_array));

function SFFT2(f::Array{ComplexF64}, X_array::typX, Y_array::typY, alpha::Float64, beta::Float64, M::Int64, N::Int64)
    function exp_fact(kernel::Float64, array, A::Int64,shift)
        @.(cis(kernel * (array - 2.0*A*shift)^2 /A))
    end
   
    exp_factor_n = exp_fact(pi*alpha,X_array,N,0);
    exp_factor_m = exp_fact(pi*beta,Y_array,M,0);
    exp_factor_n_shift = exp_fact(pi*alpha,X_array,N,1);
    exp_factor_m_shift = exp_fact(pi*beta,Y_array,M,1);

    exp_factor = 1.0 ./ (exp_factor_n .* exp_factor_m);
    
    g1_bar_pad = Matrix{ComplexF64}(undef,nextpow(2,N+M-1),nextpow(2,N+M-1));
    g2_bar_pad = copy(g1_bar_pad);
    g1_bar_pad[1:N,1:M] = @.(f * cis(pi*(alpha*X_array + beta*Y_array)) * exp_factor);
    
    g2_bar_pad[1:N,1:M] = 1.0./exp_factor; # top left chunk
    g2_bar_pad[N+1:2*N,1:M] = exp_factor_n_shift .* exp_factor_m; # bottom left chunk
    g2_bar_pad[1:N,M+1:2*M] = exp_factor_m_shift .* exp_factor_n; # top right chunk
    g2_bar_pad[N+1:2*N,M+1:2*M] = exp_factor_n_shift .* exp_factor_m_shift; # bottom right chunk

    conv_g1g2 = ifft(fft(g1_bar_pad) .* fft(g2_bar_pad))[1:N,1:M];
    @.(cis(pi*(alpha*(X_array - 0.5*N) + beta*(Y_array - 0.5*M))) * exp_factor * conv_g1g2)
end

@profview SFFT(f, X_array, Y_array, alpha, beta, M, N)

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 27, 2022, 7:35pm UTC](https://discourse.julialang.org/t/scaled-fft-implementation-seems-to-only-use-one-thread-despite-setting-no-of-threads-to-8/89396/2 "2022-10-27T19:35:50Z")

</div>

> [@Thaegy](#):
>
> Am I missing an obvious trick that is causing wild inefficiencies in Julia?

If you care about efficiency, you should use `plan_fft` to precompute a plan and re-use it, rather than calling `fft` repeatedly. (And ideally pass `flags=FFTW.MEASURE` or `flags=FFTW.PATIENT`.) This is _the_ key to using FFTW effectively, as described in the [FFTW FAQ](https://www.fftw.org/faq/section3.html#slow).

(Matlab precomputes plans for a set of common sizes IIRC.)

There is also no need to use `nextpow(2, …)`. FFTW is fast as long the sizes are composites of small factors 2,3,5,7. In particular, you can use `nextprod([2,3,5], n)` or `nextprod([2,3,5,7], n)` as discussed in another thread: [How to set the length of fft](https://discourse.julialang.org/t/how-to-set-the-length-of-fft/38885) … but it is better to set your length to be such a number to begin with rather than padding (which changes the transform, not to mention incurring copies).

---

<div class="post-metadata">

**Author:** ![Thaegy](https://avatars.discourse-cdn.com/v4/letter/t/7c8e57/32.png) [@Thaegy](https://discourse.julialang.org/u/Thaegy)\
**Post date:** [October 27, 2022, 8:06pm UTC](https://discourse.julialang.org/t/scaled-fft-implementation-seems-to-only-use-one-thread-despite-setting-no-of-threads-to-8/89396/3 "2022-10-27T20:06:33Z")

</div>

Great thank you for the suggestions I’ll implement them. I’ll also post the profiler breakdown.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/8/8/887b2c7cd11632924a224f85a502f69087915337.png)
