I was rewriting some Matlab code into Julia, and I noticed that one function which used array broadcasting operations ran several times slower on Julia. I though this was really strange and I made a simple test function to test broadcasting operations in a few different ways and print the elapsed times. So, the test function is the following:
function test_broadcast(M::Int, N::Int, niter::Int=1000) X = randn(M); # Case A - simple broadcast A = zeros(ComplexF64, M, N) @time begin for ii = 1:niter A .+= exp.(im*X) end end # Case B - broadcast with map B = zeros(ComplexF64, M, N) @time begin for ii = 1:niter B .+= map(x -> exp(x), im*X) end end # Case C - broadcast using the broadcast! function C = zeros(ComplexF64, M, N) @time begin for ii = 1:niter broadcast!(+, C, C, exp.(im*X)) end end # Case D - broadcast using auxiliary variable D = zeros(ComplexF64, M, N) @time begin for ii = 1:niter Daux = exp.(im*X) D .+= Daux end end if !all((A .== B) .& (A .== C) .& (A .== D)) throw(ErrorException("Results mismatch")) end end
when executing this code using for
M = 10000 and
N = 10, I get the following results
julia> test_broadcast(10000, 10) 1.826595 seconds (2.00 k allocations: 152.664 MiB, 0.13% gc time) 0.275579 seconds (5.00 k allocations: 305.344 MiB, 1.73% gc time) 0.268911 seconds (4.00 k allocations: 305.328 MiB, 1.74% gc time) 0.269613 seconds (4.00 k allocations: 305.328 MiB, 1.77% gc time)
So in this example the case A is roughly 7 times slower than all the other cases.
This code is really simple, I don’t know if I am missing anything. According to the documentation the case A should be equivalent to using the broadcast function. I tried this with Julia versions 1.1, 1.2, and 1.3-rc3, and the results are similar. To me this seems like a bug. I have searched open issues in github and there is this bug https://github.com/JuliaLang/julia/issues/28126 where it seems that there is a problem with broadcasting when using many arrays of the same size, but in my example I only have one array, so it seems that this is a different problem.
This is my output of versioninfo:
julia> versioninfo() Julia Version 1.2.0 Commit c6da87ff4b (2019-08-20 00:03 UTC) Platform Info: OS: Linux (x86_64-pc-linux-gnu) CPU: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz WORD_SIZE: 64 LIBM: libopenlibm LLVM: libLLVM-6.0.1 (ORCJIT, skylake) Environment: JULIA_EDITOR = "/usr/share/code/code"
Any idea of why the case A is much worse?