Plans for static compiled binaries?

Dear Julia Developers,

Is static compilation currently on the development roadmap for Julia? Any information on its progress or plans would be appreciated.

I am asking this because my use case is typically delivering bioinformatics tool to biologists that may incorporate it into some pipeline like Snakemake or Nextflow to process many files and then JIT overhead is considerable. Another usecase is deployment size and speed for something like application running on a node or hosting website. Although last one is not my usecase yet but it I think static compilation that is easy for developer would be beneficial. I know there are tools like SnoopCompile that may help with lattency, but they introduce some learning curve and are not as straight forward as just full static compilation. This may deter users that just want to deliver a program to less technical people in a team.

Thank you!

2 Likes

You’ll find some relevant information from this years “State of Julia” talk at JuliaCon

5 Likes

https://www.reddit.com/r/Julia/comments/17tot82/comment/k8yefy6/?utm_source=share&utm_medium=web2x&context=3

5 Likes

Does PackageCompiler.jl cover your use case?

I am sorry I didn’t mention this, regarding partial compilation I do use PackageCompiler but it’s still producing bundle that needs JIT and Julia and is not true static compilation. That does have relatively large JIT startup overhead compared to Python script doing the same processing in a pipeline. Further more that results in rather big in size bundles and shipping a bundle is more complicated for end-users than shipping single binary.

2 Likes

EDIT: There’s very recent [ANN] AppBundler.jl - Bundle Your Julia GUI Application - #5 by Janis_Erdmanis

If I recall this video explained how to get one file (an installer I guess), i.e. with additional tools(s) after:

See also, this works, but not yet on Windows, that limitations is worked on being lifted. There are still others, and if this works for you then the binary is tiny:

1 Like

Not having tried PackageCompiler.jl myself (but expecting to use it in a project soon), I thought precompilation removed the jit-lag, and that the main drawback compared to full static compilation was that the distributed file is much larger.

It’s partial compilation, as Julia is partially compiled language I think. Meaning that what can be compiled it is, but some stuff still might be JIT compiled. Unless you use SnoopCompile, I don’t think PackageCompiler can on its own eliminate all lag. Maybe I am asking too much from a language because now when I think about it, there is no way for compiler to know all types in advance. But I haven’t had time yet to watch the JuliaConf talk posted earlier which maybe covers some of that. But having single runnable file would already be nice, so I will definitely look at YouTube movies posted earlier. It’s just such a format that requires time to watch, and it’s hard to search, so I am kind of looking like ingorant for the moment not being able to watch these yet, but I will definitely watch these thanks!

1 Like

Julia is fully compiled in the sense all can be compiled. But sometimes it happens at runtime, yes (never strictly needed; for most code)

You can in some cases remove the LLVM dependency (back-end of the compiler), to very much reduce the compiled app size. It’s a very large dependency, the largest if I recall. You can remove more, maybe OpenBLAS, at least it should be possible if not right now.

But what then if you try to compile at runtime? Then your code will fail at runtime… not good, so you must be pretty sure that does not happen.

Since Julia also has an interpreter, then in that case such code could be run with --compile=min at least in theory. And since it’s much slower (even slower than Python, then make sure it’s not done for speed-critical code. 90% of code isn’t.

What you can do and I believe is not the default is use these (from doced with–help-hidden …):

 --strip-metadata         Remove docstrings and source location info from system image
 --strip-ir               Remove IR (intermediate representation) of compiled functions

This shouldn’t matter if your code is precompiled (but would if not fully compiled?), then the latter likely adds some fixed one-time latency per functions that aren’t fully compiled.

Both should make your app smaller, and faster. If you don’t have source code, I think you don’t (the point of compiling), nor the IR, then it seems you can’t compile further at runtime, e.g. for types you didn’t think of.

Some of Julia’s compiler is written in Julia, i.e. the frontend (and part of the optimzer?), and you should be able to drop it. Julia has a new parser, JuliaSyntax.jl and it’s bundled with. I’m not sure it’s dropped by default, maybe it should be. In theory you can include files at runtime. I think all code should be pre-parsed even if not precompiled, so should be safe, except in extreme cases (so likely not done). The legacy parser flisp is still there. I think it could be dropped, but likely not done… The focus should be on the largest dependencies first, though it might be a low-hanging fruit.

I think we should discuss PackageCompiler.jl further.

Importantly, you must provide a comprehensive workflow script so that Julia can figure out what to compile. You can then disable JIT and remove the compiler. This workflow must then explore all brnaches.

For a different approach see the following, which is much more limited:

1 Like

I think there are many programs that will simply accept a small number of types, likeInt and Float64, and that covers everything.

2 Likes

It fundamentally depends on you use case. If there’s a possibility that your program eventually encounters an unknown type - or tuple of types - then yes.
Conversely, if you (yourself) know in advance what concrete types you’ll need (say, for a web service for which you have established your own OpenAPI specification, executing some well-known services), then PackageCompiler.jl can meet your needs.

If you look at your problem in a logical, general way, then you’re totally right. Combinatoric is tricky. But in your case, the question that actually matter is, can you establish the subset of all the type tuples that you’ll encounter? My safe bet (i.e. >50% chance) is that yes, you can.

1 Like

I am just looking for a solution that won’t require a degree in compiler engineering, but without any limitations, such that produce code if fast. I mean like in Rust, compile and done.

2 Likes

This does not exist yet in Julia, probably won’t exist for at least a year, and it’s still an open question how it will end up working out in the end. For the next couple of years, I recommend using a static language like Rust if you want a static binary.

That being said, I’m also working on a bioinformatic tool in Julia. For this, I’m using Comonicon.jl, and this is the latency I currently have on Julia 1.10.0:

$ time binbench bench files/ref.json files/clusters.tsv > /dev/null
binbench bench files/ref.json files/clusters.tsv > /dev/null  1,08s user 0,48s system 133% cpu 1,168 total

Which is acceptable for my use case, even in a Snakemake workflow.

9 Likes