From: eLinux.org

Kernel Size Tuning Guide

This document describes how to configure the Linux kernel to use a small
amount of memory and flash.

Alert.gif Note: This
document is a work in progress. Please feel free to add material
anywhere you have additional information or data. Sections of this
document which need additional work are denoted with [FIXTHIS] markers.

Contents

Introduction

One big problem area when using Linux in an embedded project is the size
of the Linux kernel.

Measuring the kernel

There are 3 aspects of kernel size which are important:

the size of the kernel image stored in flash (or other persistent
storage)

the static size of kernel image in RAM (usually, this will be the size
of the uncompressed image)

  • This includes the text, data, and BSS segments of the kernel at the
    time it is loaded. The text and BSS segments will stay the same size
    for the kernel throughout it execution. However, the data and stack
    segments may grow according to the needs of the system.

the amount of dynamic RAM used by the kernel.

  • This will fluctuate during system execution. However, there is a
    baseline amount of memory which is allocated at system startup.
    Application-specific RAM can be calculated to be above this minimal
    amount of required RAM.

For now, this document ignores Execute-In-Place (XIP) and
Data-Read-In-Place (DRIP) techniques, the use of which have an impact on
the amount of flash and RAM used by the kernel. See the following online
resources for more information about these techniques: Kernel
XIP
and Data Read In
Place

Measuring the kernel image size

The compressed kernel image is what is stored in the flash or ROM of the
target device. The size of this image can be obtained by examining the
size of the image file in the host filesystem with the ‘ls -l
command:

  • for example: ‘ls -l vmlinuz‘ or ‘ls -l bzImage‘ (or whatever the
    compressed image name is for your platform.)

Measuring the kernel text, data and bss segments

Use the size command to determine the size of the text, data, and BSS
segments of a kernel image.

Note that the BSS segment is not stored in the kernel image because
it can be synthesized at boot time by filling a block of memory with
zeros. Note also that portions of the kernel text and data are set aside
in special initialization segments, which are discarded when the kernel
finishes booting. Because of these factors, the size command does not
give you an exactly correct value for the static kernel RAM size.
However, it can be used as a reasonable estimate.

To use the size command, run it with the filename of the uncompressed
kernel image (which is usually vmlinux).

  • for example: ‘size vmlinux

Example output:

  1. text data bss dec hex filename
  2. 2921377 369712 132996 3424085 343f55 vmlinux

Measuring and comparing sub-parts of the kernel

In order to find areas where the kernel size can be reduced, it is often
useful to break down the static size of the kernel by sub-system or by
kernel symbol. The following sections describe how to see the size of
each kernel sub-system, how to see the size of individual kernel
symbols, and how to compare the size of symbols between two kernel
versions. This is useful because as you make changes to the kernel
configuration you can determine what part of the kernel is affected by
the change. From this information you may be able to predict what the
affect of the change will be, and decide whether the change is
acceptable.

Measuring major kernel subsystems

The major sub-systems of the kernel are put into library object files
named built-in.o in the corresponding sub-directory for that
sub-system within the kernel build directory. The major sub-directories,
at the time of this writing (for kernel 2.6.17) are:
init, user, kernel, mm, fs, ipc, security, crypto, block, ltt, drivers, sound, net, lib

To see the size of the major kernel sections (code, data, and BSS), use
the size command, with a wildcard for the first level of
sub-directory:

  • size */built-in.o

You can pipe this output through sort to sort by the largest
libraries:

  • size */built-in.o | sort -n -r -k 4

Example output:

  1. 731596 53144 33588 818328 c7c98 drivers/built-in.o
  2. 687960 24972 2648 715580 aeb3c fs/built-in.o
  3. 547844 19508 28052 595404 915cc net/built-in.o
  4. 184072 6256 32440 222768 36630 kernel/built-in.o
  5. 141956 3300 2852 148108 2428c mm/built-in.o
  6. 68048 1804 1096 70948 11524 block/built-in.o
  7. 26216 768 0 26984 6968 crypto/built-in.o
  8. 17744 2412 2124 22280 5708 init/built-in.o
  9. 20780 292 124 21196 52cc ipc/built-in.o
  10. 18768 68 0 18836 4994 lib/built-in.o
  11. 2116 0 0 2116 844 security/built-in.o
  12. 134 0 0 134 86 usr/built-in.o
  13. text data bss dec hex filename

To see even greater detail, you can examine the size of built-in.o
files even deeper in the kernel build hierarchy, using the find
command:

  • find . -name "built-in.o" | xargs size | sort -n -r -k 4

Example output:

  1. 731596 53144 33588 818328 c7c98 ./drivers/built-in.o
  2. 687960 24972 2648 715580 aeb3c ./fs/built-in.o
  3. 547844 19508 28052 595404 915cc ./net/built-in.o
  4. 260019 9824 4944 274787 43163 ./net/ipv4/built-in.o
  5. 184072 6256 32440 222768 36630 ./kernel/built-in.o
  6. ...






Alert.gif Note: Please be careful interpreting the results from the size of the built-in.o files in sub-directories. In general, the object files are aggregated into the libraries of parent directories, meaning that many object files will have their size counted twice. You cannot simply add the columns for an indication of the total kernel size
Measuring individual kernel symbols

You can measure the size of individual kernel symbols using the ‘nm’
command. Using the nm --size -r vmlinux

  1. [tbird@crest ebony]$ nm --size -r vmlinux | head -10
  2. 00008000 b read_buffers
  3. 00004000 b __log_buf
  4. 00003100 B ide_hwifs
  5. 000024f8 T jffs2_garbage_collect_pass
  6. 00002418 T journal_commit_transaction
  7. 00002400 b futex_queues
  8. 000021a8 t jedec_probe_chip
  9. 00002000 b write_buf
  10. 00002000 D init_thread_union
  11. 00001e6c t tcp_ack

Legend: The columns of this output are:

  1. size in bytes (in hexadecimal)
  2. symbol type
  3. symbol name.

The symbol type is usually one of:

  • ‘b’ or ‘B’ for a symbol in the BSS segment (uninitialized data),
  • ‘t’ or ‘T’ for a symbol in the text segment (code), or
  • ‘d’ or ‘D’ for a symbol in the data segment.

Use ‘man nm‘ for additional information on the ‘nm‘ command.

Comparing kernel symbols between two kernel images

Use the bloat-o-meter command, found in the kernel source scripts
directory, to compare the symbol sizes between two kernel images.

  • \/scripts/bloat-o-meter vmlinux.default vmlinux.altconfig

If you get an error: ‘chmod a+x \/scripts/bloat-o-meter’

Example output, comparing a baseline kernel to one configured with
CONFIG_PRINTK=n:

  1. [] $ ../../linux/scripts/bloat-o-meter vmlinux.baseline vmlinux.no-printk
  2. add/remove: 5/23 grow/shrink: 8/1541 up/down: 1141/-199824 (-198683)
  3. function old new delta
  4. proc_ioctl_default - 610 +610
  5. proc_reapurb - 296 +296
  6. proc_disconnectsignal - 88 +88
  7. proc_releaseinterface - 72 +72
  8. proc_claiminterface - 36 +36
  9. xprt_adjust_cwnd 169 182 +13
  10. do_timer 1052 1063 +11
  11. i8042_controller_reset 78 84 +6
  12. serio_init 167 172 +5
  13. usb_exit 80 81 +1
  14. early_uart_console_init 45 46 +1
  15. console_unblank 103 104 +1
  16. console_conditional_schedule 21 22 +1
  17. parse_early_param 102 101 -1
  18. machine_emergency_restart 249 248 -1
  19. console_callback 239 238 -1
  20. arch_align_stack 45 44 -1
  21. quirk_p64h2_1k_io 183 181 -2
  22. printk_time 4 - -4
  23. printk_cpu 4 - -4
  24. oops_timestamp.7 4 - -4
  25. neigh_resolve_output 733 729 -4
  26. msg_level.4 4 - -4
  27. ...
  28. de_dump_status 1586 313 -1273
  29. decode_getfattr 3156 1748 -1408
  30. ext3_fill_super 5980 4545 -1435
  31. usbdev_ioctl 6476 4846 -1630
  32. usb_get_configuration 4001 1878 -2123
  33. proc_submiturb 2294 - -2294
  34. __log_buf 131072 - -131072

Kernel Size Tuning features

The Linux kernel includes a number of options for to control the
features and options it supports. The kernel, over time, has accumulated
a large set of features and capabilities. But many features are not
needed in Consumer Electronics products. By carefully tuning the kernel
options, you can omit many parts of the kernel and save memory in your
product.

Linux-tiny patches

The Linux-tiny patch set is a set of patches maintained by Matt Mackall
developed with the intent to help a developer reduce the size of the
Linux kernel.

These patches are described at: Linux Tiny

The Linux-tiny patch set includes a number of different patches to allow
the kernel to be reduced in size. Sometimes, the size reductions are
accomplished by reducing the number of objects for a particular features
(like the number of possible swap areas, or the number of tty discipline
structures). Sometimes, the size reductions are achieved by removing
features or functions from the kernel.

Here is a list of the individual Linux-tiny patches that are available
for the 2.6.22 kernel at Linux Tiny Patch
Details

Please note that the last patch in this list (“do-printk”) is available
separately from the main Linux-tiny patch set. Please find this patch
at: Do Printk

The patches listed in this table represent patches that can be applied
to a 2.6.16 Linux kernel. However, as of version 2.6.16, many options
for reducing the kernel were already available in Linux. A list of
options, both from these patches and from existing code, which are
interesting for tuning the kernel size is provided in the section:
“Kernel configuration Options”

How to configure the kernel

[FIXTHIS - need detailed kernel configuration instructions]

  • use ‘make menuconfig’
  • perform thorough testing of your library and applications with the
    smaller config
  • development vs. deployment configurations
  • describe all_no config - most times it won’t boot.

Kernel Configuration Options

Here is a table of kernel configuration options, including a
description, the default value for a kernel, and the recommended value
for a smaller configuration of the kernel:








































































































































































































































































CONFIG optionDescriptionDefaultSmall
CONFIG_CORE_SMALLtune some kernel data sizesNY
CONFIG_NET_SMALLtune some net-related data sizesNY
CONFIG_KMALLOC_ACCOUNTINGturn on kmalloc accountingNY
CONFIG_AUDIT_BOOTMEMprint out all bootmem allocationsNY
CONFIG_DEPRECATE_INLINEScause compiler to emit info about inlinesNY *
CONFIG_PRINTKallow disable of printk code and message dataYN
CONFIG_BUGallow elimination of BUG (and BUG_ON??) codeYN
CONFIG_ELF_COREallow disabling of ELF core dumpsYN
CONFIG_PROC_KCOREallow disabling of /proc/kcoreYN
CONFIG_AIOallow disabling of async IO syscallsYN
CONFIG_XATTRallow disabling of xattr syscallsYN
CONFIG_FILE_LOCKINGallow disabling of file locking syscallsYN
CONFIG_DIRECTIOallow disabling of direct IO supportYN
CONFIG_MAX_SWAPFILES_SHIFTnumber of swapfiles50
CONFIG_NR_LDISCSnumber of tty line disciplines162
CONFIG_MAX_USER_RT_PRIOnumber of RT priority levels (schedule slots)1005
Other config optionsThese are not in Linux-tiny, but help with sizedefaultsmall
CONFIG_KALLSYMSload all symbols for debugging/kksymoopsYN
CONFIG_SHMEMallow disabling of shmem filesystemYN +
CONFIG_SWAPallow disabling of support for a swap segment (virtual memory)YN
CONFIG_SYSV_IPCallow disabling of support for System V IPCYN +
CONFIG_POSIX_MQUEUEallow disabling of POSIX message queue supportYN +
CONFIG_SYSCTLallow disabling of sysctl supportYN +
CONFIG_LOG_BUF_SHIFTcontrol size of kernel printk buffer1411
CONFIG_UID16allow support for 16-bit uidsY??
CONFIG_CC_OPTIMIZE_FOR_SIZEUse gcc -os to optimize for sizeYY
CONFIG_MODULESallow support for kernel loadable modulesYN +
CONFIG_KMODallow support for automatic kernel module loadingYN
CONFIG_PCIallow support for PCI bus and devicesYY -
CONFIG_XIP_KERNELallow support for kernel Execute-in-PlaceNN
CONFIG_MAX_RESERVE_AREA??????
CONFIG_BLK_DEV_LOOPsupport for loopback block deviceYY -
CONFIG_BLK_DEV_RAMsupport for block devices for RAM filesystemsYY -
CONFIG_BLK_DEV_RAM_COUNTNumber of block devices for RAM filesystems162?
CONFIG_BLK_DEV_RAM_SIZESize of block device struct for RAM filesystems4096??
CONFIG_IOSCHED_ASInclude Anticipatory IO schedulerYY
CONFIG_IOSCHED_DEADLINEInclude Deadline IO schedulerYN +
CONFIG_IOSCHED_CFQInclude CFQ IO schedulerYN +
CONFIG_IP_PNPsupport for IP autoconfigurationYN +
CONFIG_IP_PNP_DHCPsupport for IP autoconfiguration via DHCPYN +
CONFIG_IDEsupport for IDE devicesYN +
CONFIG_SCSIsupport for SCSI devicesYN +

Legend:

  • “Y *“ - Set to ‘Y’ for measurement during development, and set to
    ‘N’ for deployment.
  • “N +” - Whether you can set this to ‘N’ depends on whether this
    feaure is needed by your applications.
  • “Y -“ - You probably need this, but it might we worth checking to
    see if you don’t.

Special Instructions for some kernel options

How to use CONFIG_PRINTK

If the “do-printk” patch is applied, there are two options which control
the compilation of printk elements in the kernel: CONFIG_PRINTK_FUNC
and CONFIG_PRINTK. You can use these options to control how much printk
support the kernel provides, and to control on a global basis whether
any printk messages at all are compiled into the kernel. Another special
preprocessor variable is also available, called DO_PRINTK, which
provides the ability to enable printk messages inside a single C
compilation unit, even if printk messages are disabled globally.

This section explains how to use these features to reduce the kernel
size, while still enabling sufficient printk messages to be useful
during development and deployment.

The CONFIG_PRINTK option disables all of the kernel printk calls. By
setting this option to ‘N’ in your kernel configuration, all uses of
“printk” throughout the kernel source are turned into empty statements,
and omitted when the program is compiled. This provides a substantial
size savings, since the kernel messages often account for more than 100
kilobytes of space in the kernel image. Setting this option to ‘N’ will
not, however, remove the actual

  1. printk

code itself (just the calls to

  1. printk

). The CONFIG_PRINTK_FUNC option controls whether the

  1. printk

function and various helper functions are compiled into the Linux
kernel. When this is set to ‘N’, CONFIG_PRINTK is automatically set to
‘N’, and no printk messages are compiled into the kernel. This usually
saves about another 4K of size in the kernel image.

By using both CONFIG_PRINTK and CONFIG_PRINTK_FUNC, you can reduce
the size of the kernel image (and that flash and RAM it requires).
However, there is a drawback to eliminating all the messages. Obviously,
it is then not possible to get any status, diagnostic or debug messages
from the kernel! Another mechanism is available, which allows you to
control on a per-file basis which printk calls are compiled into the
kernel. This is the pre-processor variable DO_PRINTK.

To use DO_PRINTK, set CONFIG_PRINTK to ‘N’ and CONFIG_PRINTK_FUNC to
‘Y’ in your kernel configuration. This will globally disable all printk
calls in the kernel. Now, determine the C files where you wish to enable
printk messages, and add the line:

  1. #define DO_PRINTK 1

at the top of each file. Now, the printk calls in those files will be
compiled normally. Printk calls in other modules will be omitted.

Alert.gif - Important
Note:
The DO_PRINTK variable controls how the preprocessor will treat
printk statements in the code. For this reason, this statement MUST
appear at the top of the file, before any

  1. #include

lines. In order to change the set of printk messages preserved in the
code, you will need to modify the

  1. DO_PRINTK

lines, and recompile the kernel. (There is no runtime control of the
printk calls.) This is a simple mechanism, but it does provide a way to
omit most of the printk messages from the kernel while still
preserving some messages that may be useful during

development or on a deployed product.

In review, there are basically 3 different settings combinations for
CONFIG_PRINTK_FUNC and CONFIG_PRINTK that make sense:



















Settings
Explanation
CONFIG_PRINTK_FUNC
CONFIG_PRINTK
YYThis is the default setting for the kernel configuration. In this setting the printk code is compiled into the kernel, and all printk calls throughout the entire source code are also compiled as part of the kernel.
YNThis leaves the actual printk() routine in the kernel, but disables all calls to printk throughout the entire source code. However, you can use DO_PRINTK in individual modules to enable the printk calls from those modules.
NNThis removes the printk() routine from the kernel, and disables all kernel printk messages, and gives the smallest kernel code and data size. DO_PRINTK will NOT enable any module-specific printk calls.

Booting without SysFS

(copied from linux-tiny wiki)

Turning off sysfs support can save a substantial amount of memory in
some setups. One big downside is that it breaks the normal boot process
because the kernel can no longer mapa symbolic device name to the
internal device numbers.

Thus, you will need to pass a numeric device number in hex. For example,
to boot off /dev/hda1, which has major number 3 and minor 1, you’ll need
to append a root== option like this:

  1. /boot/vmlinuz root==0x0301 ro

Booting without /proc fs

It is also possible to boot with

  1. /proc

fs, but many programs expect this psuedo-filesystem to be present and
mounted. For example,

  1. free

and

  1. ps

are two commands which retrieve information from

  1. /proc

in order to run.

list some workarounds here

Using kernel memory measurement features

Alert.gif FIXTHIS - need
instruction on bootmem auditing and counting inlines - need more detail
for kmalloc accounting

Kmalloc Accounting

This is a features of Linux-tiny, which tracks callers of kmalloc and
kfree, and produces summary statistics for kernel memory allocations, as
well as detailed information about specific kmalloc callers.

This was first published by Matt Mackall in February of 2005, but was
not mainlined at that time.

To see results for kernel allocations, follow these steps:

  • turn on the CONFIG_KMALLOC option. This will show up on the kernel
    configuration menus as “Enabled accounting of kmalloc/kfree
    allocations?”
  • recompile your kernel
  • boot the kernel
  • periodically, examine the accounting stats
    • cat /proc/kmalloc

See http://lwn.net/Articles/124374/

Bootmem Auditing
Counting Inlines

Outline

Alert.gif FIXTHIS - need
to review outline and fill in missing material

  • Tuning the kernel

  • how to measure kernel size

  • in-kernel size reporting - kmalloc accounting

  • bloat-o-meter

  • kernel configuration options

  • mainline options

  • optional features
  • minimal config
  • sufficient API?

  • POSIX compliance

  • LSB compliance
  • LTP compliance

  • file systems

  • comparison of file system sizes

  • compiler options for reducing size

  • gcc -os

  • gcc -whole-program

  • online resources:

  • bloatwatch

  • kconfigsize

References

Appendices

Appendix A - Sample minimum configuration for ARM

[FIXTHIS - need ARM minimum config.]

Appendix B - Configuration Option Details

Alert.gifWant to fill in
this section with details about configuration options.

For each option, would like to document:

  • what is size affect for different option values

  • This page & Kernel Size Tuning Guide Config Option
    Impact

    describe kernel size and RAM usage impact affected by each
    configuration option listed in “Kernel Configuration Options” above,
    on i386.

  • what is affect of performance, functionality, etc.

  • what programs (if any) will stop working if option is turned off (or
    reduced)

Appendix C - Things to research

  • miniconfigs
  • how to use an initramfs (to avoid using NFS-mounted rootfs)
  • how to use a local fs (to avoid using NFS-mounted rootfs)
  • Eric Biederman’s turning off CONFIG_BLOCK - will any FS work after
    this??

  • he got a 2.6.1 kernel (presumably all_no) to: “191K bzImage and a
    323K text segment”. See
    here.

  • why is networking so big??

  • why are file systems so big??
  • capture serial output from kernel for size measurement (see
    grabserial program)

Categories: