# Possible inefficiency in randn!

**URL:** <https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732>\
**Category:** Performance\
**Tags:** benchmark\
**Created:** [April 4, 2019, 4:19am UTC](https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732 "2019-04-04T04:19:25Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [April 4, 2019, 4:19am UTC](https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732/1 "2019-04-04T04:19:25Z")

</div>

The following two functions seem to do exactly the same thing, but the built-in version (`randn!`) is some 60% slower. Am I missing something or could `randn!` be implemented more efficiently?

```julia
using Random
broadcast_randn(x) = (x .= randn.())
inplace_randn(x) = randn!(x)

x = zeros(10_000)
@btime broadcast_randn($x)
  41.680 μs (0 allocations: 0 bytes)
@btime inplace_randn($x)
  68.003 μs (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [April 4, 2019, 5:50am UTC](https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732/2 "2019-04-04T05:50:05Z")

</div>

Looking at the output of `@code_llvm`, it seems that the broadcasted version takes advantage of SIMD instructions. The [base implementation](https://github.com/JuliaLang/julia/blob/ce17e0529e240f6afbf793002158a7d865fd58ef/stdlib/Random/src/normal.jl#L171) of the in-place version is not too complicated:

```julia
function $randfun!(rng::AbstractRNG, A::AbstractArray{T}) where T
    for i in eachindex(A)
        @inbounds A[i] = $randfun(rng, T)
    end
    A
end

```

By including a `@simd` annotation, I recover the same performance as the broadcasted version:

```julia
function myrandn!(x)
   @inbounds @simd for i in eachindex(x)
       x[i] = randn()
   end
   x
end

```

However, `@simd` may not play well with the random number generator (are there memory dependencies based on the state of the RNG?), but the specifics are beyond me.

---

<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:** [April 4, 2019, 6:06am UTC](https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732/3 "2019-04-04T06:06:41Z")

</div>

> [@stillyslalom](#):
>
> However, `@simd` may not play well with the random number generator (are there memory dependencies based on the state of the RNG?), but the specifics are beyond me.

This will not generate any SIMD instructions so it must be that the structure of the loop is slightly different with the SIMD macro which in this case appears to matter.

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [April 4, 2019, 6:55am UTC](https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732/4 "2019-04-04T06:55:04Z")

</div>

Diffing the asm generated in both cases, the only difference is that the simd version calls `julia_randn_unlikely_12356`, whereas the non-simd version calls `randn_unlikely`. No idea what that means, but probably unintended?

edit: well, that’s not the _only_ difference, there’s also a `jne` that gets swapped with a `jb`, but that probably shouldn’t matter?

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [April 4, 2019, 8:02am UTC](https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732/5 "2019-04-04T08:02:29Z")

</div>

I was confused in the previous post, sorry. That has nothing to do with `simd`:

```julia
using Random
broadcast_randn(x) = (x .= randn.())
inplace_randn(x) = randn!(x)

function myrandn!(x)
    @inbounds @simd for i in eachindex(x)
        x[i] = randn()
    end
    x
end

function myrandn_nosimd!(x)
    @inbounds for i in eachindex(x)
        x[i] = randn()
    end
    x
end

x = zeros(10_000)
@btime broadcast_randn($x);
@btime inplace_randn($x);
@btime myrandn!($x);
@btime myrandn_nosimd!($x);

```

is only slow in `inplace_randn`. The real difference in the two cases is that `randn` isn’t inlined in `randn!`. This is despite `randn` being marked as `@inline`, so it looks like the inlining heuristics are being too conservative here.

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [April 4, 2019, 8:07am UTC](https://discourse.julialang.org/t/possible-inefficiency-in-randn/22732/6 "2019-04-04T08:07:41Z")

</div>

Opened an issue: [Call to randn not inlined in randn! · Issue #31607 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/31607)
