Any syntax to specify whether a function should or should not be compiled?

I’m converting from Matlab (and some Python) to Julia. Honestly the time-to-first-plot issue of Julia really bothers me frequently. I almost never plot anything in Julia for that reason; instead, I save my (not so large) results to files, then load them up in Matlab or Python to plot. I am currently using a package for my computation needs, but that package also defines some convenient plotting functions based on Plots.jl, which I never use. Every time I need to load that package, it takes ages. When developing computation code and changing a function, sometimes I just want to quickly test if the code works correctly, but have to wait for it to be (re)compiled.

I’m aware of several ways to alleviate the issue (e.g., keep using one session, Revise.jl, Julia Interpreter, -O0, --compile=min, PackageCompiler), but none is perfect. For example, with -O0 and --compile=min the packages are loaded more quickly, plotting may be faster, but my computation code will be much slower.

My main question: Is there any way (syntax) to specify whether a function should be compiled or not (i.e., executed by the interpreter instead)? This is more like a preference than a strict constraint. For instance, in the definition of function myfun I can flag that it should be compiled or not (there will be a default, e.g., determined by --compile=). If myfun is flagged as “compiled” it will always be compiled; if it is flagged as “not compiled” it will always be interpreted. That flag can be changed during run time, probably by a Julia base function. For example, if myfun is originally “not compiled” but at some point I really need it to run fast, I can switch it to “compiled” then the next time it’s called, it will be compiled. After myfun has been compiled, if I switch it back to “not compiled” the compiled version will still be used unless myfun is changed. This flag can even be made a weight number, let’s say 0 means “never compiled”, 9 means “always compiled”, and 1 to 8 means the function will be compiled after being called frequently “enough” (how frequent is enough depends on the weight).

Usage: a developer can decide how a function should be compiled or interpreted. For example, most plotting and displaying functions can be “not compiled” for responsiveness, while computationally intensive functions are always compiled. When I am developing my computation code, I can start with “not compiled” so that I can quickly test it, but once it’s done, I can switch it to “compiled”.

2 Likes

Perhaps @nospecialize.

See When should we use `@nospecialize`?

@jameson did an experiment with allowing annotation of methods with whether they should be specialized or not and it disappointingly did not help as much as one would hope. I believe the issue is that this is not really a property of the function being called, but of the calling context. You may not care about an operation being fast when it’s part of a slow top-level routine that’s only called once, but the same operation may also be used from other contexts where you do want it to be fast. Perhaps he can write a bit more about why that experiment didn’t pan out as well as hoped.

1 Like

Not exactly what I was thinking about. As I understand, a function with @nospecialize still gets compiled, just not specialized. What I think could be helpful for responsiveness (not performance) is to allow a function to be explicitly specified as “not to be compiled but interpreted (unless it’s already been compiled earlier).” Those are functions where performance is not very important but responsiveness is (for example user-interfacing functions, like plotting). As I wrote, compilation for those functions can still be switched on if desired. I may be wrong though, since I’m not a Julia expert by any means. I just hope there is a way to trade off between performance and responsiveness, as I’ve seen quite a few colleagues (Matlab, Python, R users) were put off by how long it takes to load a Julia package and to run a function for the first time (especially plotting). I myself like Julia a lot, but have frequently decided to use Matlab or Python instead due to this issue.

2 Likes

As I understand it, in regular Julia all functions are compiled - there is no interpretation happening unless you explicitly use the recently available package JuliaInterpreter.jl.

Which julia version are you running? I’ve found that for my use cases, more recent versions are much faster when loading packages and compiling code than in e.g. julia 1.0.

I am surprised that you find that workflow more convenient. Generally, plotting is rather fast for me these days, but I use PGFPlotsX.

Which version of Julia are you using? Have you considered other plotting packages, eg using GR.jl directly? It is rather fast, first plot in a few seconds.

4 Likes

GR is indeed fast, much faster than Plots.jl. I think many/most new users install and try Plots.jl (because on the Julia language website, it looks like the default / standard plotting package for Julia) and are immediately put off by how slow it is. Thanks!

1 Like

given that there is a plan to replace Plots with Makie, and that there are alternative plotting packages (e.g. Gadfly, VegaLite, PyPlot, PGFPlotsX), some of which are faster (GR), i would suggest renaming Plots to something which doesn’t confuse newcomers into thinking it is the recommended package.

in my mind, such general names like this should never be allowed to be grabbed in the first place. other packages are suspect here too, like Images, WAV, Distributions. at least in those cases there are no alternatives.

full disclosure: i am a Gadfly maintainer.

I’m not sure that really constitutes a plan, more of a hope. Furthermore, it’s my understanding that the referenced hope seems to be on pause at best since Makie’s main developer hasn’t been working on it in a while now due to his commercial venture.

1 Like

I think Makie is not a good candidate to solve time to first plot issues for anybody right now, I think the hope there is that at some point we can compile packages once and cache them until they need to be updated. It’s just too much Julia code in such a package to ever quickly compile on demand I’d say. The good thing is that from a certain level down the types shouldn’t change no matter the input, so it can behave rather like a static library there.

Also it is actively in development, even if the pace has slowed down. Replacing Plots is still a very tall order, my personal goal (also with MakieLayout.jl) is just to have it as usable and nice as possible for interactive plots, which is something that most other packages are understandably bad at.

3 Likes