How to optimize boot time in user space on a Raspberry Pi 4 / Boot2Qt

In many cases it is advantageous to know how to reduce the boot time of your system in order to meet certain requirements or to increase usability.  

In this article, only the user space optimization is targeted. Although kernel space optimizations might give better results, this seems to be the best accessible way coming from an application developer's perspective.

Note: Be aware that Raspberry Pi has its limitations when it comes to early boot stage optimization.

Environment

  • Raspberry Pi 4B
  • Boot2Qt (or any other image with similar userspace)
  • HDMI display
  • An application built for your target image

Getting the image and toolchain

In this scenario the Boot2Qt image is used, but this procedure is not tied to a specific image. The Boot2Qt image and toolchain can be found in the maintenance tool.  

Flash the image to your Raspberry Pi and power it up. If your Raspberry boots into the default Boot2Qt application, proceed to the next section.

Optional: Build Boot2Qt yourself

General questions regarding building Boot2Qt are covered here.

When building your Boot2Qt distribution, remove the webengine DISTRO_FEATURES from the b2qt.conf file if you don’t want to use webengine. This will save time and resources. 

Note: If aiming for further optimization (e.g. static build), you will need to build Boot2Qt yourself eventually. 

User space optimization

Initial state:

The first process started in user space is /sbin/init. Using the default image, this is a symlink to systemd’s startup script. If the systemd-analyze tool is applied after startup, one can observe that many unnecessary services are started by default. 

Below is a snippet of the investigation with systemd-analyze plot > /tmp/systemd-boot.svg.


Instead of removing the irrelevant services one by one, systemd will no longer be used for initialization. Be aware that neither runlevels, services nor other features of systemd won't be available after this optimization. Instead, we will use an init script independent of systemd.

At this point it is recommended to know what dependencies your application will have. In the best case, there is already an existing application available. If not, dependencies can be added later by modifying the init script. 

Step 1: 

Create a new script and change the symlink target to that script. Make sure that the script is executable.

Screenshot from 2024-08-22 13-19-25

Step 2: 

Create a new kms.config file that will be used later by the application via QT_QPA_EGLFS_KMS_CONFIG. It could look like this or similar. 

cat /opt/kms.config
{
  "device": "/dev/dri/card1",
  "hwcursor": false,
  "pbuffers": true,
  "outputs": [
    {
      "name": "VGA1",
      "mode": "off"
    },
    {
      "name": "HDMI1",
      "mode": "1024x600"
    }
  ]
}
Step 3: 

The new_init script for a minimal boot into an application looks like this or similar. 

cat /sbin/new_init.sh
#!/bin/sh
mount -t sysfs none /sys
mount -t proc none /proc
mount -t tmpfs none /tmp
mount -o remount,rw /

#graphics setup
modprobe -a vc_sm_cma gpu_sched videodev v3d i2c_brcmstb
export QT_QPA_EGLFS_KMS_CONFIG=/opt/kms.config
./opt/app &

 

What this script does:

Mount sysfs, which is needed for kernel data 

Mount proc, which is used for hardware and process management 

Mount tmpfs, which is needed for temporary session data 

Remount root to get write access to root directory 

Load kernel modules needed for graphics on a Raspberry Pi 4 

Set the environment variable for the kms.config file 

Launch the application 

 

Note: Depending on your application it can be necessary to load further kernel modules 


Comments