Starting GLMakie takes very long

Hi,
I am getting started with Makie. The functionality is cool. However I am really annoyed by the startup time:
It takes over a minute to open the first plot in GLMakie. After that plotting works instantly, but the startup time occurs after each restart of julia. This is on both manjaro and fedora.
Is this normal? Or have I missconfigured something? What is happening during the startup time?

This is unfortunately normal (over a minute is more than what I experience but I assume it can vary depending on your hardware).
You are suffering of one of Julia’s most known pain points. In short: Julia is a compiled language, but compilation occurs the first time you run a function. With huge and complex codes like that of Makie, this first compilation takes a very long time (other plotting packages suffer from this because it is a very complex process). This problem is commonly known in the community as the “Time To First Plot” problem, but it can affect any type of program, not only the plotting ones.
Because julia does not save compiled code, when you start a new session, everything has to be compiled again.

1.- I know Simon (the main developer at Makie) is working on some refactoring of the code to make it a little more efficient but there is so much going on that it is difficult to know when things will change.
2.- A way of saving a compiled state is by creating a julia image that includes the compile code from Makie, check Home · PackageCompiler . However, Makie gets a lot of updates very frequently, so I don’t necessarily think this is the greatest of ideas.
3.- What most people do is try to keep your sessions open for a long time to try and mitigate the recompilation of all packages.

3 Likes

Hmm, that’s a bit sad… Wouldn’t it be great to have a “standard” way to precompile a Julia so that its image is loaded when imported instead of the current way?
How big are the technical limitations to do so right now?
You can’t load multiple images dynamically load an image now, right?

But I am afraid this really is a huge problem to the Julia language. It really has great and elegant functionality, but nowadays nobody wants to wait a minute to view a graph of sin(x).

The “standard” way is PackageCompiler.jl, and while it’s not especially ergonomic, it works just fine. This sort of image-loading is already used when starting the REPL for a snappy user experience for things like history & documentation search.

Makie.jl probably has the largest plot latency out of any of the plotting libraries at the moment (in large part because it’s pure-Julia, which increases the load on Julia’s compilation toolchain). Plots.jl, InspectDR.jl, PGFPlotsX.jl, and other options should be considerably faster.

The technical barriers to improving startup latency are both steep and well-known - see this series of blog posts for an intro for what’s already being done to improve the user experience:

Several members of the core developer team are working on further reducing TTFP, and Tim Holy’s running a workshop at the upcoming JuliaCon to help disseminate his knowledge on how to drive down latency across the language ecosystem.

No plotting package is pure Julia (well probably except UnicodePlots)

True, but when you’re down to 89% Julia and 10% OpenGL shading language, that’s about as close as anyone’s going to get (until some brave fool writes a GPU driver in Julia)!

2 Likes

… not counting the (likely) thousands of C lines of OpenGL itself.

1 Like

So is it possible to add your own packages to this “precompiled startup procedure”?
And how about loading multiple images and loading images dynamically in the repl?

Hi,

Note that this strongly depends on what you are doing and on the workflow. I use a lot Makie (without specific Image) and It is not a major issue… for me.

Exactly : most of the time, I work in the same Julia session for hours (thanks to Revise.jl) and, this first time to plot is not more problematic (for me) than waiting for a Matlab session to start (Video : Julia setup for beginner).

1 Like

Take a look at

if you use VSCode as your IDE then
brute_build_local()
is what you need, otherwise you can use
brute_build_julia()
to replace the original sysimg(system image - the compiled code loaded at startup)
but it is more likely to mess-up your julia installation(in that case you’ll have to re-install julia).

1 Like

It’s of course important that latency is improved on the language level, but this improvement is incremental and there’s still a long way for perfection.

PackageCompiler.jl has the potential to offer a drastic improvement, but it’s hard to use. There are different ways it can be used, they are configured differently, and they require quite a lot of manual steps.

If there would be a much simpler way to create an image for a project, it would be a lot simpler to use, and it could be more readily be offered to anyone. I’m hoping for a fully automated building of a startup image for a project with no manual steps, possibly including a couple of command line instructions.

1 Like

Ideally adding packages to your sysimg would be integrated with Pkg (or a similar REPL interface), and you would just have to do ]compile GLMakie or something like that to add it.

2 Likes

This is basically solving the time to first plot problem for most people. With Revise.jl, I would say that Julia is more quick for development than other languages, because you can keep everything running even when you change your code.

1 Like

This is exactly what I imagined and I am afraid it is also necessary to get julia further. I am right now trying to convince my university to switch to Julia and it is really hard to argue for it if startup of each package takes so long. Of course you can keep the repl open for hours. But just imagine someone who has never been programming before. If a command takes a minute to run, they will be intimated and wondering what’s wrong. And if you then tell them they just have to run some commands and always start Julia with some weird flags and load a custom image to fix it, they will want to switch back to Matlab.

We really need a simple solution to precompile packages and dynamically load the precompiled version. And probably the problem will only get worse with more advanced packages in the future.

Just FYI, since you appear to be rather new to Julia, this is indeed an extremely well known issue for which countless man-hours have gone (and will continue to go!) towards. Your concerns are completely valid, and shared by many (google “Julia time to first plot” and you will find many likeminded people), but I’m afraid there isn’t much more to be said that hasn’t already been said. Do note, however, that it is getting better with every new Julia version! I assure you they are trying their best :wink:

4 Likes

That’s true… So let’s hope the team will perform as incredibly well as it did in the past years!

2 Likes

One reason why Makie is so bad with this, is that some of the data structures it uses are chosen for maximum flexibility, but that also means many many type instabilities and therefore longer compilation, more invalidation, etc. In Python, such a design would not be a big problem but kind of the norm. Julia is not really made for the deliberate use of untyped containers etc, rather it tries to give you lots of options to avoid those. Plotting is just not like a computational workflow, where you pick a set of types to use and compile everything perfectly with those, rather the plotting software has to interface with almost every type that’s out there, and be iteratively changeable at any point.

1 Like

@jules What is your experience with the nothing 's? I also struggle with that balance between versatility and type stability/compilation-time in GMT. I use many input args that default to nothing but then @code_warntype puts reds ({Any}) everywhere.

Out of curiosity, how long does it takes to start a Matlab session nowadays ?

For us it’s not so much about nothings, but about plot attributes that are all of type Observable{Any}. So any time a plot attribute is accessed, that is a type instability. But what common type could :red, "red", RGBAf0(1, 0, 0, 1) etc have if you don’t immediately convert them?

1 Like