Reduce initramfs size and speed up the generation in Ubuntu 23.10

Abstract

Supply the kernel modules and firmware files pre-compressed and do not re-compress them in the
initramfs to make booting faster and the initramfs smaller and faster to generate.

Rationale

An initramfs contains a temporary root file system to be used during boot. It contains everything that is needed to find and mount the root file system of the host (e. g. NVMe in a laptop). The initramfs needs to include all potentially required kernel modules and firmware files. This also includes USB and graphics drivers (in case the user has to enter a password to decrypt the root partition).

The initramfs should be small and fast to boot. Creating the initramfs should be not too slow and must not need more memory than the system has.

The initramfs can be compressed (e.g. with xz, lz4 or zstd). Picking the default compression type and level depends on the hardware it runs on. The slowest hardware with the lowest amount of memory dictates what can be used. Starting with Ubuntu 22.04, the default compression is zstd -1, because zstd -19 was too slow (it took more than an hour on a Nezha development board). That leads to bigger initramfs sizes that triggered other bugs. Big initramfs sizes can also easily fill small-sized /boot partitions (grooming the 850 initramfs-tools bugs revealed several such reports).

Specification

Ship the kernel modules and firmware files zstd-compressed (LP: #2028568 and #1942260). The Debian build machines are powerful enough to compress the files with zstd level 19. Change initramfs-tools to not re-compress compressed kernel modules and firmware files (LP: #2028567). This is done by putting the compressed files into a separate cpio archive that is not compressed. The remaining files are put into a separate cpio archive that is compressed (default zstd level 2) and concatenated.

When generating the initramfs, most time is spent in the Bash auto_add_modules function. Replacing the Bash code with dracut-install reduces the execution time significantly (LP: #2031185).

A further improvement is to avoid storing the intermediate main cpio archive on disk.

Distribution upgrade

To ensure reliable dist-upgrades in case of partial upgrades or upgrade failures, backport support to tolerate zstd-compressed firmware files to the Ubuntu 22.04 “jammy” kernels. initramfs-tools in jammy supports zstd-compressed kernel modules but not zstd-compressed firmware files. Therefore, the zstd-compressed firmwares declare breaking the old initramfs-tools.

Benchmark results

To evaluate the impact of the change, there are three different aspects that can be measured: the size of the generated initramfs, the time it takes to generate the initramfs, and how fast the system boots. To put those values into perspective, measure the system before the change (Ubuntu 22.04 LTS “jammy” and Ubuntu 23.04 “lunar”) and afterwards (Ubuntu 23.10 “mantic”).

initramfs size

test distro kernel size / bytes size / MiB uncompressed size / bytes uncompressed size / MiB
amd64 minimal jammy 5.15.0-83.92 62762675 59.9 198801710 189.6
amd64 minimal lunar 6.2.0-32.32 66729453 63.6 223378396 213.0
amd64 minimal mantic uncomp¹ 6.5.0-5.5 62302654 59.4 205924538 196.4
amd64 minimal mantic 6.5.0-5.5 55326431 52.8 64224628 61.2
amd64 full jammy 5.15.0-83.92 112782161 107.6 345507840 329.5
amd64 full lunar 6.2.0-32.32 124663880 118.9 406902468 388.1
amd64 full mantic uncomp¹ 6.5.0-5.5 115110927 109.8 375100662 357.7
amd64 full mantic 6.5.0-5.5 103623579 98.8 126072148 120.2
amd64 nvidia jammy 5.15.0-83.92 202413553 193.0 470515992 448.7
amd64 nvidia lunar 6.2.0-32.32 213388241 203.5 530733877 506.1
amd64 nvidia mantic uncomp¹ 6.5.0-5.5 203887505 194.4 499346193 476.2
amd64 nvidia mantic 6.5.0-5.5 189517267 180.7 230569794 219.9
Pi Zero 2 jammy 5.15.0-1037.40 36769927 35.1 64928449 61.9
Pi Zero 2 lunar 6.2.0-1013.15 39577844 37.7 69974064 66.7
Pi Zero 2 mantic 6.5.0-1002.2 31046627 29.6 40592364 38.7
VisionFive 2 lunar 6.2.0-33.33.1 112822390 107.6 376176126 358.7
VisionFive 2 mantic uncomp kernel only 6.2.0-33.33.1 109754816 104.7 275491464 262.7
VisionFive 2 mantic 6.2.0-33.33.1² 101693476 97.0 125650851 119.8

Legend

  • minimal: chroot with the following packages: linux-image-generic initramfs-tools zstd
  • full: minimal plus the following packages: busybox-initramfs cryptsetup-initramfs isc-dhcp-client kbd lvm2 mdadm ntfs-3g plymouth plymouth-theme-spinner
  • nvidia: full plus the following packages: linux-headers-generic nvidia-driver-535
  • Pi Zero 2: Raspberry Pi Zero 2 ARM board
  • VisionFive 2: VisionFive 2 RISC-V board
  • uncomp¹: Revert the compression change by decompressing the kernel modules and use a linux-firmware package that was built without compressing the firmware with zstd
  • 6.2.0-33.33.1²: The kernel modules were manually compressed with zstd -19
  • nvidia-driver-535 is not yet easily installable on mantic (see bug #2037305) and needs patching to be included in the initramfs (bug #2037400

How to reproduce

  • chroot setup: Use a minimal chroot and install the packages with the --no-install-recommends parameter.
  • Compress kernel modules (for mantic uncomp¹ only):
    find /lib/modules/$(uname -r) -type f -name '*.ko' -print0 | xargs -0 -P 4 sudo zstd -19 -z --rm && sudo depmod "$(uname -r)"
    
  • Check the size: stat -L -c '%s' /boot/initrd.img
  • Extract the initrasmfs content and check its size:
    rm -rf unpacked && unmkinitramfs /boot/initrd.img unpacked && du -sb unpacked
    

initramfs build time and memory usage

test / machine distro kernel build time / s memory usage / MiB
amd64 minimal 5700G tmpfs jammy 5.15.0-83.92 4.37 ± 0.01 39.02 ± 0.43
amd64 minimal 5700G tmpfs lunar 6.2.0-32.32 4.43 ± 0.01 39.98 ± 0.88
amd64 minimal 5700G tmpfs mantic 6.5.0-5.5 1.84 ± 0.01 25.75 ± 0.13
amd64 full 5700G tmpfs jammy 5.15.0-83.92 6.90 ± 0.03 39.38 ± 0.33
amd64 full 5700G tmpfs lunar 6.2.0-32.32 7.31 ± 0.02 40.86 ± 0.88
amd64 full 5700G tmpfs mantic 6.5.0-5.5 3.89 ± 0.02 55.99 ± 0.08
amd64 nvidia 5700G tmpfs jammy 5.15.0-83.92 7.09 ± 0.03 45.92 ± 0.76
amd64 nvidia 5700G tmpfs lunar 6.2.0-32.32 7.17 ± 0.02 47.18 ± 0.92
amd64 nvidia 5700G tmpfs mantic 6.5.0-5.5 4.10 ± 0.01 160.57 ± 0.11
Pi Zero 2 jammy 5.15.0-1037.40 102.77 ± 0.97 TBD
Pi Zero 2 lunar 6.2.0-1013.15 127.91 ± 1.36 15.61 ± 0.09
Pi Zero 2 mantic 6.5.0-1002.2 99.36 ± 0.92 20.04 ± 0.05
VisionFive 2 lunar 6.2.0-33.33.1 134.18 ± 0.96 36.10 ± 0.07
VisionFive 2 mantic 6.2.0-33.33.1¹ 85.07 ± 0.21 40.53 ± 0.06

Legend

  • 5700G tmpfs: AMD Ryzen 7 5700G with schroot and overlay on tmpfs
  • Pi Zero 2: Raspberry Pi Zero 2 ARM board with 64 GB Samsung EVO Plus 2020 microSDXC (running armhf)
  • VisionFive 2: VisionFive 2 RISC-V board with 32 GB Sandisk Ultra microSDHC
  • 6.2.0-33.33.1¹: The kernel modules were manually compressed with zstd -19

How to reproduce

  • Run update-initramfs -u ten or twenty times (and build the average and standard deviation):
    for i in $(seq 20); do time update-initramfs -u > /dev/null 2>&1; done
    
  • Measure the memory consumption in Kbytes with time: /usr/bin/time -f "%M"
  • Build the average and standard deviation:
    for i in $(seq 20); do /usr/bin/time -f "%M" update-initramfs -u > /dev/null; done
    

Boot time

Systemd-analyze can be used to measure the boot time. The reported kernel time also contains the time spent in the initramfs because systemd is not used in the initramfs.

test / machine distro kernel kernel / s userspace / s total / s
amd64 5700G VM lunar 6.2.0.33.33 1.65 ± 0.05 22.20 ± 0.37² 23.85 ± 0.42²
amd64 5700G VM mantic uncomp¹ 6.5.0-5.5 1.36 ± 0.03 23.28 ± 0.48² 24.64 ± 0.50²
amd64 5700G VM mantic 6.5.0-5.5 1.17 ± 0.04 22.71 ± 0.55² 23.88 ± 0.57²
Pi Zero 2 lunar 6.2.0-1013.15 6.84 ± 0.02 28.79 ± 0.47 35.64 ± 0.47
Pi Zero 2 mantic 6.5.0-1002.2 7.34 ± 0.02 27.07 ± 0.16 34.40 ± 0.16
VisionFive 2 lunar 6.2.0-33.33.1 25.42 ± 0.21 30.74 ± 0.56 56.16 ± 0.59
VisionFive 2 mantic 6.2.0-33.33.1³ 16.61 ± 0.07 28.98 ± 0.34 45.58 ± 0.38

Legend

  • uncomp¹: Revert the compression change by decompressing the kernel modules and use a linux-firmware package that was built without compressing the firmware with zstd.
  • ² Take those slow userspace times with a grain of salt (see bug #2036592)
  • 5700G VM: Virtual machine with 8 vCPUs (host AMD Ryzen 7 5700G) and 4 GB memory
  • 6.2.0-33.33.1³: The kernel modules were manually compressed with zstd -19

How to reproduce

  • Reboot the machine at least ten times and take the boot time by running systemd-analyze. Remove the entries with too long boot times.

Further Information

The improvement was discussed on the ubuntu-devel mailing list. See
Reducing initramfs size and speed up the generation and
Update on reducing initramfs size and speed up.

6 Likes

Are the changes in [MANTIC][PATCH 0/3] Enable zstd compressed modules and Bug #2028568 “Ship kernel modules Zstd compressed” : Bugs : linux package : Ubuntu to get “in-kernel zstd module decompression support” being upstreamed?

Those patches are changing to packaging, where would you see them being upstreamed to?