메모리가 작은 시스템을 위한 커널 경량화 (3) — Kconfig 옵션으로 커널 이미지 줄이기

(1)편에서 defconfig 커널의 베이스라인을 잡았고, (2)편에서는 initrd 사용 여부에 따른 트레이드오프를 확인했다. 두 편 모두 커널 설정 자체는 defconfig 그대로였다 — 실제로는 여기서부터가 진짜 경량화 작업이다. defconfig는 온갖 하드웨어를 지원하기 위해 1,629개 옵션을 켜두는데, QEMU virtio 헤드리스 서버 같은 특정 타깃에는 그중 상당수가 필요 없다. 이 글에서는 Kconfig 옵션을 스크립트로 정리해 재빌드하고, (1)편 베이스라인과 실측치를 직접 비교한다.

이 시리즈의 다른 글

정리 대상 선정

QEMU virtio 콘솔 전용 헤드리스 서버라는 타깃을 기준으로 아래 항목을 껐다. GPU/사운드/무선처럼 이 타깃에 물리적으로 존재하지 않는 하드웨어용 드라이버가 대상이다.

직접 끈 옵션이유연쇄로 함께 꺼진 옵션 수
CONFIG_DRM, CONFIG_DRM_I915-nographic 콘솔이라 GPU 드라이버 불필요22
CONFIG_SND, CONFIG_SOUND오디오 하드웨어 없음32
CONFIG_USB_SUPPORTvirtio-blk/virtio-net만 사용, USB 미사용22
CONFIG_CFG80211, CONFIG_MAC80211, CONFIG_WLAN무선랜 없음30
CONFIG_NETFILTER이 데모에서 방화벽 규칙 불필요28
CONFIG_NFS_FSNFS 클라이언트 불필요9
CONFIG_INPUT_JOYSTICK입력 장치 없음32 (나머지)

scripts/config로 옵션 끄기

make menuconfig는 인터랙티브라 재현·자동화가 어렵다. 커널 소스에 포함된 scripts/config로 같은 작업을 커맨드라인에서 스크립트화할 수 있다.

cp .config .config.baseline
./scripts/config --disable CONFIG_DRM_I915
./scripts/config --disable CONFIG_DRM
./scripts/config --disable CONFIG_SND
./scripts/config --disable CONFIG_SOUND
./scripts/config --disable CONFIG_CFG80211
./scripts/config --disable CONFIG_MAC80211
./scripts/config --disable CONFIG_WLAN
./scripts/config --disable CONFIG_INPUT_JOYSTICK
./scripts/config --disable CONFIG_NFS_FS
./scripts/config --disable CONFIG_NETFILTER
./scripts/config --disable CONFIG_USB_SUPPORT
make olddefconfig

olddefconfig가 의존 관계를 자동으로 정리한다. 직접 끈 건 11개 옵션인데, 의존성으로 연쇄 비활성화된 옵션까지 합치면 총 175개가 꺼졌다 — 커밋 전에 반드시 baseline과 diff로 확인해야 하는 이유다.

diff <(grep "=y$" .config.baseline | sort) <(grep "=y$" .config | sort) | grep "^<" | wc -l
grep -E "^CONFIG_VIRTIO_BLK=|^CONFIG_EXT4_FS=" .config
175
CONFIG_VIRTIO_BLK=y
CONFIG_EXT4_FS=y

(1)편에서 반드시 built-in이어야 한다고 확인했던 CONFIG_VIRTIO_BLK/CONFIG_EXT4_FS는 연쇄 비활성화 대상에 걸리지 않고 그대로 살아있는 것도 함께 확인했다.

재빌드와 크기 비교

time make -j6 bzImage
size vmlinux
Kernel: arch/x86/boot/bzImage is ready  (#2)

real    1m24.305s
user    4m50.291s
sys     1m23.711s

   text     data      bss      dec      hex filename
22030098  6138150   995648 29163896  1bd0178 vmlinux

옵션을 정리한 뒤에는 오브젝트 자체가 줄어 재빌드도 1분 24초로 끝났다. 같은 방식으로 QEMU에 재부팅해 런타임 수치도 다시 잡았다(-drive rootfs.img ... root=/dev/vda, initrd 미사용은 (1)편과 동일).

===== free -m =====
              total        used        free      shared  buff/cache   available
Mem:            980          12         965           0           3         957
Swap:             0           0           0
===== /proc/meminfo (head) =====
MemTotal:        1003332 kB
MemFree:          988200 kB
MemAvailable:     979916 kB
Buffers:             236 kB
Cached:             2068 kB
===== slab total =====
Slab:               5968 kB
SReclaimable:        792 kB
SUnreclaim:         5176 kB
===== boot done (no initrd, root=/dev/vda) =====
[    2.452655] reboot: Power down

before/after 비교

항목(1)편 defconfig옵션 정리 후변화
vmlinux (심볼 포함)53.7 MB39.0 MB-27%
bzImage (실제 부팅용)14.8 MB10.2 MB-31%
부팅 후 MemTotal969 MB980 MB+11 MB (커널 정적 예약 감소분)
부팅 직후 used13 MB12 MB-1 MB
Slab 총합6.7 MB6.0 MB-10%
커널 타임스탬프 (userspace 도달)5.37초2.45초-54%

이미지 크기는 30% 안팎으로 줄었고, 부팅 시간은 절반 이하로 줄었다. 부팅 시간 개선폭이 이미지 크기 개선폭보다 큰 건, 줄인 옵션 대부분이 PCI 디바이스 프로브·USB 열거처럼 부팅 중 실행 시간을 잡아먹는 초기화 코드였기 때문으로 보인다.

주의사항

  • 여기서 고른 옵션은 “QEMU virtio 헤드리스 서버”라는 특정 타깃을 전제로 한다. 실제 노트북/데스크톱이나 그래픽·오디오·무선이 필요한 보드에는 그대로 적용하면 안 되고, 타깃 하드웨어에 맞춰 대상 목록을 다시 골라야 한다.
  • 11개를 껐는데 175개가 연쇄로 꺼진 것처럼, olddefconfig의 의존성 해석은 의도하지 않은 옵션까지 함께 끌 수 있다. 이 글에서는 CONFIG_VIRTIO_BLK/CONFIG_EXT4_FS처럼 반드시 필요한 옵션이 살아있는지 diff로 직접 확인했다 — 옵션을 끌 때마다 이런 확인 없이 바로 커밋하면 안 된다.
  • 부팅 시간 개선 원인을 “DRM/USB 프로브 제거 때문”이라고 서술했지만, 이 글에서는 11개 옵션을 한 번에 묶어서 껐다 껐다 켰다를 반복하며 옵션별로 분해 측정하지는 않았다. 어떤 옵션이 몇 초를 기여했는지 정확한 기여도는 검증하지 않은 추정이다.

마무리

Kconfig 옵션 정리만으로 bzImage는 31%, 부팅 시간은 54% 줄었다. 다음 편에서는 컴파일러 옵션(-Os, LTO)과 module vs builtin 트레이드오프, initramfs 자체를 최소화하는 방법을 다룬다.

참고

답글 남기기