Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider using DwarFS #36

Open
probonopd opened this issue Oct 3, 2022 · 14 comments
Open

Consider using DwarFS #36

probonopd opened this issue Oct 3, 2022 · 14 comments

Comments

@probonopd
Copy link
Member

probonopd commented Oct 3, 2022

https://github.com/mhx/dwarfs is making bold claims:

So in this comparison, mkdwarfs is more than 6 times faster than mksquashfs, both in terms of CPU time and wall clock time.
In terms of compression ratio, the DwarFS file system is more than 10 times smaller than the SquashFS file system.

It'd be interesting to do some real-world comparisons by recompressing existing AppImages in DwarFS.

Reference:

@FryingPanBrock
Copy link

I have done some informal tests on some AppImages I have lying around. MB are megabytes, not mebibytes.

Cryptomator
AppImage: 59.6 MB, 5.5 s
AppDwarf: 48.4 MB (19% smaller), 4.3 s (22% faster)

FontForge
AppImage: 42 MB, 1 s
AppDwarf: 31.2 MB (26% smaller), 1 s (same)

Inkscape
AppImage: 126.7 MB, 3.5 s
AppDwarf: 82.2 MB (35% smaller), 3.4 s (3% faster)

LibreOffice
AppImage: 270.1 MB, 4.1 s
AppDwarf: 206.3 MB (24% smaller), 3.2 s (22% faster)

qView
AppImage: 44.2 MB, 0.7 s
AppDwarf: 32.3 MB (27% smaller), 0.6 s (14% faster)

VSCodium
AppImage: 124.6 MB, 1.9 s
AppDwarf: 91.2 MB (27% smaller), 1.8 s (5% faster)

In the median case, the DwarFS image is 27% smaller and loads 10% faster. AppDwarf creates an .sh file which you cannot simply mark as executable and launch from Nautilus. Furthermore, installing DwarFS requires manually adding it to PATH. However, if DwarFS were used in AppImage, I assume you could solve these issues. Switching from SquashFS to DwarFS is a no-brainer which improves the AppImage format without drawbacks.

@probonopd
Copy link
Member Author

Thanks for your tests @FryingPanBrock. Interesting!

It would be valuable to do very systematic testing using the various zstandard compression levels and block sizes vs. DwarfFS, and then consider app size, app launch speed, zsync efficiency for AppImageUpdate, and (not so important) filesystem creation time.

Definitely something to be looked into. Maybe these tests could be scripted, unfortunately I don't have the time to do so now.

@Samueru-sama
Copy link

There is now an appimage runtime that supports dwarfs written in rust: https://github.com/VHSgunzo/uruntime

Here are some tests using the latest LibreOffice-still.basic.AppImage as reference, which still uses the old runtime and likely gzip compression.

  • libreoffice.original.AppImage being the original appimage

  • libreoffice.squashfs.zstd22.AppImage being the appimage with the new static runtime, 128K block size and zstd22 compression.

  • libreoffice.dwarfs.l7.AppImagemade running mkdwarfs -l7 which uses zstd22 by default as well iirc and then I just added to the runtime with cat ./dwarfs.image >> runtime

Here the initial benchmarks:

image

TLDR: dwarfs makes the smallest appimage at 221MiB, however it also takes longer to start, about 100ms higher than the original appimage and about 500ms slower than the appimage using the static runtime with zstd22 squashfs and 128K blocks.

It is very likely that the dwarfs settings can be changed to still make smaller images that startup faster though.

The biggest problem I see with the new runtime is that it is almost 6 MiB, which means it only comes useful for appimages bigger than 60 MiB I would say.

@Samueru-sama
Copy link

Samueru-sama commented Oct 25, 2024

Update: I here are some tests using different mksquashfs parameters instead of the defaults:

mkdwarfs -f --set-owner 0 --set-group 0 --no-history --no-create-timestamp --header runtime \
-i squashfs-root -o libreoffice.dwarfs.optimized.AppImage --compression zstd:level=22 -S20 -B9

mkdwarfs can also add the runtime instead of using cat.

image

Now it is smaller than squashfs while having about the same startup speed.


Edit: More testing with the brave appimage, this time with -S22 -B16 in dwarfs:

image

TLDR: dwarfs is 9% smaller and 21% faster

@Samueru-sama
Copy link

Samueru-sama commented Nov 15, 2024

I made 2 dwarfs appimages that use this runtime:

https://github.com/Samueru-sama/GIMP-AppImage/releases/tag/continuous
https://github.com/Samueru-sama/OBS-Studio-AppImage/releases/tag/continuous

The runtime is now fully compatible with the static type2-runtime, including updates with appimageupdatetool work perfectly.

Edit: Also these appimages bundle all the libs and the ld-*.so with sharun which makes them work on any linux system.

@FryingPanBrock
Copy link

Excellent. Your approach is even immune to the “missing GLIBC x.y.z” errors which plague so many AppImages created now, contrary to the philosophy of packaging Windows-style widely compatible software that works forever. Writing this from Ubuntu 20.04.6 LTS. Using dwarfs with your approach looks obviously better.

@probonopd
Copy link
Member Author

probonopd commented Nov 16, 2024

Hi @Samueru-sama

Not entirely sure how exactly this userland-execve magic is working but I have to say it is working nicely on Windows 11 WSL2 with Debian 👍

image

@Samueru-sama
Copy link

Not entirely sure how exactly this userland-execve magic is working

sharun is just a binary that you symlink to inside the AppDir and based on the name of the symlink it will find the ld-*.so and call the binary in ./shared/bin while passing every single directory that contains libraries to --library-path when calling the ld-*.so. This means that when hardlinks get used /proc/self/exe is the name of the binary instead of ld-*.so, and since every single directory with libraries gets passed down with the --library-path flag there is no need to use patchelf to set rpaths.

It also sets several env variables on its own if it detects certain directories that need them in the AppDir.

Excellent. Your approach is even immune to the “missing GLIBC x.y.z” errors which plague so many AppImages created now, contrary to the philosophy of packaging Windows-style widely compatible software that works forever. Writing this from Ubuntu 20.04.6 LTS. Using dwarfs with your approach looks obviously better.

This approach is something that began with go-appimage as far as I know, however note that you don't need dwarfs in other to make appimages that work on any linux system, you can see some other appimages that I made that work on any linux system here, not all use sharun either.

@probonopd
Copy link
Member Author

probonopd commented Nov 16, 2024

@Samueru-sama does your sharun approach work with applications that need GLX, like https://github.com/AlbrechtL/welle.io/?

Reference:

@Samueru-sama
Copy link

Samueru-sama commented Nov 16, 2024

@Samueru-sama does your sharun approach work with applications that need GLX, like https://github.com/AlbrechtL/welle.io/?

Reference:

* [Fatal: Could not initialize GLX probonopd/go-appimage#301](https://github.com/probonopd/go-appimage/issues/301)

Yes, you can see it in the OBS Studio AppImage I bundled the gpu libs and set __EGL_VENDOR_LIBRARY_DIRS

The deploy script that sharun uses an script, named lib4bin has a mode that uses strace to get all the libraries that get dlopened and copies them to the AppDir.

I used it in the OBS AppImage because otherwise I was getting incompatible mesa errors when testing it on alpine linux.

The only downside is that this means the application has to launched in the CI, although it was as simple as using xvfb-run to simulate a working display.

@probonopd
Copy link
Member Author

@Samueru-sama I am really becoming a fan of your approach. Do you think you could build welle.io on Alpine Linux and then bundle it with your approach? That would be a killer demo 💯

@Samueru-sama
Copy link

@Samueru-sama I am really becoming a fan of your approach. Do you think you could build welle.io on Alpine Linux and then bundle it with your approach? That would be a killer demo 💯

image

I used the following script on Artix linux, use the well-io aur package binaries instead of compiling it:

#!/bin/sh

set -eu

PACKAGE=welle.io
DESKTOP=welle-io.desktop
ICON=welle-io.png

export ARCH="$(uname -m)"
export APPIMAGE_EXTRACT_AND_RUN=1
export VERSION="$(pacman -Q $PACKAGE | awk 'NR==1 {print $2; exit}')"

APPIMAGETOOL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$ARCH.AppImage"
UPINFO="gh-releases-zsync|$(echo $GITHUB_REPOSITORY | tr '/' '|')|continuous|*$ARCH.AppImage.zsync"
LIB4BN="https://raw.githubusercontent.com/VHSgunzo/sharun/refs/heads/main/lib4bin"

# Prepare AppDir
mkdir -p ./"$PACKAGE"/AppDir/shared/lib \
	./"$PACKAGE"/AppDir/usr/share/applications \
	./"$PACKAGE"/AppDir/etc
cd ./"$PACKAGE"/AppDir

cp -r /usr/share/welle-io   ./usr/share
cp -r /usr/share/locale     ./usr/share
cp -r /usr/share/glvnd      ./usr/share

cp /usr/share/applications/$DESKTOP              ./usr/share/applications
cp /usr/share/applications/$DESKTOP              ./
cp /usr/share/icons/hicolor/256x256/apps/"$ICON" ./

ln -s ./usr/share  ./share
ln -s ./shared/lib ./lib

# ADD LIBRARIES
wget "$LIB4BN" -O ./lib4bin
chmod +x ./lib4bin
xvfb-run -d -- ./lib4bin -p -v -r -e /usr/bin/welle-*
rm -f ./lib4bin

# DELOY QT
mkdir -p ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/iconengines       ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/imageformats      ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/platforms         ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/platformthemes    ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/styles            ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/xcbglintegrations ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/wayland-*         ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/plugins/qml*              ./shared/lib/qt6/plugins
cp -r /usr/lib/qt6/qml                       ./shared/lib/qt6

ldd ./shared/lib/qt6/plugins/*/* 2>/dev/null \
  | awk -F"[> ]" '{print $4}' | xargs -I {} cp -nv {} ./shared/lib || true

find ./shared -type f -exec strip -s -R .comment --strip-unneeded {} ';'

# Prepare sharun
ln ./sharun ./AppRun
./sharun -g

# MAKE APPIAMGE WITH FUSE3 COMPATIBLE APPIMAGETOOL
cd ..
wget -q "$APPIMAGETOOL" -O ./appimagetool
chmod +x ./appimagetool

./appimagetool --comp zstd \
	--mksquashfs-opt -Xcompression-level --mksquashfs-opt 22 \
	-n -u "$UPINFO" "$PWD"/AppDir "$PWD"/"$PACKAGE"-"$VERSION"-"$ARCH".AppImage

mv ./*.AppImage* ../
cd ..
rm -rf ./"$PACKAGE"
echo "All Done!"

And here is the appimage if anyone wants to do a quick test

@probonopd
Copy link
Member Author

probonopd commented Nov 16, 2024

This is what happens with Debian on Windows 11 with WSL2:

image

@Samueru-sama
Copy link

Samueru-sama commented Nov 16, 2024

I just booted an ubuntu 20.04 vm to test it:

image

And here is on a voidlinux musl vm:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants