# If control flow 40X slow down

**URL:** <https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144>\
**Category:** General Usage\
**Created:** [November 4, 2018, 7:43pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144 "2018-11-04T19:43:54Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Donut\_Meepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/donut_meepo/32/9085_2.png) [@Donut\_Meepo](https://discourse.julialang.org/u/Donut_Meepo)\
**Post date:** [November 4, 2018, 7:43pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/1 "2018-11-04T19:43:54Z")

</div>

Hi,

By adding some work in the if statement (test2 function), even though the evaluation always false and so nothing has been done in the if block, I got 40X slow down compare to real nothing (test) in the if blocks.

```julia
function test(m::Array{Int8,2})
    n = size(m)[1]
    progress = 0
    @inbounds for i in 1:n, j in i:n
        nonoverlap = true
        progress+=1
        if progress%100000000==0
            #do nothing
        end
    end
end

```

```julia
function test2(m::Array{Int8,2})
    n = size(m)[1]
    progress = 0
    @inbounds for i in 1:n, j in i:n
        nonoverlap = true
        progress+=1
        if progress%100000000==0
            @printf("%d\n",progress)
        end
    end
end

```

m=convert(Array{Int8,2}, rand(0:1, 22, 1000))  
benchmark test(m) and test(m2) results are attached. I am confused what are the extra running time comes from. Thanks.  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/b/e/be0d9ce394508dd1103dcb953dcb1a196fe819cb.png)  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/7/6/7641ee061cd6ac94884332f017afa43cdcdaa1ca.png)

---

<div class="post-metadata">

**Author:** ![anon94023334](https://avatars.discourse-cdn.com/v4/letter/a/e274bd/32.png) [@anon94023334](https://discourse.julialang.org/u/anon94023334)\
**Post date:** [November 4, 2018, 7:48pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/2 "2018-11-04T19:48:08Z")

</div>

Probably because the compiler is smart enough to elide most of test, but not test2:

```julia
julia> @code_native test(a)
	.section	__TEXT,__ text,regular,pure_instructions
; Function test {
; Location: REPL[1]:2
	decl	%eax
	movl	%esi, -8(%esp)
; Location: REPL[1]:8
	decl	%eax
	movl	$174055432, %eax ## imm = 0xA5FE008
	addl	%eax, (%eax)
	addb	%al, (%eax)
	retl
;}

```

vs test2:  
[julia\> @code\_native test2(a) .section \_\_TEXT,\_\_text,regular,pure\_instructions - Pastebin.com](https://pastebin.com/Z2JmTd1L) (was too long to paste here - also I changed `@printf` to `printf`.)

---

<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:** [November 4, 2018, 7:55pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/3 "2018-11-04T19:55:09Z")

</div>

I see that you have tried to quote your code, but it’s not quite right. Please take a look at this post to see how to format code for discourse: [PSA: how to quote code with backticks](https://discourse.julialang.org/t/psa-how-to-quote-code-with-backticks/7530)

You should also remember to interpolate variables when using BenchmarkTools: `@benchmark test($m)`, instead of `@benchmark test(m)`. It may not make a difference here, but in general, it does, and it removes the need to double-check if performance issues are due to the lack of interpolation.

---

<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:** [November 4, 2018, 8:04pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/4 "2018-11-04T20:04:36Z")

</div>

When benchmarking it is important to be able to do some napkin math to figure out if the results one get are at all reasonable.

For example, here you have a double loop going doing `22 * 22 ~ 500` iterations. As a very rough estimate, we can say that a CPU can do 1 integer addition per cycle. So a 3 GHz CPU should be able to do `500` iterations in

`500 / (3 * 10^9) * 10^9` ns which is approximately `170` ns. So clearly, getting a result of `4` ns is just not reasonable.

---

<div class="post-metadata">

**Author:** ![Donut\_Meepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/donut_meepo/32/9085_2.png) [@Donut\_Meepo](https://discourse.julialang.org/u/Donut_Meepo)\
**Post date:** [November 4, 2018, 8:08pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/5 "2018-11-04T20:08:24Z")

</div>

Thank you for the link! I was looking for that.

```julia
function test(m::Array{Int8,2})
    n = size(m)[1]
    progress = 0
    @inbounds for i in 1:n, j in i:n
        nonoverlap = true
        progress+=1
        if progress%100000000==0
            #do nothing
        end
    end
end

```

```julia
function test2(m::Array{Int8,2})
    n = size(m)[1]
    progress = 0
    @inbounds for i in 1:n, j in i:n
        nonoverlap = true
        progress+=1
        if progress%100000000==0
            @printf("%d\n",progress)
        end
    end
end

```

---

<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:** [November 4, 2018, 8:10pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/6 "2018-11-04T20:10:17Z")

</div>

> [@Donut\_Meepo](#):
>
> ```julia
> if progress%100000000==0
> #do nothing
> end
> 
> ```

There is nothing going on inside this block, therefore it is not necessary to evaluate the condition. And therefore it is not necessary to evaluate the loop either. The whole function is basically optimized away.

> [@Donut\_Meepo](#):
>
> ```julia
> if progress%100000000==0
> @printf("%d\n",progress)
> end
> 
> ```

Even though it’s alway false, you don’t know that _a priori_, so you still have to evaluate the condition at every step of the loop.

---

<div class="post-metadata">

**Author:** ![Donut\_Meepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/donut_meepo/32/9085_2.png) [@Donut\_Meepo](https://discourse.julialang.org/u/Donut_Meepo)\
**Post date:** [November 4, 2018, 8:14pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/7 "2018-11-04T20:14:20Z")

</div>

I change the block to

```julia
if progress%100000000==0
    1+1
end
'''
it still gives me ～5ns result.
```

---

<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:** [November 4, 2018, 8:14pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/8 "2018-11-04T20:14:40Z")

</div>

Further problems:

1. `progress` is not returned, so `test2(m::Array{Int8, 2}) = nothing` is an equivalent function (if the `@printf` is removed).

2. The optimizer knows math so it can just figure out what the end result of `progress` from the loop ranges.

---

<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:** [November 4, 2018, 8:15pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/9 "2018-11-04T20:15:57Z")

</div>

> [@Donut\_Meepo](#):
>
> I change the block to
> 
> ```julia
> if progress%100000000==0
> 1+1
> end
> 
> ```
> 
> it still gives me ～5ns result.

1+1 also doesn’t do anything visible from the caller. A compiler is free to optimize as much as it wants as long as it doesn’t change any observable result. This is known as the “as if” rule.

---

<div class="post-metadata">

**Author:** ![Donut\_Meepo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/donut_meepo/32/9085_2.png) [@Donut\_Meepo](https://discourse.julialang.org/u/Donut_Meepo)\
**Post date:** [November 4, 2018, 8:16pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/10 "2018-11-04T20:16:31Z")

</div>

so it does not run the for loop at all?

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [November 4, 2018, 8:16pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/11 "2018-11-04T20:16:35Z")

</div>

The `@printf` macro generates a ton of inline code (which is not great and should be fixed), you could try putting it in its own function and see if that helps at all.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [November 4, 2018, 8:23pm UTC](https://discourse.julialang.org/t/if-control-flow-40x-slow-down/17144/12 "2018-11-04T20:23:16Z")

</div>

> [@Donut\_Meepo](#):
>
> so it does not run the for loop at all?

A trivial loop can easily be optimized away entirely. This can happen even in non-trivial cases:

```jl
function range_sum(a::Int, b::Int)
    s = 0
    for i = min(a,b):max(a,b)
        s += i
    end
    return s
end

```

```jl
julia> @code_llvm range_sum(-10, 10)

define i64 @julia_range_sum_220933050(i64, i64) {
  %2 = icmp slt i64 %1, %0
  %3 = select i1 %2, i64 %0, i64 %1
  %4 = select i1 %2, i64 %1, i64 %0
  %5 = sub i64 %3, %4
  %6 = add i64 %3, -1
  %7 = sub i64 %6, %4
  %8 = zext i64 %7 to i65
  %9 = zext i64 %5 to i65
  %10 = mul i65 %8, %9
  %11 = lshr i65 %10, 1
  %12 = trunc i65 %11 to i64
  %13 = add i64 %4, 1
  %14 = mul i64 %5, %13
  %15 = add i64 %4, %14
  %16 = add i64 %15, %12
  ret i64 %16
}

```

The function is computed in closed form, no loops. Compilers are very good at integer math and know how to simplify basic integer summation problems.
