Fast boot is a requirement on most embedded devices. For good user experience it is important that a hand-held camera or a phone becomes usable seconds after switching it on. Apart from user experience, fastboot time also becomes a non-negotiable hard requirement for some applications. For example, a network camera or a car rear view camera must be accessible as soon as possible after power up.
A brief introduction to Linux boot process:
The boot time for a device consists of:
- Time taken by bootloader
- Time taken by Linux kernel initialization up to the launch of first user space process
- Time required for user space initialization, including launching all required daemons, running all Linux init scripts
Boot loader and Linux kernel init time can be brought down to less than 1 second on modern embedded platforms. Some standard techniques for this have been documented here.
In most boot time optimization problems, more than 80% of the boot time is taken by user space. Optimization of user space on the other hand cannot be standardized, because the user space varies from application to application.
The first user space process that runs on Linux startup is called 'init'. The init process should take care of all user space initialization required to boot up the system. This includes:
- Mounting all filesystems
- Creating device nodes
- Starting all daemons
- Performing other functions specific to the use case, like loading of firmware, starting of userspace programs
Reducing user space boot time therefore means optimizing this initialization process. The standard init process for Linux systems is Sysvinit (or busybox init for userspace systems)
Both Sysvinit and busybox init read /etc/inittab to find out what needs to be done at boot up. The first line of the init tab file defines the default 'run level' of the system. The default process executed by sysvinit is /etc/init.d/rcS, which in turn calls /etc/init.d/rc . The 'rc' script basically executes all scripts in /etc/init.d/rcN folder in order (where N is the run level).
Figure 1: sysvinit init scripts
Figure 2 : inittab file
The shortcomings of Linux Sysvinit are therefore apparent:
- The order and dependencies of init scripts must be carefully assigned. As a rule, S01 will be executed before S02 and so on. Listing out the services and enforcing dependency has to be done manually, making the process tedious and error prone.
- The init.d scripts are run in serial order. This leaves CPU resources underutilized and increases the system boot time
Linux Systemd is an alternative to Sysvinit. Systemd replaces the concept of runlevels in Sysvinit with 'targets'. A target is a set of Systemd 'units'. The Systemd units can be roughly understood as 'services'. Each service is a file which consists of statements that define its behavior, for example, the process it starts, its dependencies, and many other parameters. The dependencies between services can be enforced by means of the 'Wants' and 'Required' sections. All the services that a service depends on should be listed under 'Wants' (good to have) or ‘Requires’ (necessary to have).
Figure 3: example Systemd service
Systemd has a set of pre-defined targets that get started at system boot. The services that are need at boot up should be linked under the directory '/etc/systemd/system/default.target.wants'.
Systemd starts by looking at the basic.target and launches all services required for that target, following the dependency chain. All services required by a particular service are started before that service is started. All services that are not dependent on each other are started in parallel. Thus, Systemd achieves aggressive parallelization during boot up.
Figure 4: Adding custom Systemd service to boot target
Figure 5: Complete list of systemd services and dependencies on a system
Systemd reduces boot time in two ways:
- By way of correct configuration of dependencies and targets, it is possible to do only required init for boot, leaving other activities for after boot. For example, instead of mounting all file systems, we can configure the boot target to be dependent on only root file system. In this way the boot time target will start without waiting for other filesystem mounts. Since filesystem mounting usually takes a long time, this will speed up the boot time. This way, it is very easy to control what gets started at boot up, and also track dependencies in a centralized way.
- Systemd launches services in parallel unless a serialized dependency is enforced. This speeds up boot process significantly, leading to better CPU utilization during boot.
Thus Systemd optimizes boot time, by allowing fine grained and easy control over dependencies, and then by starting services in parallel. It comes with additional advantages of fine control of service dependencies, cleanly handling service behaviour in case of failure (restart vs fail), handles logging and system watchdog.
Systemd also comes with tools like Systemd-blame and Systemd-analyze that give a pictorial representation of how services were started. These tools make it quite convenient to know what is happening and optimize things accordingly.
It is easy to bring down user space boot time to less than 4 or 5 seconds on an embedded device by use of Systemd. Further optimizations can be squeezed out on a case by case basis. We have achieved a total boot time of 3 seconds on ARM running at 1 GHz,
Systemd is available for download here : https://www.freedesktop.org/software/systemd/ and can be cross-compiled for embedded platforms.
This article provides methodologies for improving boot time in PathPartner solutions which includes complete boot time optimization (bootloader, kernel parameters and userspace) on all embedded platforms.