# Repeated compilation for same function with extreme type instability

**URL:** <https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 14, 2024, 10:38am UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244 "2024-05-14T10:38:02Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [May 14, 2024, 10:38am UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/1 "2024-05-14T10:38:02Z")

</div>

Here is a minimal reproducible example: [Repeated compilation for same function with extreme type instability - #5 by guoyongzhi](https://discourse.julialang.org/t/repeated-compilation-for-same-function/114244/5)

* * *

My function consistently experiences prolonged compilation times with each execution. However, upon @snoopr inspection, I consistently receive empty invalidations. What steps should I take to address this issue?

```julia
using WordCloud
using SnoopCompileCore
using SnoopCompile
wordcloud("aa bb cc dd")
invalidations = @snoopr wordcloud("aa bb cc dd")
@show length(uinvalidated(invalidations))
@time wordcloud("aa bb cc dd")

```

length(uinvalidated(invalidations)) = 0  
0.669331 seconds (438.85 k allocations: 30.645 MiB, 75.80% compilation time: 4% of which was recompilation)

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [May 14, 2024, 2:15pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/2 "2024-05-14T14:15:11Z")

</div>

I think this issue might be related to unstable types, as I’m certain the problem lies within function `WordCloud.getstylescheme`, where there are some types determined by random numbers.

```julia
using WordCloud
WordCloud.getstylescheme(["a"], [1]);
@time WordCloud.getstylescheme(["a"], [1]);

```

0.181821 seconds (204.89 k allocations: 13.782 MiB, 98.69% compilation time)

* * *

Are there any inspection tools in Julia for this kind of issues?  
Is there a way in Julia to mark a dynamic function to be executed by interpretation instead of time consuming re-compilation?

---

<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:** [May 14, 2024, 2:46pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/3 "2024-05-14T14:46:51Z")

</div>

Maybe you can try `@nospecialize`:

[https://docs.julialang.org/en/v1/base/base/#Base.@nospecialize](https://docs.julialang.org/en/v1/base/base/#Base.@nospecialize)

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [May 14, 2024, 3:03pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/4 "2024-05-14T15:03:42Z")

</div>

The random number is generated within the function body, and since the function can accept zero arguments, the `@nospecialize` decorator can not help me. Thank you regardless.

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [May 14, 2024, 3:11pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/5 "2024-05-14T15:11:16Z")

</div>

Thankfully, I have created a minimal reproducible example:

```julia
f1() = rand() > 0.5 ? 1 : rand()
f2() = rand() > 0.5 ? 1 : rand()
f3() = rand() > 0.5 ? 1 : rand()
f4() = rand() > 0.5 ? 1 : rand()
f5() = rand() > 0.5 ? 1 : rand()
f6() = rand() > 0.5 ? 1 : rand()

ff() = f1() + f2() + f3() + f4() + f5() + f6()

@time ff()

```

0.007261 seconds (7.20 k allocations: 485.763 KiB, 98.70% compilation time)

```julia
@time (f1(), f2(), f3(), f4(), f5(), f6())

```

0.000019 seconds (6 allocations: 240 bytes)

Is there a way in Julia to mark `ff()` to be executed by interpretation instead of time consuming re-compilation?

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [July 10, 2024, 4:32am UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/6 "2024-07-10T04:32:15Z")

</div>

I found that: [GitHub - JuliaDebug/JuliaInterpreter.jl: Interpreter for Julia code](https://github.com/JuliaDebug/JuliaInterpreter.jl)

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 10, 2024, 7:44am UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/7 "2024-07-10T07:44:00Z")

</div>

I am unsure whether I understand your problem. Let me try to summarize what I got:  
You have some function `WordCloud.wordcloud` and this is slow, because everytime you call it something gets compiled. You think this is due to some type-instability which is caused by randomness and provide an example showcasing that.

The compilations in your example stem indeed from type-instability. In this case, I think it is because `a+b+c+d` is transformed into `+(a,b,c,d)` and so a new version of this multi-argument `+` needs to be compiled for every new combination. This hypothesis can be checked by putting in parenthesis:

```julia
ff() = (f1() + f2()) + ((f3() + f4()) + (f5() + f6()))

```

Here all `+` are 2-argument and it does not show any compilations.

I also ran `wordcloud` a couple of times and noticed that the style or something is randomized. So I think the compilations stem from the fact that each run generates a combination of types passed to another function that was not encountered before. So a new method needs to be compiled for that type-combination. Note that after a couple of runs, new combinations become rarer and often times no compilation happens.  
To reduce the compilations, you’ll need to reduce the number of type combinations. I don’t know how much influence you have on that, since I don’t know at what level these happen in the code and which level you can influence. To reduce the number of type combinations there are a couple of ways to achieve this:

1. break up functions to reduce the combinatorics, e.g. split (if possible) `f(randtypeA, randtypeB)` into `f1(randtypeA)` and `f2(randtypeB)`
2. Reduce types e.g. by removing parameters on parametric types - this introduces type-instabilities but reduces the compilation times
3. Instead of the above, use SumTypes.jl (or DynamicsSumTypes.jl) to “pack” multiple “subtypes” into a single type.

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [July 10, 2024, 5:18pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/8 "2024-07-10T17:18:03Z")

</div>

Thanks for your nice reply. You’ve understood my problem precisely. Your advice to reduce the number of type combinations is very inspiring. Let me elaborate further on the context.

My type-unstable function acts as a random scheme generator (corresponding to `ff()`). It’s not performance-critical and is naturally written (and likely to be run) in a Pythonic way. For instance, the color generator (corresponding to `f1()`) might return either `"black"`, `0.7`, `(255,255,255)` or a `Color` object. Similarly, the picture size generator (corresponding to `f2()`) might return `512`, `(512, 768)`, `0.5`, or `:original`.

I believe such scenarios are not uncommon, so I’m wondering if there’s a way to instruct Julia to operate in an interpreted mode for a specific function. We already have `@nospecialize` after all. I came across `JuliaInterpreter.@interpret`. It works, but it seems not tailored for this purpose and is quite slow.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 10, 2024, 5:30pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/9 "2024-07-10T17:30:30Z")

</div>

> [@guoyongzhi](#):
>
> I believe such scenarios are not uncommon, so I’m wondering if there’s a way to instruct Julia to operate in an interpreted mode for a specific function.

While this is not possible to my knowledge, maybe it would be an idea to reduce the optimization level. This can either be done globally by starting Julia with `-O0` or `-O1` or even `--compilation=min` (this effectively turns Julia into an interpreter).  
If your program does not do much more than the plotting, then one of these might be the easiest option.

Alternatively there is `Base.Experimental.@optlevel` where you can set the optimization level for a module (but as the name suggests this is a experimental setting). As this is on a per-module basis, you’d need to separate out the parts that should get less optimization into their own submodule.

---

<div class="post-metadata">

**Author:** ![guoyongzhi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/guoyongzhi/32/28306_2.png) [@guoyongzhi](https://discourse.julialang.org/u/guoyongzhi)\
**Post date:** [July 10, 2024, 5:34pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/10 "2024-07-10T17:34:20Z")

</div>

There is no all-powerful programming language.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 10, 2024, 5:38pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/11 "2024-07-10T17:38:41Z")

</div>

…yet 😆

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 10, 2024, 6:34pm UTC](https://discourse.julialang.org/t/repeated-compilation-for-same-function-with-extreme-type-instability/114244/12 "2024-07-10T18:34:03Z")

</div>

> [@guoyongzhi](#):
>
> wondering if there’s a way to instruct Julia to operate in an interpreted mode for a specific function

It’s still just an experimental interface, but there’s `Base.Experimental.@compiler_options`. Try something like:

```julia
module InterpretedModule

Base.Experimental.@compiler_options optimize=0 compile=min infer=no max_methods=1

...

end

```
