ArticleAdvancedFirmware

Embedded Linux Boot Time Optimization

A field guide to profiling and cutting boot time — from bootloader hand-off through systemd service ordering to first user-space process.

Embedded Linux Boot Time Optimization

A field guide to profiling and cutting boot time — from bootloader hand-off through systemd service ordering to first user-space process.

Why boot time matters

For consumer devices, every second of boot time is user-visible. For industrial equipment, it's availability. For safety-critical systems, it may be a certification requirement. Boot time is a product quality metric, not a development detail.

Phase 1 — Bootloader

Profile: Add timestamps in U-Boot with CONFIG_BOOTSTAGE=y and CONFIG_BOOTSTAGE_REPORT=y.

Quick wins:

  • Reduce DDR training time — use stored training results if your SoC supports it (i.MX6/8 DDR calibration, Rockchip ddr_init)
  • Cut console baud rate negotiation — fix baud rate in config instead of auto-detecting
  • Skip unnecessary peripherals — disable USB, Ethernet PHY init, splash screen if not required for your target
  • Enable NAND/eMMC fast boot — configure CONFIG_FASTBOOT or eMMC HS200/HS400 mode

Target: U-Boot should hand off to the kernel in < 500 ms for most embedded platforms.

Phase 2 — Kernel

Profile: Add initcall_debug to kernel cmdline, capture output, sort by duration.

Or use bootgraph.py on dmesg output:

dmesg | perl scripts/bootgraph.pl > boot.svg

Quick wins:

  • Reduce initcall overhead — disable drivers for hardware you don't have (make menuconfig → trim to your BOM)
  • Use CONFIG_INITRAMFS_SOURCE — embed a minimal initramfs instead of separate rootfs mount
  • Async driver probing — mark independent drivers with PROBE_PREFER_ASYNCHRONOUS (kernel 5.x+)
  • Defer non-critical subsystems — move audio, GPU, USB host init to after user-space is up

Phase 3 — systemd / init

Profile:

systemd-analyze
systemd-analyze blame
systemd-analyze critical-chain
systemd-analyze plot > boot.svg

Quick wins:

  • Audit WantedBy=multi-user.target — every service that boots unnecessarily adds to critical path
  • Add Type=notify + socket activation — services that support it start only when their socket receives a connection
  • Mask unused unitssystemctl mask bluetooth.service if you have no Bluetooth
  • Set DefaultTimeoutStartSec — prevent hung services from blocking the boot sequence indefinitely

Phase 4 — Application startup

  • Defer non-essential initialization (analytics, telemetry upload, UI polish) until after the device is "operational"
  • Use sd_notify(0, "READY=1") to signal systemd as early as possible, even before full initialization
  • Pre-compile Python/interpreted startup scripts or replace with compiled binaries

Measurement

Always measure boot time with a hardware timer or GPIO toggle — kernel logs have variable latency. A logic analyzer or oscilloscope on a GPIO that goes high at "first user-space ready" is the ground truth.

Realistic targets

| Platform | Bootloader | Kernel | User-space | Total | |---|---|---|---|---| | Cortex-A53, eMMC | 300 ms | 800 ms | 500 ms | ~1.6 s | | i.MX8, NVMe | 200 ms | 600 ms | 400 ms | ~1.2 s | | Raspberry Pi 4 | 2–3 s | 3–4 s | 2 s | ~7 s (stock) | | RPi 4 optimized | 300 ms | 1 s | 500 ms | ~1.8 s |

Next Step

Ready for a full course path?

Use this resource as a starting point and continue with structured modules in Learn courses.