# Invalidating sysimages?

**URL:** https://discourse.julialang.org/t/invalidating-sysimages/53922
**Category:** Performance
**Tags:** package-compiler, sysimage
**Created:** [January 25, 2021, 6:16pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922 "2021-01-25T18:16:23Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![airpmb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/airpmb/32/7826_2.png) [@airpmb](https://discourse.julialang.org/u/airpmb)
#### Post date: [January 25, 2021, 6:16pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/1 "2021-01-25T18:16:23Z")

</div>

If I’m not mistaken if you use a custom sysimage and then make any changes to any of the packages included in said sysimage, then these won’t be reflected in any Julia sessions where you use that sysimage. What I’m wondering is whether if there is any way to detect such ‘invalidations’ of the sysimage. So kind of thinking of the sysimage of something of a cache.

If not currently possible is there a way to get there? I’m thinking something like including some kind of hash of the package sources that went into creation of the sysimage.

And kind of a related question, is the sysimage necessarily monolithic? Or can it be decomposed into some number of parts, such as by package, such that ideally if one package in an environment that was used to create the sysimage was updated, just that part of the sysimage could be recreated?

---

<div class="post-metadata">

### Author: ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)
#### Post date: [January 26, 2021, 9:32am UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/2 "2021-01-26T09:32:17Z")

</div>

Not exactly what you’re mentioning, but this PR is at least related and the discussion in it might be interesting to you:

> <https://github.com/JuliaLang/julia/pull/35794>
>
> With this patch, you can do
> 
> \`\`\`
> (@v1.x) pkg\> activate .
> 
> julia\> Base.set\_s…ysimage\_path("PATH/TO/sys.so")
> 
> julia\> exit()
> 
> $ julia --project=. # implicitly use -J=PATH/TO/sys.so
> \`\`\`
> 
> To use \`julia\` with project-specific system image.
> 
> \### Implementation/design
> 
> Given \`--project=$projectdir\`, \`julia\` binary tries to read the text file \`$projectdir/.julia/sysimages/$slug.path\` and use its content as the default \`--sysimage\` argument. The \`$slug\` is computed from the path of \`julia\` binary. This way, it is safe to use multiple \`julia\` binaries with the same project.
> 
> (Edit: it was pointed out that including \`VERSION\` in \`slug\` as well might be a better idea https://github.com/JuliaLang/Pkg.jl/issues/2008#issuecomment-687847827)
> 
> This PR does not store the system image directly at \`$projectdir/.julia/sysimages/$slug.$dlext\` because the system image is rather large and it is nice to be able to use the same system image in multiple projects without copying the image file itself. Furthermore, it may make sense to distribute pre-compiled system image using the artifacts mechanism. It then is desirable to load system image directly from artifacts datastore rather than in \`$projectdir/.julia/sysimages\`. Note that symbolic link is not a good option for supporting Windows.
> 
> @staticfloat suggested to use triplet instead of \`$slug\` https://github.com/JuliaLang/julia/issues/33973#issuecomment-601505588 but this means to re-implement triplet detection in C. Furthermore, I don't think it is enough for supporting other variations of \`julia\` (e.g., debug build, different versions). Hashing the path of \`julia\` binary seems to be a simple robust solution.
> 
> \---
> 
> If the design is good, I can add some tests. Also, since I'm not a C programmer, I may be doing something stupid. Let me know if there is a better way to implement this.

One [interesting point](https://github.com/JuliaLang/julia/pull/35794#issuecomment-691175857) made by @tkf is the following:

> […] note that everything _[i.e. the process of detecting the correct sysimage to use, note by me]_ has to be implemented in C (or C++ or scheme) because we can’t use Julia before loading the system image [^1]. So, that’s why I’m shooting for a very simple and flexible interface in this PR.
> 
> [^1] OK, technically, we can do this in a subprocess or maybe even re-initializing Julia runtime is possible? But it sounds very tricky and fragile to me.

  

More directly related to your question, I’ve tested something like what you mention in order to build & invalidate system images in `eglot-jl`. In order to have this in Julia, I used the workaround mentioned by @tkf in the above mentioned comment: everything related to sysimage detection is performed in a preliminary Julia process, which then starts a new Julia process with the correct sysimage. The relevant PR is not (yet?) merged, but I’ve used it on a daily basis for the last few months without trouble, which I think validates the practical usefulness of the approach.

> <https://github.com/non-Jedi/eglot-jl/pull/12>
>
> The following PR introduces features helping compile and use custom system image…s for LanguageServer and SymbolServer. The expected benefits are reduced start-up times for the language server. On my (old-ish) machine, start-up times are reduced from 20 seconds to less than 2. On a newer machine where I also tested this, times went from 15 seconds down to less than 1.
> 
> The idea is the following:
> \- \`eglot-jl.jl\` looks at the \`EGLOT\_JL\_TEST\` environment variable; when it is set, the server is configured to read from an IOBuffer that sends it an \`exit\` instruction as soon as it is able to process requests. This allows \`eglot-jl.jl\` to be used as a \`precompile\_execution\_file\` that exercises the (language) server before gracefully exiting.
> \- a \`compile.jl\` script automates the generation of a system image, named after the julia version (and having the relevant extension depending on the OS).
> 
> This is what the first commit in this PR introduces, alongside with instructions in \`README.org\` explaining how to compile the system image, and set \`eglot-jl-julia-args\` to use it.
> 
> The second commit goes a step further: it automates the search for a suitable system image at server startup, in order to use it if one is found.
> \- a first call to julia allows getting the version number. This involves something like 0.1s additional latency before the server is run, which I think is acceptable but is nevertheless quite a large amount of time for such an insignificant-looking task
> \- a suitable system image is looked for, based on the version number; if one is found, the corresponding \`--sysimage\` command-line switch is generated. If not, nothing happens; no system image is used, so users who have not generated any system image will not be impacted by this.
> \- the whole process handling system images can be deactivated using a new \`eglot-jl-enable-sysimage\` customizable option. This allows users to opt out of the system, even if they have previously generated a system image (for example in case it would become stale for some reason). It also completely removes the julia version overhead.
> 
> Additionally, a new autoloaded command allows running the system image generation script from within emacs. The same command could be used to re-generate a system image if the previous one caused problems for any reason.
> 
> This is documented in \`README.org\`. I've tested this with Julia 1.3 and 1.4, on Windows and Linux, without encountering any problem (I don't have access to a Mac).
> 
> I know you were reluctant to handle system images in \`eglot-jl\`, and were (rightfully) especially concerned about possible ways that a system image would become obsolete. I tried making this implementation as robust as possible, but I might very well have overlooked something. So please do not hesitate to tell me if something bothers you with this proposal.

However the whole system is indeed a bit fragile; it works well in this case, but only because in `eglot-jl` we completely control the environment we want to work in, and the command-line flags provided to Julia. I wonder if such a technique could be robustly implemented in a more general context, but unfortunately I’ve never really taken the time to think it through…

  

In any case, I’m looking forward to reading what others have to say about this!

---

<div class="post-metadata">

### Author: ![airpmb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/airpmb/32/7826_2.png) [@airpmb](https://discourse.julialang.org/u/airpmb)
#### Post date: [January 29, 2021, 8:07pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/3 "2021-01-29T20:07:37Z")

</div>

Thanks, those are some useful pointers. It sounds like there’s some work ongoing that in the longer term can really improve sysimage workflows.

In the meantime I think what I might try is a simple experiment in my own package with at script that saves a snapshot of Manifest.toml as it was when I ran PackageCompiler last and if there has been a change it will re-run PackageCompiler.

It’s actually so simple that I suspect others are already doing this but I might be missing some nuance… OTOH I also wonder whether any and all changes to Manifest.toml should trigger a rebuild or only packages that I list in the call to `create_sysimage`.

---

<div class="post-metadata">

### Author: ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)
#### Post date: [January 29, 2021, 8:16pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/4 "2021-01-29T20:16:32Z")

</div>

It looks like the Julia VSCode extension does it based on timestamps: [julia-vscode/repl.ts at b7a8b6b3fa838a64715f2315d634f2d9d09f79c9 · julia-vscode/julia-vscode · GitHub](https://github.com/julia-vscode/julia-vscode/blob/b7a8b6b3fa838a64715f2315d634f2d9d09f79c9/src/repl.ts#L197)

But they always use all packages in the environment to build the sysimage. I think the right set to watch is the packages you pass to create the sysimage, and all of their dependencies (and their dependencies, etc).

---

<div class="post-metadata">

### Author: ![airpmb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/airpmb/32/7826_2.png) [@airpmb](https://discourse.julialang.org/u/airpmb)
#### Post date: [January 29, 2021, 9:08pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/5 "2021-01-29T21:08:51Z")

</div>

Thanks. Mostly though I don’t run from within VS Code–and it looks like that is only for the REPL in VS Code?

At any rate, just so I actually have some transparency to what’s going on–and also, IIUC, not updating the sysimage will just silently cause much confusion down the road–for now I’m going to try rolling my own script.

---

<div class="post-metadata">

### Author: ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)
#### Post date: [January 29, 2021, 9:13pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/6 "2021-01-29T21:13:16Z")

</div>

Oh yeah, I didn’t mean to suggest you should re-use their code (which is in typescript anyway), I just wanted to provide some support to the idea that others are already doing it for various uses 🙂. The VSCode extension does it so you can ask it to compile a sysimage through the UI and it knows when to invalidate it, and automatically start the REPL with that sysimage.

I think it makes sense to roll your own script for now, though hopefully at some point there is more tooling built up around it. In fact, hopefully at some point the package manager itself can be aware of when sysimages are invalidated by changes to the project ([https://github.com/JuliaLang/Pkg.jl/issues/2008](https://github.com/JuliaLang/Pkg.jl/issues/2008)).

---

<div class="post-metadata">

### Author: ![airpmb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/airpmb/32/7826_2.png) [@airpmb](https://discourse.julialang.org/u/airpmb)
#### Post date: [January 29, 2021, 9:23pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/7 "2021-01-29T21:23:40Z")

</div>

> [@ericphanson](#):
>
> hopefully at some point the package manager itself can be aware of when sysimages are invalidated by changes to the project ([Proposal for more first class handing of sysimages in Pkg · Issue #2008 · JuliaLang/Pkg.jl · GitHub](https://github.com/JuliaLang/Pkg.jl/issues/2008)).

Yes I’m particularly excited for that to come about!

So a related thing I’m wondering: Is there a way to determine what packages (modules?) are worth including in the `create_sysimage` call? I mean I guess I can just list every single package in the manifest but over time I’ll start to accumulate packages that I don’t always use.

I’m also still not quite clear on under what conditions I should definitely update the sysimage. For example, do I need to worry about transitive dependencies or do these show up in the manifest as changes anyway? Are there any changes that would not show up in Manifest.toml yet would invalidate a custom sysimage in some way?

---

<div class="post-metadata">

### Author: ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)
#### Post date: [January 29, 2021, 9:46pm UTC](https://discourse.julialang.org/t/invalidating-sysimages/53922/8 "2021-01-29T21:46:09Z")

</div>

> Is there a way to determine what packages (modules?) are worth including in the `create_sysimage` call?

I think it’s a bit of a balancing act, because you are locking in those versions, so updating them means waiting for a sysimage rebuild. So I think it’s good for packages you use often but are fairly stable and you don’t often need to update them (or their (transitive) dependencies!). I used to use a sysimage for plotting with Makie.jl, but it’s still in a state of active development and I end up updating a lot, and so I stopped using one. At my work, we also use sysimages in docker images, to package up a piece of code and have it start quickly. There we just put everything except for `dev`’d dependencies into the sysimage (i.e. everything except for the code we’re actually working on).

> do I need to worry about transitive dependencies or do these show up in the manifest as changes anyway?

Yeah, changes to transitive dependencies will show up in the Manifest.

> Are there any changes that would not show up in Manifest.toml yet would invalidate a custom sysimage in some way?

Hm, changing the Julia version would do that, but I can’t really think of anything else.
