# Generators speed

**URL:** https://discourse.julialang.org/t/generators-speed/3715
**Category:** New to Julia
**Created:** [May 15, 2017, 12:21pm UTC](https://discourse.julialang.org/t/generators-speed/3715 "2017-05-15T12:21:08Z")
**Posts on this page:** 6
**Page:** 1

<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: [May 15, 2017, 12:21pm UTC](https://discourse.julialang.org/t/generators-speed/3715/1 "2017-05-15T12:21:08Z")

</div>

Hi,

```julia
julia> N = 10000000; A = randn(N); @time sum(A); @time sum(A[i] for i in 1:N); @time sum(a for a in A)
  0.007686 seconds (5 allocations: 176 bytes)
  0.640131 seconds (30.02 M allocations: 458.566 MB, 13.64% gc time)
  0.039558 seconds (16.76 k allocations: 713.857 KB)

```

in both 0.5 and 0.6rc. Am I wrong in thinking the second and third versions should also be fast, based on the paragraph “Generators” of [Julia 0.5 Highlights](https://julialang.org/blog/2016/10/julia-0.5-highlights)?

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [May 15, 2017, 12:30pm UTC](https://discourse.julialang.org/t/generators-speed/3715/2 "2017-05-15T12:30:34Z")

</div>

You should not benchmark in global scope.

```julia
using BenchmarkTools

N = 10000000
A = randn(N)

sum1(A) = sum(A)
sum2(A) = sum(A[i] for i in 1:N)
sum3(A) = sum(a for a in A)

```

then

```julia
julia> @benchmark sum1($A)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 4.576 ms (0.00% GC)
  median time: 5.744 ms (0.00% GC)
  mean time: 5.672 ms (0.00% GC)
  maximum time: 6.901 ms (0.00% GC)
  --------------
  samples: 881
  evals/sample: 1

julia> @benchmark sum2($A)
BenchmarkTools.Trial: 
  memory estimate: 112 bytes
  allocs estimate: 5
  --------------
  minimum time: 12.764 ms (0.00% GC)
  median time: 12.885 ms (0.00% GC)
  mean time: 12.972 ms (0.00% GC)
  maximum time: 16.242 ms (0.00% GC)
  --------------
  samples: 386
  evals/sample: 1

julia> @benchmark sum3($A)
BenchmarkTools.Trial: 
  memory estimate: 48 bytes
  allocs estimate: 3
  --------------
  minimum time: 12.761 ms (0.00% GC)
  median time: 12.874 ms (0.00% GC)
  mean time: 12.941 ms (0.00% GC)
  maximum time: 16.360 ms (0.00% GC)
  --------------
  samples: 387
  evals/sample: 1

```

so the difference is 2-3x. Above using `v0.6-rc1`.

---

<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: [May 15, 2017, 12:45pm UTC](https://discourse.julialang.org/t/generators-speed/3715/3 "2017-05-15T12:45:57Z")

</div>

FWIW `sum2` is still using global variables…

---

<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: [May 15, 2017, 12:52pm UTC](https://discourse.julialang.org/t/generators-speed/3715/4 "2017-05-15T12:52:36Z")

</div>

That’s right, sorry about that! I was extracting the code from a function that had weird performance and forgot about the (very annoying) globals problem. So here’s a more interesting benchmark, closer to what I’m actually doing:

```julia
using BenchmarkTools

const N = 10000000
A = randn(N)

sum1(A) = sum(A.*A.+A)
sum2(A) = sum(A.*A+A)
sum3(A) = sum(A[i]*A[i]+A[i] for i in 1:N)
sum4(A) = sum(a*a+a for a in A)
function sum5(A)
    res = 0.0
    for i = 1:N
        res += A[i]*A[i]+A[i]
    end
end

BenchmarkTools.DEFAULT_PARAMETERS.samples = 10
BenchmarkTools.DEFAULT_PARAMETERS.seconds = 2

@btime sum1($A)
@btime sum2($A)
@btime sum3($A)
@btime sum4($A)
@btime sum5($A)

```

I get

```julia
  36.951 ms (2 allocations: 76.29 MiB)
  80.213 ms (4 allocations: 152.59 MiB)
  12.607 ms (4 allocations: 80 bytes)
  12.628 ms (3 allocations: 48 bytes)
  4.011 ms (0 allocations: 0 bytes)

```

I understand the first two timings (they imply a vector allocation), but not the third and fourth. Is any of these timings considered a bug? Does it mean I’m condemned to boring loops? ☹

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [May 15, 2017, 1:21pm UTC](https://discourse.julialang.org/t/generators-speed/3715/5 "2017-05-15T13:21:56Z")

</div>

How fast is your `sum5` if you actually return the result?

This is maybe too specialized to generalize to your real problem but you can also compare

```julia
sum6(A) = sum(x -> x * x + x, A)

```

---

<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: [May 15, 2017, 1:36pm UTC](https://discourse.julialang.org/t/generators-speed/3715/6 "2017-05-15T13:36:40Z")

</div>

That’s a good point… then the speed difference vanishes. I also included an `@inbounds @simd` version of the loop. The final benchmark is

```julia
using BenchmarkTools

const N = 10000000
A = randn(N)

sum1(A) = sum(A.*A.+A)
sum2(A) = sum(A.*A+A)
sum3(A) = sum(A[i]*A[i]+A[i] for i in 1:N)
sum4(A) = sum(a*a+a for a in A)
function sum5(A)
    res = 0.0
    for i = 1:N
        res += A[i]*A[i]+A[i]
    end
    res
end
function sum6(A)
    res = 0.0
    @inbounds @simd for i = 1:N
        res += A[i]*A[i]+A[i]
    end
    res
end
sum7(A) = sum(x -> x * x + x, A)

BenchmarkTools.DEFAULT_PARAMETERS.samples = 10
BenchmarkTools.DEFAULT_PARAMETERS.seconds = 2

@btime sum1($A)
@btime sum2($A)
@btime sum3($A)
@btime sum4($A)
@btime sum5($A)
@btime sum6($A)
@btime sum7($A)

```

with result (0.6 rc)

```julia
  38.080 ms (2 allocations: 76.29 MiB)
  84.583 ms (4 allocations: 152.59 MiB)
  12.619 ms (4 allocations: 80 bytes)
  12.606 ms (3 allocations: 48 bytes)
  12.629 ms (0 allocations: 0 bytes)
  7.230 ms (0 allocations: 0 bytes)
  7.297 ms (0 allocations: 0 bytes)

```

(neither `@inbounds` nor `@simd` by itself is able to get the 7ms, both are needed)

Amazingly, sum(x → x \* x + x, A) is able to SIMD automatically! I don’t understand how that can happen: looking at the implementation, it falls back to mapfoldl\_impl, which is a simple while loop…
