\documentclass[obeyspaces,spaces,hyphens]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{minted}

\mode<presentation>
\usetheme{Bootlin}

\newcommand{\codehack}[1]{{\usebeamercolor[fg]{code} {\tt #1}}}

\title{Update on boot time reduction techniques, with figures}
\authors{Michael Opdenacker}
\institute{Bootlin}

\usepackage{hyperref}

\begin{document}

\begin{frame}{Embedded Linux Conference 2014}
  \begin{columns}[c]
   \column{0.6\textwidth}
     \huge
     Update on boot time reduction techniques, with figures\\
     \vspace{2cm}
     \normalsize
     Michael Opdenacker\\
     {\bf Bootlin}\\
     {\em michael.opdenacker@bootlin.com}
     \column{0.4\textwidth}
     % From http://openclipart.org/detail/46075/stop-watch-by-klaasvangend
     \includegraphics[width=\textwidth]{stop-watch.pdf}
   \end{columns}
\vfill \tiny Clipart:
\url{http://openclipart.org/detail/46075/stop-watch-by-klaasvangend}
\end{frame}

\begin{frame}{Michael Opdenacker}
  \begin{itemize}
  \item CEO and Embedded Linux engineer at Bootlin
    \begin{itemize}
    \item Embedded Linux {\bf development}: kernel and driver
      development, system integration, boot time and power
      consumption optimization, consulting, etc.
    \item Embedded Linux {\bf training}, Linux driver development training
      and Android system development training, with materials freely
      available under a Creative Commons license.
    \item \url{http://bootlin.com}
    \end{itemize}
  \item Conducted several boot time reduction projects,\\
        and preparing a workshop on the topic.
  \item Living in {\bf Orange}, south of France.
  \end{itemize}
\end{frame}

\begin{frame}
\frametitle{About this presentation}
\begin{itemize}
\item It is based on our new Linux boot time training materials:
      \url{http://bootlin.com/doc/training/boot-time}.
\item That's where you will find extensive details about Linux boot time
      reduction methodology and resources.
\item Here, we are focusing on
      \begin{itemize}
      \item New resources
      \item Techniques that we hadn't documented yet,\\
	    and that we used in recent projects.
      \item Benchmarks made recently
      \item Details that you may have missed
      \end{itemize}
\item Thanks to 
      \begin{itemize}
      \item Alexandre Belloni, co-author of this document.\\
      \item Atmel Corporation, for funding the development of the first
            version of these materials, and for providing boards. 
      \end{itemize}
\end{itemize}
\end{frame}

\subsection{Why reduce boot time?}

\begin{frame}
\frametitle{To make a fortune}
\begin{itemize}
\item Hi California startup creators!
\item Here is an opportunity to make millions and change people's lives:
      \begin{itemize}
      \item During the BA flight to San Franciso yesterday, they had to reboot the
            "Highlife Entertainment System". The lady warned that it
            could take up to 20 minutes.
      \item It took 16 minutes to start showing "System being reset,
            please wait".
      \item It was up and running in about 18 minutes.
      \item The lady warned: "Please don't touch the screen during the
            reboot process."
      \end{itemize}
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Because you don't want to let...}
\end{frame}

\begin{frame}
\frametitle{Because you don't want to let...}
{\large Chuck Norris reduce boot time for you!}
\begin{center}
    \includegraphics[width=0.8\textwidth]{guns-and-ammo.jpg}
    \tiny
    \newline Image credits:
    \url{http://commons.wikimedia.org/wiki/File:Guns\_\%26\_Ammo\_4.jpg}
\end{center}
\end{frame}

\begin{frame}
\frametitle{Boot time reduction methodology}
\begin{center}
    \includegraphics[width=\textwidth]{methodology.pdf}
\end{center}
\end{frame}

\begin{frame}
\frametitle{Boot time components}
Generic boot sequence
\begin{center}
    \includegraphics[width=\textwidth]{generic-boot-sequence.pdf}
\end{center}
We are focusing on reducing {\em cold} boot time, from power on to the
critical application.
\end{frame}

\begin{frame}
\frametitle{What to optimize first}
Start by optimizing the last steps of the boot process!
\begin{itemize}
\item Don't start by optimizing things that will reduce your ability to 
      make measurements and implement other optimizations.
\item Start by optimizing your applications and startup
      scripts first.
\item You can then simplify BusyBox, reducing the number of available
      commands.
\item The next thing to do is simplify and optimize the kernel. This
      will make you lose debugging and development capabilities,
      but this is fine as userspace has already been simplified.
\item The last thing to do is implement bootloader optimizations,
      when kernel optimizations are over and when the kernel command
      line is frozen.
\end{itemize}
\end{frame}

\subsection{Measuring}

\begin{frame}
\frametitle{grabserial}
\begin{itemize}
\item From Tim Bird: \url{http://elinux.org/Grabserial} (Hi Tim!)
\item A Python script to add timestamps to messages coming from a
      serial console.
\item Key advantage: starts counting very early (bootstrap and
      bootloader).
\item Another advantage: no overhead on the target, because run on the host machine.
\item Drawbacks: may not be precise enough.\\
      Can't measure power-up time.
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Using grabserial}
\begin{center}
    \includegraphics[width=\textwidth]{using-grabserial.pdf}
\end{center}
{\small
{\bf Caution}: \code{grabserial} shows the arrival time of the 
{\bf first character} of a line. This doesn't mean that the entire line
was received at that time.}
\end{frame}

\subsection{Filesystem optimizations}

\begin{frame}
\frametitle{Filesystem impact on performance}
Tuning the filesystem is usually one of the first things
we work on in boot time projects.
\begin{itemize}
\item Different filesystems can have different initialization
      and mount times. In particular, the type of filesystem
      for the root filesystem directly impacts boot time.
\item Different filesystems can exhibit different read, write
      and access time performance, according to the type 
      of filesystem activity and to the type of files in the
      system. 
\item Fortunately, changing filesystem types is quite cheap,
      and completely transparent for applications. Just try 
      several filesystem options, as see which one works best 
      for you!
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Block filesystems}
For block storage (media cards, eMMC...)
\begin{itemize}
\item ext4: best for rather big partitions, good read and write
      performance.
\item xfs, jfs, reiserfs: can be good in some read or write scenarii
      as well.
\item btrfs, f2fs: can achieve best read and write performance,
      taking advantage of the characteristics of flash-based block
      devices.
\item SquashFS: best mount time and read performance, for read-only
      partitions. Great for root filesystems which can be read-only.
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Block filesystem boot benchmarks}
Measured on the Atmel SAMA5D3 Xplained board (ARM),\\
Linux 3.10
\vfill{}
\begin{tabular}{| l || c | c | c | c |}
\hline
& ext3 & ext4 & btrfs & f2fs\\
\hline
Start init & 7.878 s & 8.039s & 7.907s & 8.817s \\
\hline
\end{tabular}
\newline
\vfill{}
Note that the \code{rootfstype} kernel command line option
also helps. It saves \code{10 ms} for \code{ext3} on the same board
and kernel (can be even worse if the static kernel supports more
filesystems). 
\end{frame}

\begin{frame}
\frametitle{Flash filesystems}
For raw flash storage
\begin{itemize}
\item JFFS2: bad read, write and mount performance. Needs
      \code{CONFIG_JFFS2_SUMMARY} to avoid huge mount time.
\item YAFFS2: good read, write and mount performance, but no
      compression. Not in mainline.
\item UBIFS: good read and write performance. Good mount performance,
      but requires {\em UBI Fastmap} (need Linux 3.7 or later). 
\item See our flash filesystem benchmarks:
      {\small
      \url{http://elinux.org/Flash_Filesystem_Benchmarks}.
      }
\end{itemize}
\end{frame}


\begin{frame}
\frametitle{Using UBI Fastmap}
\begin{itemize}
\item Compile your kernel with \code{CONFIG_UBI_FASTMAP}
\item Boot your system at least once with the
      \code{ubi.fm_autoconvert=1} kernel parameter.
\item Reboot your system in a clean way
\item You can now remove \code{ubi.fm_autoconvert=1}
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{UBI Fastmap benchmark}
\begin{itemize}
\item Measured on the Atmel SAMA5D3 Xplained board (ARM), Linux 3.10
\item UBI space: 216 MB
\item Root filesystem: 80 MB used (Yocto)
\item Average results:
    \newline \newline
    \begin{tabular}{| l || c | c | c |}
    \hline
    & Attach time & Diff & Total time\\
    \hline
    Without {\em UBI Fastmap} & 968 ms & & \\
    With {\em UBI Fastmap} & 238 ms & -731 ms & -665 ms \\
    \hline
    \end{tabular}
    \newline
\item Expect to save more with bigger UBI spaces!
\end{itemize}
Note: total boot time reduction a bit lower probably
because of other kernel threads executing during the
attach process.
\end{frame}

\begin{frame}
\frametitle{ubiblock + SquashFS}
For raw flash storage
\begin{itemize}
\item {\em ubiblock}: read-only block device on top of UBI
      (\code{CONFIG_MTD_UBI_BLOCK}). Available in Linux 3.15
      (developed on his spare time by Ezequiel Garcia,
      a Bootlin contractor).
\item Allows to put SquashFS on a UBI volume.
\item Expecting great boot time and read performance. Great
      for read-only root filesystems.
\item Benchmarks not available yet.
\end{itemize}
\end{frame}

\subsection{Init scripts}

\begin{frame}
\frametitle{Measuring - bootchart}
If you want to have a more detailed look at the userland boot sequence
than with \code{grabserial}, you can use \code{bootchart}.
\begin{figure}[h!]
	\centering
	\includegraphics[height=0.8\textheight]{bootchart.png}
\end{figure}
\end{frame}

\begin{frame}[fragile]
\frametitle{Measuring - bootchart}
\begin{itemize}
	\item You can use \code{bootchartd} from \code{busybox}
	      (\code{CONFIG_BOOTCHARTD=y})
	\item Boot your board passing \code{init=/sbin/bootchartd} on your
	      kernel command line
	\item Copy \code{/var/log/bootlog.tgz} from your target to your host
	\item Generate the timechart:
\begin{block}{}
\begin{verbatim}
cd bootchart-<version>
java -jar bootchart.jar bootlog.tgz
\end{verbatim}
\end{block}
\end{itemize}
\code{bootchart} is available at \url{http://www.bootchart.org}
\end{frame}

\begin{frame}[fragile]
\frametitle{Measuring - systemd}
If you are using \code{systemd} as your \code{init} program, you can use
\code{systemd-analyze}. See
\url{http://www.freedesktop.org/software/systemd/man/systemd-analyze.html}.\\
\begin{block}{}
\tiny
\begin{verbatim}
$ systemd-analyze blame
  6207ms udev-settle.service
   735ms NetworkManager.service
   642ms avahi-daemon.service
   600ms abrtd.service
   517ms rtkit-daemon.service
   396ms dbus.service
   390ms rpcidmapd.service
   346ms systemd-tmpfiles-setup.service
   316ms cups.service
   310ms console-kit-log-system-start.service
   309ms libvirtd.service
   303ms rpcbind.service
   298ms ksmtuned.service
   281ms rpcgssd.service
   277ms sshd.service
...
\end{verbatim}
\end{block}
\end{frame}

\begin{frame}
\frametitle{Optimizing init scripts}
\begin{itemize}
	\item Start all your services directly from a single startup
	      script (e.g. \code{/etc/init.d/rcS}). This eliminates multiple
	      calls to \code{/bin/sh}.
	\item If you need \code{udev} to manage hotplug events, replace
              \code{udev} with BusyBox \code{mdev}. It is not running as a
              daemon. It will only be run when hotplug events happen.
	\item If you just need \code{udev} to create device files,
              remove it and use \code{devtmpfs} (\code{CONFIG_DEVTMPFS}) instead,
  	      automatically managed by the kernel, and cheaper.
 	\item Results: Atmel SAMA5D3x evaluation kit, video player demo:\\
	      \code{1.015 s} saved by replacing \code{udev} by \code{devtmpfs}.
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{Reduce forking (1)}
\begin{itemize}
\item \code{fork}/\code{exec} system calls are very expensive.
      Because of this, calls to executables from shells are slow.
\item Even an \code{echo} in a BusyBox shell results in a \code{fork} syscall!
\item Select \code{Shells -> Standalone shell} in BusyBox
      configuration to make the shell call applets whenever possible.
\item Pipes and back-quotes are also implemented by
      \code{fork}/\code{exec}.  You can reduce their usage in
      scripts. Example:
      \begin{block}{}
      \begin{verbatim}
cat /proc/cpuinfo | grep model
      \end{verbatim}
      \end{block}
Replace it with:
      \begin{block}{}
      \begin{verbatim}
grep model /proc/cpuinfo
      \end{verbatim}
      \end{block}
\end{itemize}
See \url{http://elinux.org/Optimize_RC_Scripts}
\end{frame}

\begin{frame}[fragile]
\frametitle{Reduce forking (2)}
Replaced:
\begin{block}{}
\begin{verbatim}
if [ $(expr match "$(cat /proc/cmdline)" '.* debug.*')\
       -ne 0 -o -f /root/debug ]; then
DEBUG=1
\end{verbatim}
\end{block}
By a much cheaper command running only one process:
\begin{block}{}
\begin{verbatim}
res=`grep " debug" /proc/cmdline`
if [ "$res" -o -f /root/debug ]; then
DEBUG=1
\end{verbatim}
\end{block}
This only optimization allowed to save 87 ms on an ARM AT91SAM9263
system (200 MHz)!
\end{frame}

\begin{frame}
\frametitle{Do not compress your initramfs (1)}
\begin{itemize}
\item If you ship your initramfs inside a compressed kernel image, don't compress
      it \\
      (enable \code{CONFIG_INITRAMFS_COMPRESSION_NONE}).
\item Otherwise, your initramfs data will be compressed twice, and
      the kernel will be slightly bigger and will take a little more time to uncompress. 
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Do not compress your initramfs (2)}
Tests on Linux 3.13-rc4, measuring the penalty of having a
\code{gzip} compressed initramfs in a \code{gzip} compressed kernel. \\
\vfill{}
\scriptsize
Beagle Bone Black (ARM, TI AM3359, 1 GHz)
\begin{tabular}{| l || c | c | c | c | c | }
\hline
Mode & Size & Copy & Uncompress & Total & Diff \\
\hline
No initramfs compression & 4308200 & 451 ms & 945 ms & 5.516 s & \\
Initramfs compression & 4309112 & 455 ms & 947 ms & 5.527 s & + 11 ms \\
\hline
\end{tabular}
\newline\newline
CALAO USB-A9263 (ARM, Atmel AT91SAM9263, 200 MHz)
\begin{tabular}{| l || c | c | c | c | c | }
\hline
Mode & Size & Copy & Uncompress & Total & Diff \\
\hline
No initramfs compression & 3016192 & 4.1047 s & 1.737 s & 8.795 s & \\
Initramfs compression & 3016928 & 4.1050 s & 1.760 s  & 8.813 s & + 18 ms \\
\hline
\end{tabular}
\end{frame}

\begin{frame}
\frametitle{Quick splashscreen display (1)}
Often the first sign of life that you are showing!
\begin{itemize}
\item You could use the \code{fbv} program
      (\url{http://freecode.com/projects/fbv})\\
      to display your splashscreen.
\item On \code{armel}, you can just use our statically compiled
      binary: {\tiny
\url{http://git.bootlin.com/users/michael-opdenacker/static-binaries/tree/fbv}}
\item However, this is slow:\\
      878 ms on an Atmel AT91SAM9263 system!
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{Quick splashscreen display (2)}
\begin{itemize}
\item To do it faster, you can dump the framebuffer contents:\\
      \begin{verbatim}
fbv -d 1 /root/logo.bmp
cp /dev/fb0 /root/logo.fb
lzop -9 /root/logo.fb
      \end{verbatim}
\item And then copy it back as early as possible in an initramfs:
      \begin{verbatim}
lzopcat /root/logo.fb.lzo > /dev/fb0 
      \end{verbatim}
\end{itemize}
Results on an Atmel AT91SAM9263 system: \\
\begin{tabular}{| l || c | c | c | }
\hline
& \code{fbv} & plain copy (\code{dd}) & \code{lzopcat} \\
\hline
Time & 878 ms & 54 ms & 52.5 ms\\
\hline
\end{tabular}
\vfill
\footnotesize
\url{http://bootlin.com/blog/super-fast-linux-splashscreen/}
\end{frame}

\subsection{Applications}

\begin{frame}
\frametitle{Tracing applications}
You need ways of tracing your application,\\
and understand where time is spent:
\begin{itemize}
\item \code{strace}
\item \code{oprofile}
\item \code{perf}
\end{itemize}
See usage details on our slides:
\url{http://bootlin.com/doc/training/boot-time}
\end{frame}

\subsection{Kernel optimizations}

\begin{frame}[fragile]
\frametitle{Measure - Kernel initialization functions}
To find out which kernel initialization functions are the longest to
execute, add \code{initcall_debug} to the kernel command line.
Here's what you get on the kernel log:
\begin{block}{}
\tiny
\begin{verbatim}
...
[    3.750000] calling  ov2640_i2c_driver_init+0x0/0x10 @ 1
[    3.760000] initcall ov2640_i2c_driver_init+0x0/0x10 returned 0 after 544 usecs
[    3.760000] calling  at91sam9x5_video_init+0x0/0x14 @ 1
[    3.760000] at91sam9x5-video f0030340.lcdheo1: video device registered @ 0xe0d3e340, irq = 24
[    3.770000] initcall at91sam9x5_video_init+0x0/0x14 returned 0 after 10388 usecs
[    3.770000] calling  gspca_init+0x0/0x18 @ 1
[    3.770000] gspca_main: v2.14.0 registered
[    3.770000] initcall gspca_init+0x0/0x18 returned 0 after 3966 usecs
...
\end{verbatim}
\end{block}
It is probably a good idea to increase the log buffer size with
\code{CONFIG_LOG_BUF_SHIFT} in your kernel configuration. You will
also need \code{CONFIG_PRINTK_TIME} and \code{CONFIG_KALLSYMS}.
\end{frame}

\begin{frame}
\frametitle{Kernel boot graph}
With \code{initcall_debug}, you can generate a boot graph
making it easy to see which kernel initialization functions
take most time to execute.
\begin{itemize}
\item Copy and paste the console output or the output of
      the \code{dmesg} command to a file (let's call it \code{boot.log})
\item On your workstation, run the \code{scripts/bootgraph.pl} script
      in the kernel sources: \\
      \code{perl scripts/bootgraph.pl boot.log > boot.svg}
\item You can now open the boot graph with a vector graphics 
      editor such as \code{inkscape}:
\end{itemize}
\begin{center}
    \includegraphics[width=\textwidth]{boot.png}
\end{center}
\end{frame}

\begin{frame}
\frametitle{Using the kernel boot graph (1)}
Start working on the functions consuming most time first. For each
function:
\begin{itemize}
\item Look for its definition in the kernel source code. You can use LXR
      (for example \url{http://lxr.bootlin.com}).
\item Remove unnecessary functionality:
      \begin{itemize}
      \item Look for kernel parameters in C sources and Makefiles, starting
      with \code{CONFIG_}. Some settings for such parameters could help
      to remove code complexity or remove unnecessary features. 
      \item Find which module (if any) it belongs to. Loading this module
            could be deferred.
      \end{itemize}
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Using the kernel boot graph (2)}
\begin{itemize}
\item Postpone:
      \begin{itemize}
      \item Find which module (if any) the function belongs to.
            Load this module later if possible.
      \end{itemize}
\item Optimize necessary functionality:
      \begin{itemize}
      \item Look for parameters which could be used to reduce probe time,
            looking for the \code{module_param} macro.
      \item Look for delay loops and calls to functions containing
            \code{delay} in their name, which could take more time than
            needed. You could reduce such delays, and see whether the 
            code still works or not.
      \end{itemize}
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Reduce kernel size}
To let the kernel load and initialize faster
\begin{itemize}
\item Compile everything that is not needed at boot time as a module
      \begin{itemize}
      \item Results: Atmel SAMA5D3x evaluation kit, video player demo:\\
	    \code{950 ms} saved by using modules.
      \end{itemize}
\item Remove features not needed in your system: features, drivers,
      and also debugging functionality.
\item Kernel compression: will be done after bootloader optimizations.
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Turning off console output}
\begin{itemize}
\item Console output is actually taking a lot of time (very slow device).
      Probably not needed in production. Disable it by
      passing the \code{quiet} argument on the kernel command line.
\item You will still be able to use \code{dmesg} to get the kernel
      messages.
\item Time between starting the kernel and starting the \code{init}
      program, on Atmel SAMA5D3 Xplained (ARM), Linux 3.10:
      \newline\newline
    \begin{tabular}{| l || c | c | c |}
    \hline
    & Time & Diff \\
    \hline
    Without \code{quiet} & 2.352 s & \\
    With \code{quiet} & 1.285 s & -1.067 s\\
    \hline
    \end{tabular}
      \newline
\item Less time will be saved on a reduced kernel, of course.
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{Preset loops per jiffy}
\begin{itemize}
	\item At each boot, the Linux kernel calibrates a delay loop (for
	      the \code{udelay} function). This measures a number of loops per
	      jiffy ({\em lpj}) value. You just need to measure this once! Find
	      the \code{lpj} value in the kernel boot messages:
\begin{block}{}
\tiny
\begin{verbatim}
Calibrating delay loop... 262.96 BogoMIPS (lpj=1314816)
\end{verbatim}
\end{block}
	\item Now, you can add \code{lpj=<value>} to the kernel command
	      line:
\begin{block}{}
\tiny
\begin{verbatim}
Calibrating delay loop (skipped) preset value.. 262.96 BogoMIPS (lpj=1314816)
\end{verbatim}
\end{block}
	\item Tests on Atmel SAMA5D3 Xplained (ARM), Linux 3.10:
      \newline\newline
    \begin{tabular}{| l || c | c | c |}
    \hline
    & Time & Diff \\
    \hline
    Without \code{lpj} & 71 ms & \\
    With \code{lpj} & 8 ms & -63 ms\\
    \hline
    \end{tabular}
	\newline
	\item This calculation was longer before 2.6.39 (about 200 ms).
\end{itemize}
\end{frame}

\subsection{Bootloader optimizations}

\begin{frame}
\frametitle{U-Boot - Remove unnecessary functionality}
Recompile U-Boot to remove features not needed in production
\begin{itemize}
\item Disable as many features as possible 
      in \code{include/configs/<soc>-<board>.h}
\item Examples: MMC, USB, Ethernet, dhcp, ping, command line edition,
      command completion...
\item A smaller and simpler U-Boot is faster to load and faster 
      to initialize.
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{U-Boot - Remove the boot delay}
\begin{itemize}
\item Remove the boot delay:\\
      \code{setenv bootdelay 0}
\item This usually saves several seconds!
\item Before you do that, recompile U-Boot with
      \code{CONFIG_ZERO_BOOTDELAY_CHECK}, documented in
      \code{doc/README.autoboot}. It allows to stop the autoboot 
      process by hitting a key even if the boot delay is set to
      \code{0}.
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{U-Boot - Simplify scripts}
Some boards have over complicated scripts:
\begin{block}{}
\scriptsize
\begin{verbatim}
bootcmd=run bootf0
bootf0=run ${args0}; setenv bootargs ${bootargs} \
maximasp.kernel=maximasp_nand.0:kernel0; nboot 0x70007fc0 kernel0
\end{verbatim}
\end{block}
Let's replace this by:
\begin{block}{}
\tiny
\begin{verbatim}
setenv bootargs 'mem=128M console=tty0 consoleblank=0 console=ttyS0,57600 \
mtdparts=maximasp_nand.0:2M(u-boot)ro,512k(env0)ro,512k(env1)ro,\
4M(kernel0),4M(kernel1),5M(kernel2),100M(root0),100M(root1),-(other)\
rw ubi.mtd=root0 root=ubi0:rootfs rootfstype=ubifs earlyprintk debug \
user_debug=28 maximasp.board=EEKv1.3.x \
maximasp.kernel=maximasp_nand.0:kernel0'
setenv bootcmd 'nboot 0x70007fc0 kernel0'
\end{verbatim}
\end{block}
This saved 56 ms on this ARM9 system (400 MHz)!
\end{frame}

\begin{frame}
\frametitle{Bootloader: copy the exact kernel size}
\begin{itemize}
\item When copying the kernel from flash to RAM, we still see
      many systems that copy too many bytes, not taking the
      exact kernel size into account.
\item In U-Boot, use the \code{nboot} command:\\
      \code{nboot ramaddr 0 nandoffset}
\item U-Boot using the kernel size information stored in the
      \code{uImage} header to know how many bytes to copy. 
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{U-Boot - Optimize kernel loading}
\begin{itemize}
\item After copying the kernel \code{uImage} to RAM,
      U-Boot always moves it to the load address specified
      in the \code{uImage} header.
\item A CRC check is also performed.
\end{itemize}
\begin{center}
    \includegraphics[width=\textwidth]{u-boot-kernel-loading.pdf}
\end{center}
\end{frame}

\begin{frame}
\frametitle{U-Boot - Remove unnecessary memmove (1)}
\begin{itemize}
\item You can make U-Boot skip the \code{memmove} operation
      by directly loading the \code{uImage} at the right
      address.
\item Compute this address: \\
      {\small
      \code{Addr = Load Address - uImage header size}\\
      \code{Addr = Load Address - (size(uImage) - size(zImage))}\\ 
      \code{Addr = 0x20008000 - 0x40 = 0x20007fc0}\\
      }
\end{itemize}
\begin{center}
    \includegraphics[width=\textwidth]{u-boot-kernel-loading-no-memmove.pdf}
\end{center}
\end{frame}

\begin{frame}
\frametitle{U-Boot - Remove unnecessary memmove (2)}
Results on Atmel SAMA5D3 Xplained (ARM), Linux 3.10:
\newline\newline
\begin{tabular}{| l || c | c |}
\hline
& Time & Diff \\
\hline
Default & 1.433 s & \\
Optimum load address & 0.583 s & -0.85 s\\
\hline
\end{tabular}
\newline\newline
\small
Measured between \code{Booting kernel} and \code{Starting kernel ...}
\end{frame}

\begin{frame}
\frametitle{U-Boot - Remove kernel CRC check}
\begin{itemize}
\item Fine in production when you never have data corruption
      copying the kernel to RAM.
\item Disable CRC checking with a U-boot environment variable:\\
      \code{setenv verify no}
\end{itemize}
Results on Atmel SAMA5D3 Xplained (ARM), Linux 3.10:
\newline\newline
\begin{tabular}{| l || c | c |}
\hline
& Time & Diff \\
\hline
With CRC check & 583 ms & \\
Without CRC check & 60 ms & -523 ms \\
\hline
\end{tabular}
\newline\newline
\small
Measured between \code{Booting kernel} and \code{Starting kernel ...}
\end{frame}

\begin{frame}
\frametitle{Further U-Boot optimizations}
\begin{itemize}
\item Silence U-Boot console output. You will need to compile
      U-Boot with \code{CONFIG_SILENT_CONSOLE} and
      \code{setenv silent yes}.\\
      See \code{doc/README.silent} for details.
\item Ultimate solution: use U-Boot's {\em Falcon} mode.\\
      U-Boot is split in two parts: the SPL (Secondary Program Loader)
      and the U-Boot image. U-Boot can then configure the SPL to load
      the Linux kernel directly, instead of the U-Boot image.\\
      See \code{doc/README.falcon} for details.
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Kernel compression and size optimizations}
After optimizing the time to load the kernel in the
bootloader, we are ready to experiment with kernel 
options impacting size:
\begin{itemize}
\item Kernel compression options
\item Optimizing kernel code for size 
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Kernel compression options}
Results on TI AM335x (ARM), 1 GHz, Linux 3.13-rc4
{\scriptsize
\begin{tabular}{| l || c | c | c | c | c | c |}
\hline
Timestamp & gzip & lzma & xz & lzo & lz4 & uncompressed \\
\hline
Size & 4308200 & 3177528 & {\bf 3021928} & 4747560 & 5133224 & 8991104 \\
Copy & 0.451 s & 0.332 s & {\bf 0.315 s} & 0.499 s & 0.526 s & 0.914 s \\
Uncompress & 0.945 s & 2.329 s & 2.056 s & 0.861 s & {\bf 0.851 s} & {\bf 0.687 s} \\
Total & {\bf 5.516 s} & 6.066 s & 5.678 s & 5.759 s & 6.017 s & 8.683 s \\
\hline
\end{tabular}
}
\vfill{}
Results on Atmel AT91SAM9263 (ARM), 200 MHz, Linux 3.13-rc4
{\scriptsize
\begin{tabular}{| l || c | c | c | c | c | c |}
\hline
Timestamp & gzip & lzma & xz & lzo & lz4 & uncompressed \\
\hline
Size & 3016192 & 2270064 & {\bf 2186056} & 3292528 & 3541040 & 5775472 \\
Copy & 4.105 s & 3.095 s & {\bf 2.981 s} & 4.478 s & 4.814 & 7.836 s \\
Uncompress & 1.737 s & 8.691 s & 6.531 s & {\bf 1.073} s & 1.225 s & N/A \\
Total & 8.795 s & 14.200 s & 11.865 s & {\bf 8.700 s} & 9.368 s & N/A \\
\hline
\end{tabular}
}
\newline\newline
Results indeed depend on I/O and CPU performance!
\end{frame}

\begin{frame}
\frametitle{Optimize kernel for size}
\begin{itemize}
\item \code{CONFIG_CC_OPTIMIZE_FOR_SIZE}: possibility to compile the kernel
      with \code{gcc -Os} instead of \code{gcc -O2}.
\item Such optimizations give priority to code size at
      the expense of code speed.
\item Results: the initial boot time is better (smaller
      size), but the slower kernel code quickly offsets
      the benefits. Your system will run slower!  
\end{itemize}
Results on Atmel SAMA5D3 Xplained (ARM), Linux 3.10, gzip compression:
\newline\newline
\begin{tabular}{| l || c | c | c |}
\hline
Timestamp & O2 & Os & Diff \\
\hline
Starting kernel & 4.307 s & 4.213 s & -94 ms \\
Starting init & 5.593 s & 5.549 s & -44 ms \\
Login prompt & 21.085 s & 22.900 s & + 1.815 s \\
\hline
\end{tabular}
\newline\newline
\small
\end{frame}

\begin{frame}
\frametitle{Replacing U-Boot by Barebox}
\begin{itemize}
\item We saved time by replacing U-Boot by Barebox.
\item Barebox can be made very small too, and loads
      the Linux kernel with the CPU caches on. This 
      significantly reduces kernel decompression time!
\item At this stage, we can't share our benchmarks yet.
      They are not fair for U-Boot, as we did optimize
      Barebox further than we did with U-Boot.
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{Removing the bootloader (1)}
Principle: instead of loading the bootloader and then the kernel,
load the kernel right away!
\begin{center}
    \includegraphics[width=\textwidth]{timechart-barebox-final.pdf}
\end{center}
Using \code{AT91bootstrap} to boot the Linux kernel:
\begin{center}
    \includegraphics[width=\textwidth]{timechart-at91.pdf}
\end{center}
\url{http://bootlin.com/blog/starting-linux-directly-from-at91bootstrap3/}
\end{frame}

\begin{frame}[fragile]
\frametitle{Removing the bootloader (2)}
\begin{itemize}
\item In our particular case, though, we can see that we are losing
      the main advantages of Barebox: it uses the CPU caches while
      loading the kernel.
\item Skipping the bootloader is not always the best choice!
\end{itemize}
\url{http://bootlin.com/blog/starting-linux-directly-from-at91bootstrap3/}
\end{frame}

\begin{frame}
  \begin{center}
  \Huge
  Questions?\\
  \vspace{1.5cm}
  \huge
  Michael Opdenacker\\
  \large
  \vspace{0.5cm}
  \code{michael.opdenacker@bootlin.com}
  \vspace{0.5cm}
  \newline Slides under CC-BY-SA 3.0\\
  \scriptsize
  \url{http://bootlin.com/pub/conferences/2014/elc/opdenacker-boot-time/}
  \end{center}
\end{frame}

\end{document}
