# Taking TTFX seriously: Can we make common packages faster to load and use

**URL:** <https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949>\
**Category:** Performance\
**Tags:** ttfp\
**Created:** [January 20, 2022, 5:16pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949 "2022-01-20T17:16:03Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 20, 2022, 5:16pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/1 "2022-01-20T17:16:03Z")

</div>

So much work has been done to improve julia compilation and remove invalidations. Things really feel a lot snappier to use.

But there is still the problem of packages that were written without much thought to startup time, and TTFX - the time-to-first whatever a package does most, is sometimes really slow.

Some common problems I see are (reorganised to be in order of importance):

1. Lack of type stability slowing down compilation.
2. Not calling `precompile` for common methods, or just running them if that is possible (see Chrisses comment below).
3. Using Requires.jl so there is no code precompilation for the required code.
4. Not checking or fixing compilation time of dependencies

Or simply that TTFX profiling has never been done, or was difficult in the specific context.

I have been as guilty of these things as anyone else, and I’m slowly trying to work on it in my own packages. But it seems there are problems in some widely used packages, and fixing these could really improve the experience of using Julia. We could all probably learn a bit more about how people are improving load times across the ecosystem.

## An example: Blink.jl and `Window()`

I’m not singling anyone out, Blink is super useful. It’s just something I happen to use for a few things and would really like if it loaded quickly.

Blink.jl seems to be the default container for a Julia desktop web app. But it’s _really_ slow to get started. `using Blink` takes 5 seconds to load on my laptop, and loading an empty window with `Blink.Window()` takes 11-15 seconds to finish the first time!! In comparison, vscode only takes 2 seconds to load in total, also using Electron.

> <https://github.com/JuliaGizmos/Blink.jl/issues/288>
>
> So I use blink for a lot of things, and it's useful. But its tedious.
> 
> \`using …Blink\` takes over 5 seconds on my laptop:
> 
> !\[2022-01-20-134131\_1920x1080\_scrot\](https://user-images.githubusercontent.com/2534009/150340742-e0ee9053-0f9e-4e7b-a24b-78727c62cca8.png)
> 
> Mostly this is spent in AssetRegistry.jl (the large red section). I'm not sure why this takes so long.
> 
> Second, the first time \`Blink.Window()\` takes over 11 seconds: 
> 
> !\[2022-01-20-135156\_1920x1080\_scrot\](https://user-images.githubusercontent.com/2534009/150342110-5dabefa9-2b20-4560-b850-71aba29ec297.png)
> 
> A lot of compilation (cant we \`precompile\` some of this for a generic \`Window\` call?) and the large middle chunk in Mux.jl and Parser, wherever that is.
> 
> Loading vscode only takes 2 seconds, and it's built on Electron too...
> 
> How do we reduce this to a reasonable amount?
> 
> Edit:
> 
> \## Package load time
> 
> It seems at least partly this is caused by the strange relationships of Blink.jl and WebIO.jl: If Blink depends on WebIO.jl, why is there code for blink in a Requires.jl block in WebIO.jl? This breaks precompilation.
> 
> Reorganising the requires block in WebIO.jl gets the load time of Blink.jl down to 1 second!
> 
> \## Blink.Window
> 
> A large fraction of the load time is parsing in s \`JSON.Parser.parse\`. For a generic window, surely we can do this work up-front during precompilation?
> 
> Another large fraction of the work is type inference, probably due to all the untyped objects. This also means that \`precompile(Window, ())\` is not very successful. Precompiling the component methods that \`Window()\` ends up calling in HTTP.jl/Mux.jl may be able to reduce this. But more type stability should also help.

It turns out startup time is largely due to Requires.jl blocks in WebIO.jl. It seems to be precompilation and JSON parsing in `Blink.Window()`.

Moving code out of requires in WebIO.jl gets the blink load time down to 1 second! Yes, a 5x improvement just from that.

But `Blink.Window()` is harder, a lot of compilation in HTTP.jl and Mux.jl, slow JSON parsing in `JSON.parse`, and various other things I’m not across. Maybe JSON3.jl would be faster? Maybe we can precompile all of this somehow? Maybe some profiling work on HTTP.jl would help? I’m not sure, but probably someone here has some ideas.

## Can we do this collectively?

It could be faster and more fun to make a collective effort of speeding up startup time for common packages, also making the tricks more widely known. A bit like the performance workshopping we see here - can we get competitive about how fast we can make a package load and perform its most common operation?

We could also get together a list of packages that we all use that could be faster? and make it happen? or just have a common thread here like “TTFX: Blink.jl Window()”.

Thoughts on this generally? Or ideas for Blink?

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 20, 2022, 11:31pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/2 "2022-01-20T23:31:19Z")

</div>

PR to WebIO fixing the startup time to Blink.jl:

[https://github.com/JuliaGizmos/WebIO.jl/pull/478](https://github.com/JuliaGizmos/WebIO.jl/pull/478)

Before

 ![usingBlink1](https://global.discourse-cdn.com/julialang/original/3X/9/b/9bf494c6130be38bae7fb418ef343d4bb7b94500.png)

After

 ![using_Blink2](https://global.discourse-cdn.com/julialang/original/3X/1/9/19fc34aec67cd0a7a2112c23c4fae5c6ffc93244.png)

`using Blink` is 1 second. But `Window()` is still really slow. Would be great if that was a few seconds.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [January 21, 2022, 2:26am UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/3 "2022-01-21T02:26:46Z")

</div>

> [@Raf](#):
>
> Simply that TTFX profiling has never been done.

If anyone hasn’t read the issue [https://github.com/SciML/DifferentialEquations.jl/issues/786](https://github.com/SciML/DifferentialEquations.jl/issues/786) I would recommend doing so. We worked through and documented a lot of starting time issues in DifferentialEquations.jl and go things about an order of magnitude better.

> [@Raf](#):
>
> Using Requires.jl so there is no code precompilation.

That seems to be overblown. The right way to profile it exists now:

> <https://github.com/JuliaPackaging/Requires.jl/pull/107>
>
> Adds a debug log so you can monitor \`@require\`s that get triggered and the time …spent running code
> 
> \`\`\`julia
> julia\> ENV\["JULIA\_DEBUG"\]="Requires"
> "Requires"
> 
> julia\> using Foo
> ┌ Debug: Requires conditionally ran code in 0.917808094 seconds: \`Ratios\` detected \`FixedPointNumbers\`
> └ @ Requires ~/.julia/packages/Ratios/xLeZh/src/Ratios.jl:123
> ┌ Debug: Requires conditionally ran code in 0.531145239 seconds: \`ArrayInterface\` detected \`SuiteSparse\`
> └ @ Requires ~/.julia/packages/ArrayInterface/mI7ab/src/ArrayInterface.jl:675
> ┌ Debug: Requires conditionally ran code in 0.002734456 seconds: \`ArrayInterface\` detected \`Adapt\`
> └ @ Requires ~/.julia/packages/ArrayInterface/mI7ab/src/ArrayInterface.jl:760
> ┌ Debug: Requires conditionally ran code in 0.029623663 seconds: \`ArrayInterface\` detected \`StaticArrays\`
> └ @ Requires ~/.julia/packages/ArrayInterface/mI7ab/src/ArrayInterface.jl:690
> ┌ Debug: Requires conditionally ran code in 0.006599821 seconds: \`ArrayInterface\` detected \`OffsetArrays\`
> └ @ Requires ~/.julia/packages/ArrayInterface/mI7ab/src/ArrayInterface.jl:1116
> ┌ Debug: Requires conditionally ran code in 0.022674606 seconds: \`HDF5\` detected \`FileIO\`
> └ @ Requires ~/.julia/packages/HDF5/pIJra/src/HDF5.jl:2133
> ┌ Debug: Requires conditionally ran code in 0.002288416 seconds: \`RandomNumbers\` detected \`Random123\`
> └ @ Requires ~/.julia/packages/RandomNumbers/3pD1N/src/RandomNumbers.jl:38
> ┌ Debug: Requires conditionally ran code in 1.708197842 seconds: \`CUDA\` detected \`SpecialFunctions\`
> └ @ Requires ~/.julia/packages/CUDA/sCev8/src/initialization.jl:35
> ┌ Debug: Requires conditionally ran code in 0.0126559 seconds: \`ArrayInterface\` detected \`Adapt\`
> └ @ Requires ~/.julia/packages/ArrayInterface/mI7ab/src/ArrayInterface.jl:796
> ┌ Debug: Requires conditionally ran code in 0.029985851 seconds: \`ArrayInterface\` detected \`CUDA\`
> └ @ Requires ~/.julia/packages/ArrayInterface/mI7ab/src/ArrayInterface.jl:795
> ┌ Debug: Requires conditionally ran code in 2.06503522 seconds: \`Zygote\` detected \`CUDA\`
> └ @ Requires ~/.julia/packages/Zygote/umM0L/src/lib/broadcast.jl:251
> ┌ Debug: Requires conditionally ran code in 0.211960078 seconds: \`Zygote\` detected \`Distances\`
> └ @ Requires ~/.julia/packages/Zygote/umM0L/src/Zygote.jl:45
> ┌ Debug: Requires conditionally ran code in 0.258361828 seconds: \`Zygote\` detected \`LogExpFunctions\`
> └ @ Requires ~/.julia/packages/Zygote/umM0L/src/Zygote.jl:46
> ┌ Debug: Requires conditionally ran code in 0.003038184 seconds: \`Zygote\` detected \`Colors\`
> └ @ Requires ~/.julia/packages/Zygote/umM0L/src/Zygote.jl:60
> ┌ Debug: Requires conditionally ran code in 0.284711345 seconds: \`ImageMorphology\` detected \`ImageMetadata\`
> └ @ Requires ~/.julia/packages/ImageMorphology/6oqcS/src/ImageMorphology.jl:65
> ┌ Debug: Requires conditionally ran code in 0.002487405 seconds: \`RegisterCore\` detected \`ImageMetadata\`
> └ @ Requires ~/.julia/packages/RegisterCore/YuSsR/src/RegisterCore.jl:397
> 
> julia\> 
> \`\`\`
> 
> cc. @ChrisRackauckas I think you were also after something like this

You can see that DifferentialEquations.jl had like \<1% in Requires.jl time. Some packages may have more, but I think most of the big Requires offenders seem to have been fixed, judging by the fact that DiffEq pulls in a lot of the ecosystem.

> [@Raf](#):
>
> - Not calling `precompile` for common methods.

This is not recommended. Instead, one should do simple calls in using time, maybe in a `let` block so the results don’t leak. See [https://github.com/SciML/OrdinaryDiffEq.jl/blob/v6.4.2/src/OrdinaryDiffEq.jl#L185-L214](https://github.com/SciML/OrdinaryDiffEq.jl/blob/v6.4.2/src/OrdinaryDiffEq.jl#L185-L214) as an example. This way you get something that’s always up-to-date.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 21, 2022, 2:52am UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/4 "2022-01-21T02:52:04Z")

</div>

> That seems to be overblown.

Its 80% of package load time in the example, so maybe not. And using Requires does exactly mean that the code behind the requires block is not precompiled. But thanks for the link.

> This is not recommended. Instead.

Its not always possible to actually call functions, but feel free to add a PR that calls `Blink.Window()` to improve compile time 😉

But I’ll alter the text to include both methods.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [January 21, 2022, 3:06am UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/5 "2022-01-21T03:06:00Z")

</div>

> [@Raf](#):
>
> Its not always possible to actually call functions, but feel free to add a PR that calls `Blink.Window()` to improve compile time 😉

Definitely not all of the time, but using `precompile` should probably the exception rather than the rule. There are some pretty clear maintenance reasons to prefer never using `precompile` unless you have to.

> [@Raf](#):
>
> Its 80% of package load time in the example, so maybe not. And using Requires does exactly mean that the code behind the requires block is not precompiled. But thanks for the link.

Sure it can happen, but I dug through a ton of packages and just didn’t find it to be the case for most package load times. In fact, StaticArrays ended up contributing more to using time than Requires for pretty much any package I tried (which is what led to [When should a package move to the standard library or system image? StaticArrays, what is it?](https://discourse.julialang.org/t/when-should-a-package-move-to-the-standard-library-or-system-image-staticarrays-what-is-it/73577)). So there’s always exceptions, but I don’t think the exceptions should be highlighted as the norm.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 21, 2022, 4:16am UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/6 "2022-01-21T04:16:43Z")

</div>

I think we are probably optimizing different kinds of packages, and that is reflected in the approach and the problems we encounter.

The places where I have still found classic Julia load times are in things like file IO tools like HDF5.jl and NCDatasets.jl, and some other visualisation things like `Blink.Window()`, `Interact.slider(x)`. These all still have pretty slow TTFX. Largely they would have to use `precompile` instead of running functions directly, because of IO. There are other package (e.g. Makie.plot and CSV.File) that are also pretty slow, but for harder to solve reasons.

Maybe it would be more productive to make a list of packages that are still much slower than they need to be, but a lot of people use. Key examples for me are:

~~Blink.jl  
Interact.jl  
HDF5.jl~~

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 21, 2022, 4:38am UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/7 "2022-01-21T04:38:02Z")

</div>

FWIW, `precompile` statements - especially where there is IO:  
[https://github.com/timholy/FlameGraphs.jl/blob/master/src/FlameGraphs.jl#L23](https://github.com/timholy/FlameGraphs.jl/blob/master/src/FlameGraphs.jl#L23)

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [January 21, 2022, 9:26am UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/8 "2022-01-21T09:26:47Z")

</div>

GUIs and IO need to do some weird stuff, yes.

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [January 21, 2022, 7:32pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/9 "2022-01-21T19:32:00Z")

</div>

> [@Raf](#):
>
> But there is still the problem of packages that were written without much thought to startup time, and TTFX - the time-to-first whatever a package does most, is sometimes really slow.

I put some effort into this every now and then, reading about packages for analyzing, and techniques, trying things. I have tried both `precompile` and running code during precompilation. I have never seen any benefit. In fact, running `somefunction(...)` in a `let` block as above made TTFX _slower_ in one case. That is, running `somefunction(...)` the first time after `using` the module took longer and allocated more. I know there are ways to investigate to find what to call or precompile, etc. But, it’s fairly complicated.

So in my case, it’s definitely not “written without much thought to startup time”. It’s that reducing start up time takes a lot of learning and a lot of time.

---

<div class="post-metadata">

**Author:** ![Krastanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/krastanov/32/6817_2.png) [@Krastanov](https://discourse.julialang.org/u/Krastanov)\
**Post date:** [January 21, 2022, 7:49pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/10 "2022-01-21T19:49:35Z")

</div>

If I could use this to share my own “I tried but the results were bad / made no sense” story: I tried to add `let` block with a “typical code use” statement (and **nothing else** , no change to the rest of the library), and that made the runtime (not compiletime) of the library worse: [Removing precompilation leads to lower allocations!?](https://discourse.julialang.org/t/removing-precompilation-leads-to-lower-allocations/73621) Some methods started to allocate instead of being allocation free (again, without changing anything in their source code).

I thought that should not be possible, and I still can not figure out what is so special about this fairly boring simulation code, that led to such weird behavior.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 21, 2022, 8:30pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/11 "2022-01-21T20:30:58Z")

</div>

I’ve also had this experience. In the example here, precompiling `Window` for Blink.jl does essentially nothing. But I’m pretty sure that’s because its not type stable very far, and the methods it will call don’t actually get compiled.

With NCDatasets.jl I experienced this too, but then fixed the type stability of the objects so all the fields were concrete. That alone improved compile time, and afterwards adding `precompile` also helped because it compiled much further down. But getting the type stability was actually the most important part.

@jlapeyre yes I could have phrased that better. Its totally true that sometimes you can do a lot of work on compilation and get no benefit from it. So the situation is more that either nothing has been tried, or improving anything is actually quite difficult.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [January 21, 2022, 9:33pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/12 "2022-01-21T21:33:58Z")

</div>

> [@Krastanov](#):
>
> I tried to add `let` block with a “typical code use” statement (and **nothing else** , no change to the rest of the library), and that made the runtime (not compiletime) of the library worse: [Removing precompilation leads to lower allocations!?](https://discourse.julialang.org/t/removing-precompilation-leads-to-lower-allocations/73621)

This could be an instance of [https://github.com/JuliaLang/julia/issues/35800](https://github.com/JuliaLang/julia/issues/35800) triggered by having Polyester and other JuliaSIMD tools in the stack. We’ve been talking about this inference bug for a bit, it’s a rough one but hopefully it will get resolved soon.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 21, 2022, 9:41pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/13 "2022-01-21T21:41:54Z")

</div>

Its such an awful bug, we wasted a lot of time on it with Accessors.jl, Revise compilation can fix it too giving you hope that you actually fixed something, when you didn’t.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 21, 2022, 10:17pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/14 "2022-01-21T22:17:20Z")

</div>

Also @jlapeyre, with this post I was hoping we could start sharing problems like you describe, and workshop them here like we do with performance issues. We can all dev a package and run `@profview using SomePackage` without too much hassle. It’s also easy to push a branch with changes to compare and add to.

---

<div class="post-metadata">

**Author:** ![Krastanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/krastanov/32/6817_2.png) [@Krastanov](https://discourse.julialang.org/u/Krastanov)\
**Post date:** [January 22, 2022, 5:05pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/15 "2022-01-22T17:05:18Z")

</div>

Exploring the linked issues, led me to a (seemingly esoteric) thing that is being done with kwargs to help with type inference.

Instead of `function f(...; kw::Bool=false)` people seem to be doing `function f(...;kw::Val{T}=Val(false)) where T`.

I think I am seeing things like this in these OrdinaryDiffEq and Polyester changes:

[https://github.com/SciML/OrdinaryDiffEq.jl/pull/1473/files#diff-8ce813ea8d7f370bc91b5ac1526a80f7fd354be769bafdd6b12b7368f3ae90a9L395](https://github.com/SciML/OrdinaryDiffEq.jl/pull/1473/files#diff-8ce813ea8d7f370bc91b5ac1526a80f7fd354be769bafdd6b12b7368f3ae90a9L395)

[https://github.com/JuliaSIMD/Polyester.jl/commit/5e6ae4c2ae009b507bbcf90ff2c2b9b7d5e94559#diff-a523f7f63af3c48f517501d7e392926093393f7d033fb208f477568ec30bec38L72](https://github.com/JuliaSIMD/Polyester.jl/commit/5e6ae4c2ae009b507bbcf90ff2c2b9b7d5e94559#diff-a523f7f63af3c48f517501d7e392926093393f7d033fb208f477568ec30bec38L72)

Why is this necessary? Why is it better than saying the keyword will be of type Bool?

EDIT: discourse seems to be stripping out the anchors from the links above making it difficult to tell which lines I am talking about. Here are the [SciML](https://github.com/SciML/OrdinaryDiffEq.jl/pull/1473/files#diff-8ce813ea8d7f370bc91b5ac1526a80f7fd354be769bafdd6b12b7368f3ae90a9L395) and [Polyester](https://github.com/JuliaSIMD/Polyester.jl/commit/5e6ae4c2ae009b507bbcf90ff2c2b9b7d5e94559#diff-a523f7f63af3c48f517501d7e392926093393f7d033fb208f477568ec30bec38L72) links with anchors.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [January 22, 2022, 5:54pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/16 "2022-01-22T17:54:37Z")

</div>

That’s to force specialization. Functions and DataTypes do not always specialize when passed into a function.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 22, 2022, 9:34pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/17 "2022-01-22T21:34:20Z")

</div>

Here’s a fun find in the Blink.jl (and Interact.jl) TTFX story: JSON.jl serialization seems to be responsible for half the TTFX of most JuliaGizmos packages! Swapping to JSON3.jl has huge TTFX gains for Interact.jl, and should for WebIO.jl/Blink.jl:

[https://github.com/JuliaGizmos/AssetRegistry.jl/pull/15](https://github.com/JuliaGizmos/AssetRegistry.jl/pull/15)  
[https://github.com/JuliaGizmos/WebIO.jl/issues/479](https://github.com/JuliaGizmos/WebIO.jl/issues/479)

---

<div class="post-metadata">

**Author:** ![TsurHerman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tsurherman/32/1234_2.png) [@TsurHerman](https://discourse.julialang.org/u/TsurHerman)\
**Post date:** [January 23, 2022, 8:56am UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/18 "2022-01-23T08:56:29Z")

</div>

There is an inherent problem with Julia design as it is now.  
I use it for anything that is a little bit more involved… and the developer experience gets worse and worse with huge start-up time recompilations, and the methods to speed that like concrete typing  
style: `struct A{T1,T2,T3}` makes the error messages I get hideous(Flux anyone?)

I used to circumvent that problem by using my port of package compiler , but recently all incremental builds fails for anything that is more than a text book example.

I pointed out in the past in this forum, that multiple dispatch should work upside-down to what is now… a dispatch table for a function should be determined by the context of the caller. thus making all binary code cacheable.

I would also in my dream language investigate [Thorin - AnyDSL](https://anydsl.github.io/Thorin.html) which uses Continuation Passing Style under the hood , which I think is the holy grail for language like Julia.  
Instead of propagating type instability during inference … resolve the instability in the point of contact and carry on compiling a type stable code.

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [January 23, 2022, 2:58pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/19 "2022-01-23T14:58:47Z")

</div>

I’m not sure I believe there is any way forward on this issue _in general_, except for the language itself to improve.

Part of the promise of Julia is that you _can_ have a high-level programming language that was also fast, as long as you internalize some idioms. If the social convention become that library authors need to profile the precise inference/compilation of the package and adjust the package accordingly, then at least to me, Julia is no longer particularly convenient in the first place, and its advantage over a static language becomes less clear.

Realistically, it just won’t be possible to create a social norm around this kind of inference whack-a-mole if it is as difficult or annoying as it is now. If there was a simple checklist to improve TTFX similar to the Julia performance tips, then maybe there could be some limited traction

Of course, nothing prevents enthusiastic _individual_ authors to take deep dives into the compilation process and improve the TTPX of their own package, especially if they’ve authored a widely used package with large latency. But this kind of individual effort for specific packages is not the same as a blanket effort affecting the whole ecosystem

By all means, do make PRs on individual packages where the latency annoys you. I just don’t see how we can meaningfully make a collective effort on this issue.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 23, 2022, 3:25pm UTC](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949/20 "2022-01-23T15:25:30Z")

</div>

Isn’t that an unnecessarily depressing take? The whack mole that you are talking about isn’t needed for many packages to be much better than they are now. There are simple improvements available in 100s of packages that have very little to do with the compiler nuances you and @TsurHerman discuss.

That’s what I’m trying to get at here. Half of the improvements are just easy, low hanging fruit, but often also things the compiler will always struggle to optimise.

For example, Interact.jl has 450 stars. Its super useful. And you can get the TTFX down by 80% in half a days work, fixing most of the JuliaGizmos packages at the same time. Probably by 90% with a few more hours.  
[https://github.com/piever/Widgets.jl/pull/48](https://github.com/piever/Widgets.jl/pull/48)

This stuff isn’t hard, its just basic profiling and type stability, with ProfileView and Cthulhu. We just have to do it, and waiting for the compiler to fix everything isn’t going to work. It wont.

I never expected to avoid this in package dev. I’ve worked on R/C++ packages and these things are trivial compared to the amount of work you need to put in to make that fast. The promise of julia is that you can do whatever you want in a script. Expecting that in package dev is a big ask.

Making it collective involves improving awareness of known TTFX pitfalls, the need to profile, and normalising that its ok to ask for help on TTFX problems like it is for performance optimisation.

I don’t know why you think we have to slave away solo and not share the experience, as I’m trying to do here, and as @ChrisRackauckas has also been doing really well from his experience.

[Next page](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949.md?page=2)
