# Compilation Over Branches

**URL:** https://discourse.julialang.org/t/compilation-over-branches/74776
**Category:** Internals & Design
**Tags:** question
**Created:** [January 17, 2022, 11:04pm UTC](https://discourse.julialang.org/t/compilation-over-branches/74776 "2022-01-17T23:04:16Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![bjack205](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjack205/32/7294_2.png) [@bjack205](https://discourse.julialang.org/u/bjack205)
#### Post date: [January 17, 2022, 11:04pm UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/1 "2022-01-17T23:04:16Z")

</div>

I have a question on how the compiler internals work. Does the compiler compile all functions that could called in any branch of the code? For example, if I have a function like the following:

```julia
using StaticArrays

function fast(A)::Nothing
    for i in eachindex(A)
        A[i] += 1
    end
    return nothing
end

function slow(A)::Nothing
    A .+= 1
    return nothing
end

function outer(A; flag=false)
    if flag
        slow(A)::Nothing
    else
        fast(A)::Nothing
    end
end

A = SizedMatrix{50,50}(zeros(50,50))
@time fast(A);
@time outer(A);

```

which returns

```julia
0.007224 seconds (19.49 k allocations: 1.133 MiB, 99.70% compilation time)
2.679748 seconds (19.08 M allocations: 711.613 MiB, 12.69% gc time, 100.00% compilation time)

```

So it’s pretty obvious the `slow` method is getting compiled, even though it’s never called. Does this continue until all branches have been called? For example, if `slow` had more branches, would all of those get compiled as well?

Is the only way to avoid compiling the `slow` method here to use a compile-time action using e.g. multiple dispatch on the type of `A` or `@generated`?

My use case is pretty similar to this, where I want to use StaticArrays for small sizes, but fall back to methods that use normal arrays for larger sizes because the compilation time blows up for large `StaticArrays`. For some critical computation kernels I have 2 version like the above, and want to switch easily between them. I just want to verify that this HAS to be done as a compile-time decision. For example, ideally I’d let the user decide if it’s worth it to pay the compile-time cost for runtime performance (which actually isn’t much in this case, but in general, you could see this being a logical tradeoff you’d want to expose to the end user). My previous understanding was that the Julia compiler only compiled functions as it encountered them. I was a little surprised that `slow` had to be compiled, even when `outer` already knows the output type.

---

<div class="post-metadata">

### Author: ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)
#### Post date: [January 17, 2022, 11:08pm UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/2 "2022-01-17T23:08:27Z")

</div>

The compiler tries to compile the maximal amount of code that is statically derivable from the entrypoint to the compiler. There currently aren’t really any barriers to control this behavior, but if you do something like `Base.inferencebarrier(slow)(A)`, you’ll prevent inference from knowing what `slow` is, so it won’t get compiled.

---

<div class="post-metadata">

### Author: ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)
#### Post date: [January 17, 2022, 11:11pm UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/3 "2022-01-17T23:11:25Z")

</div>

Note that this will result in losing type stability.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [January 17, 2022, 11:11pm UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/4 "2022-01-17T23:11:54Z")

</div>

> [@bjack205](#):
>
> My use case is pretty similar to this, where I want to use StaticArrays for small sizes, but fall back to methods that use normal arrays for larger sizes because the compilation time blows up for large `StaticArrays` .

This seems a good place for multiple dispatch with a function barrier.

Something like this?

```julia
julia> g(x::SVector) = 1
g (generic function with 3 methods)

julia> g(x::AbstractVector) = 2
g (generic function with 3 methods)

julia> function f(x)
           if length(x) < 10
               y = SVector(ntuple(i -> x[i], length(x))...)
           else
               y = copy(x)
           end
           return g(y)
       end
f (generic function with 1 method)

julia> @time f(rand(3))
  0.012883 seconds (25.37 k allocations: 1.655 MiB, 99.67% compilation time)
1

julia> @time f(rand(3))
  0.000014 seconds (7 allocations: 224 bytes)
1

julia> @time f(rand(20))
  0.000125 seconds (397 allocations: 28.062 KiB, 79.30% compilation time)
2

julia> @time f(rand(20))
  0.000006 seconds (2 allocations: 448 bytes)
2

```

`f` is type-unstable, though. That would only make sense if `g` is where the expensive computations occur.

---

<div class="post-metadata">

### Author: ![bjack205](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjack205/32/7294_2.png) [@bjack205](https://discourse.julialang.org/u/bjack205)
#### Post date: [January 17, 2022, 11:15pm UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/5 "2022-01-17T23:15:14Z")

</div>

Okay, this is a useful insight into the compiler behavior, thank you!

---

<div class="post-metadata">

### Author: ![bjack205](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjack205/32/7294_2.png) [@bjack205](https://discourse.julialang.org/u/bjack205)
#### Post date: [January 17, 2022, 11:16pm UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/6 "2022-01-17T23:16:17Z")

</div>

You could fix the type instability with a type annotation like above, though, right?

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [January 18, 2022, 12:04am UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/7 "2022-01-18T00:04:08Z")

</div>

> fixing type instability

Stripping down the example (possibly too much)…

```julia
g(x::AbstractVector) = 2
g(x::SVector) = 1

function f(x)
    y = copy(x)
    return g(y)
end

a = SVector{4}(collect(1:4));
b = collect(1:12);

```

```julia
julia> @code_warntype(f(a))
MethodInstance for f(::SVector{4, Int64})
  from f(x) in Main at REPL[4]:1
Arguments
  #self#::Core.Const(f)
  x::SVector{4, Int64}
Locals
  y::SVector{4, Int64}
Body::Int64
1 ─ (y = Main.copy(x))
│ %2 = Main.g(y)::Core.Const(1)
└── return %2

julia> @code_warntype(f(b))
MethodInstance for f(::Vector{Int64})
  from f(x) in Main at REPL[4]:1
Arguments
  #self#::Core.Const(f)
  x::Vector{Int64}
Locals
  y::Vector{Int64}
Body::Int64
1 ─ (y = Main.copy(x))
│ %2 = Main.g(y)::Core.Const(2)
└── return %2

```

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [January 18, 2022, 12:16am UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/8 "2022-01-18T00:16:59Z")

</div>

Yeah, the hard part for type stability is to make a decision based on the vector length, when the length is not part of the type (as for StaticArrays).

---

<div class="post-metadata">

### Author: ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)
#### Post date: [January 18, 2022, 5:00am UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/9 "2022-01-18T05:00:34Z")

</div>

Some compilers do support such behavior. For example, to accelerate application warm up time, Android (Java) and many JS engine distinguish between “cold” code and “hot” code and may delay the compilation of “cold” code or only use a less optimized interpreter/bytecode compiler. Once the “cold” code has executed enough times, the compiler will promote the “cold” code to a “hot” code and recompile the function.

Unfortunately, some dedicated mechanisms are needed here to avoid performance loss. After compiling of the cold code, the previously generated machine code needs to be “patched” to switch from the old less optimized code to this newly compiled code. Otherwise a runtime check is needed to check whether the code has already got compiled.

I am not sure whether this is a good idea for numerical code because it might hurt performance if the code is invoked in a loop. Another problem is that this also has something to do with type inference. Even we can defer compilation to runtime, type inference must function statically as a whole unless we add necessary annotations (that is, there’s no partial type inference). Anyway, this could be an interesting demo of dynamic compilation.

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [January 18, 2022, 5:27am UTC](https://discourse.julialang.org/t/compilation-over-branches/74776/10 "2022-01-18T05:27:30Z")

</div>

indeed, Julia does not use: [Tracing just-in-time compilation - Wikipedia](https://en.wikipedia.org/wiki/Tracing_just-in-time_compilation) (notable examples are HotSpot JVM and V8 I guess)

however, there’s [https://github.com/tisztamo/Catwalk.jl](https://github.com/tisztamo/Catwalk.jl) that pushes optimization even further “at runtime”.
