# Poor performance of the cis() function

**URL:** <https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402>\
**Category:** General Usage\
**Tags:** performance\
**Created:** [April 27, 2017, 12:18pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402 "2017-04-27T12:18:20Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![111](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/111/32/33971_2.png) [@111](https://discourse.julialang.org/u/111)\
**Post date:** [April 27, 2017, 12:18pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/1 "2017-04-27T12:18:20Z")

</div>

I wrote a program with Julia, but the performance is disappointing.

The program is constructed with some functions, and global variables are prevented, arrays are well preallocated before used, the fft operation is accelerated by setting FFTW.set\_num\_threads(Sys.CPU\_CORES).

No red words are shown when profiling it with @code\_warntype. When I use the @profile macro to find out the bottleneck of the code, I find all the most-time-consuming lines share a common word: **cis**!

Below are these lines:

```
for j in eachindex(u)
    prop_e[j] = cis( -ele * (xplusy[j] * dt/2.0) ) * prop_x[j] # 2209
end
...

for j2 in 1:ngrid, j1 in 1:ngrid
    uo[j1+Δn, j2+Δn] = u[j1, j2] * splitter[j1, j2] * cis(A[i]*xplusy[j1, j2]) ## 2462
end
...
for j2 in 1:ngrid2, j1 in 1:ngrid2
    uo[j1, j2] *= cis( -dt * (pp[j1] + pp[j2]) ) # 38049
end

```

the number at the end of each line is the corresponding result of Profile.print() for this line. Note that the total number is 50454.  
When I implement the program with Fortran, these lines never much time, but never so much. I wonder if there is anything wrong with my Julia version.

---

<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:** [April 27, 2017, 2:07pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/2 "2017-04-27T14:07:45Z")

</div>

`cis` is faster than `exp(im * ...)`, but not particularly optimized, it simply calls `Complex(cos(x), sin(x))`. This function should be a bit faster:

```julia
const A = Ref{Cdouble}()
const B = Ref{Cdouble}()
function my_cis(x::Real)
    ccall((:sincos, Base.Math.libm), Void, (Cdouble, Ptr{Cdouble}, Ptr{Cdouble}), x, A, B)
    return Complex(B[], A[])
end

```

Some benchmarks:

```julia
julia> using BenchmarkTools

julia> g = collect(linspace(-100, 100, 1000000));

julia> @benchmark cis.($g)
BenchmarkTools.Trial: 
  memory estimate: 15.26 MiB
  allocs estimate: 2
  --------------
  minimum time: 27.409 ms (0.00% GC)
  median time: 30.013 ms (0.59% GC)
  mean time: 30.225 ms (2.78% GC)
  maximum time: 87.457 ms (64.57% GC)
  --------------
  samples: 166
  evals/sample: 1

julia> @benchmark my_cis.($g)
BenchmarkTools.Trial: 
  memory estimate: 15.26 MiB
  allocs estimate: 2
  --------------
  minimum time: 19.548 ms (0.00% GC)
  median time: 21.421 ms (0.00% GC)
  mean time: 21.835 ms (3.11% GC)
  maximum time: 79.516 ms (70.58% GC)
  --------------
  samples: 229
  evals/sample: 1

```

BTW, `FFTW.set_num_threads(Sys.CPU_CORES)` might not be a good idea, you can run into hyper-threading penalties.

If you want more specific advices, you probably need to provide a more complete example (not the whole program, but just a minimal working code reproducing your issue).

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [April 27, 2017, 3:08pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/3 "2017-04-27T15:08:46Z")

</div>

See also [https://github.com/JuliaLang/julia/pull/21589](https://github.com/JuliaLang/julia/pull/21589) or the original fastmath only `sincos` implementation [https://github.com/nacs-lab/yyc-data/blob/f717b873d8dece11703b90b8c1c03552368cf359/lib/NaCsCalc/src/utils.jl#L115-L141](https://github.com/nacs-lab/yyc-data/blob/f717b873d8dece11703b90b8c1c03552368cf359/lib/NaCsCalc/src/utils.jl#L115-L141)

---

<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:** [April 27, 2017, 4:53pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/4 "2017-04-27T16:53:57Z")

</div>

Nice. Just to understand: what’s the problem with directly ccalling sincos? `Ref` is already used in `modf`, for example.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [April 27, 2017, 5:05pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/5 "2017-04-27T17:05:03Z")

</div>

It’ll allocate memory. As mentioned in the PR, it’ll not be necessary once we can stack allocate those.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [April 27, 2017, 5:06pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/6 "2017-04-27T17:06:26Z")

</div>

And the use of `Ref` in `modf` is not thread safe.

---

<div class="post-metadata">

**Author:** ![111](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/111/32/33971_2.png) [@111](https://discourse.julialang.org/u/111)\
**Post date:** [April 28, 2017, 2:25am UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/7 "2017-04-28T02:25:47Z")

</div>

```
for i in 1:nt
   step_evolution_real!(u, p_fft!, prop_x, prop_p, ele[i], xplusy, prop_e)

   uo .= 0.0
   for j2 in eachindex(p), j1 in eachindex(p)
      uo[j1+Δn, j2+Δn] = u[j1, j2] * splitter[j1, j2] * cis(A[i]*xplusy[j1, j2])
   end
   for j in eachindex(u)
      u[j] *= 1 - splitter[j]
   end
   p_fft2! * uo
   for j in eachindex(pp)
     pp[j] = ( p2[j]^2 /2.0 ) * (nt-i) + p2[j]*sum(@view A[i:nt]) + um(@viewA²[i:nt])/2.0
   end
   for (j2, pp2) in enumerate(pp), (j1, pp1) in enumerate(pp)
      uo[j1, j2] *= cis( -dt * (pp1 + pp2) )
   end
   for j in eachindex(up)
      up[j] += uo[j]
   end
end

```

where the function step\_evolution\_real! is

```
function step_evolution_real!(u::Array{Complex128, 2},
p_fft!::Base.DFT.FFTW.cFFTWPlan{Complex128, -1, true, 2},
prop_x::Array{Complex128, 2}, prop_p::Array{Complex128, 2},
ele::Float64, xplusy::Array{Float64, 2},
prop_e::Array{Complex128, 2})
for j in eachindex(u)
   prop_e[j] = cis( -ele * (xplusy[j] * dt/2.0) ) * prop_x[j]
end
for j in eachindex(u)
   u[j] *= prop_e[j]
end
p_fft! * u
for j in eachindex(u)
   u[j] *= prop_p[j]
end
p_fft! \ u
for j in eachindex(u)
   u[j] *= prop_e[j]
end
nothing
end

```

---

<div class="post-metadata">

**Author:** ![Ralph\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ralph_smith/32/10344_2.png) [@Ralph\_Smith](https://discourse.julialang.org/u/Ralph_Smith)\
**Post date:** [April 28, 2017, 1:44pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/8 "2017-04-28T13:44:14Z")

</div>

As other posts show, `cis()` is translated to a scalar function call. I suggest rewriting the expensive loops to use vector math library calls (via VML.jl, Yeppp.jl, etc.). The extra trouble with temporary arrays is often worthwhile in cases like this.

Many Fortran compilers automatically use SIMD vector math libraries for cases like this. There is ongoing work to add such facility to LLVM, so eventually it should work for Julia too.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 28, 2017, 2:54pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/9 "2017-04-28T14:54:29Z")

</div>

Take a look at [this](https://discourse.julialang.org/t/why-is-this-julia-code-considerably-slower-than-matlab/2365) thread, where there is a similar discussion, and with examples of using a vector library (AppleAccelerate in that case) to speed up cis.

---

<div class="post-metadata">

**Author:** ![111](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/111/32/33971_2.png) [@111](https://discourse.julialang.org/u/111)\
**Post date:** [May 2, 2017, 1:57pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/10 "2017-05-02T13:57:26Z")

</div>

The VML.jl and Yeppp.jl are both sometimes helpful, but not in my condition. I need the exponential function for complex numbers. As I know these packages do not support complex numbers now.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [May 2, 2017, 2:33pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/11 "2017-05-02T14:33:50Z")

</div>

But `exp(z) = e^real(z) * (cos(imag(z)) + i * sin(imag(z)))`

---

<div class="post-metadata">

**Author:** ![111](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/111/32/33971_2.png) [@111](https://discourse.julialang.org/u/111)\
**Post date:** [May 3, 2017, 10:36am UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/12 "2017-05-03T10:36:26Z")

</div>

I don’t think of rewritting the **cis** function so complexly as a good solution, It seems to be even slower.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 3, 2017, 1:34pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/13 "2017-05-03T13:34:51Z")

</div>

Do you need it for complex numbers, or for imaginary numbers?

It may not help you, but AppleAccelerate.jl has both an optimized `cis` and `cis!` function which will work for imaginary numbers (by than I mean that you input `imag(z)`).

---

<div class="post-metadata">

**Author:** ![111](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/111/32/33971_2.png) [@111](https://discourse.julialang.org/u/111)\
**Post date:** [May 3, 2017, 2:06pm UTC](https://discourse.julialang.org/t/poor-performance-of-the-cis-function/3402/14 "2017-05-03T14:06:34Z")

</div>

I need the cis(x::Float64) function. AppleAccelerate.jl is a good package, but I am a windows user.
