Improving first run performance of desktop app snaps

One thing that was bugging me about running snapped desktop apps was the time it took to start the first time around, or after an update. So I’ve been looking at ways to improve performance and the results are promising.

I’ve been focusing on apps using the one of the cloud parts provided by snapcraft-desktop-helpers (e.g. desktop-gtk3, desktop-qt5, desktop-gnome-platform). I’ve mainly been focusing on snaps using the GNOME platform snap, but we should be able to get similar improvements in other modes.

These parts produce a $SNAP/bin/desktop-launch script that performs some of the operations that would usually be performed by postinst scripts on classic Ubuntu. But since the script is doing them after the user has decided to use the app, the work is more noticeable. So I started looking at what could be improved. To start with, I’ve focused on three caches desktop-launch creates:

  1. the shared-mime-info cache (this one seems to be the heaviest)
  2. compiled versions of gsettings schemas
  3. icon theme caches

In all three cases, the caches are built by postinst scripts on classic systems because each uses a cache file covering all files in a directory (or directory tree), and multiple packages may place files in the directory. For snap packages though, the directories will be in a read only squashfs, so we should be able to generate a matching cache at package creation time.

I started by updating the gnome-3-26-1604 platform snap to generate these caches as part of the package build:

This change is now live on the edge channel of the store. I then put together a PR for snapcraft-desktop-helpers to take advantage of this:

The basic changes are:

  1. If the $RUNTIME/usr/share/mime folder contains a mime.cache file, don’t bother copying and rebuilding the mime database.
  2. If a gsettings schema directory contains a gschemas.compiled file, don’t bother symlinking and compiling schemas from there.
  3. If an icon theme directory contains an icon-theme.cache file, don’t bother symlinking and generating an icon cache for it.

These changes should be backward compatible with snaps which use the parts, but give a path for snaps to avoid these steps. For snaps using the GNOME platform snap, they should immediately see some benefits simply by rebuilding once the changes to the cloud part are merged.

So what is the performance difference? Looking at just the performance of just the desktop-launch script on my desktop system (not particularly new, and no SSD), here are the before numbers for the iagno snap:

james@scruffy:~$ time bash $SNAP/bin/desktop-launch true

real	0m16.973s
user	0m0.744s
sys	0m0.894s

… and for the updated desktop-launch:

james@scruffy:~$ time bash desktop-launch true

real	0m0.301s
user	0m0.153s
sys	0m0.143s

In this case, the glib-compile-schemas is still being run to cover the app’s schemas, but not for anything in the platform snap. That’s getting to the level where it is unnoticeable.

Now it would be nice to automate some of this for snaps that are not using the GNOME platform snap, but it is not clear whether Snapcraft makes this possible. The cloud part is generally configured to run before the app’s main part, but we probably want to generate the caches based on the combined content of the stage/ directory (e.g. so that we can pick up the app’s gsettings schemas).

4 Likes

If I understand correctly, something like a yaml directive “last” which gets run after the build but before the assembly of the snap itself could work here?

The main requirement here is to be able to operate on the files staged by all other parts. This could be achieved in a number of ways:

  1. Have snapcraft support a “post stage” scriptlet, and then have a part scheduled after everything else. A “last” directive could work here, but it could also be a “before” directive.

  2. Have some step between stage and prime that can be hooked with a scriptlet. This would allow the scriptlet to be attached to the existing desktop-* parts.

1 Like

Maybe as a temporary fix we could implement some sort of status indicator. One of the biggest problems is that users think the app hasn’t even started, so they repeatedly try to launch the snap, resulting in multiple applications being opened and slowing down the first run process even more. Although a temporary fix, it would provide much more user information to help while snapcraft tries to make first-start faster.