🔧

[Linux] 起動時間を*極限まで*短くする

に公開

ノートパソコンでもなくただのデスクトップなので起動時間が長いのもしょうがないかなーとか思っていたのですがやっぱり起動時間が長いとモチベーションが下がるのでちょうどArch LinuxからCachyOSに移行したのを機にいろいろ変えてみました

環境

$ systemd-analyze #現在の起動時間
Startup finished in 17.469s (firmware) + 6.790s (loader) + 11.084s (kernel) + 7.852s (userspace) = 43.196s 
graphical.target reached after 4.802s in userspace.
  • firmware : BIOS/UEFIの処理
  • loader : GRUBやsystemd-bootがlinuxを読み込むまでの時間
  • kernel:カーネルの初期化
  • usespace:initがログイン画面を出すまで

目標

  • 少なくともログイン後にはsshdやNetworkManagerが動いていて、しっかり/直下のディレクトリは全てマウントされてる状態になること
  • Corebootを入れたりするような起動しなくなるリスクがあること(危険行為)はしない
  • とにかく、起動を早く、爆速に

本題

今起動時間が多いのは

firmware > kernel > userspace > loader

の順番ですね。

( )のところには使ってるものを書いておきます。

Linux ディストリビューション

これに関してはインストール後にカスタマイズすれば結局どうにかなるものですが、インストール時から最適化されているものは

  • Void(systemdの代わりにrunit)
  • Alpine Linux(systemdの代わりにopenrc)

後からカスタマイズしやすいものは

firmware (UEFI)

ここは使ってるマザーボードによってだいぶ変わってくると思います。
CorebootができればやりたかったのですがBIOSが壊れても自分じゃ直せない自信しかないのでやめておきました。

自分のマザーボードではこのような設定になりました

名前
MSI Fast Boot 有効
Memory Fast Boot No Training

これにプラスでLinuxが入っているディスクを起動順序で一番最初にしたり、使っていないもの(ネットワークブートなど)を無効化しました。

firmwareの時間はだいぶ気まぐれなのでもう参考にしてません()

あとBIOSのアップデートをしたら早くなってた気がします

kernel (linux-cachyos-gcc -> linux-cachyos-eevdf-lto)

mkinitcpio.conf

/etc/mkinitcpio.confHOOKで使わないものを削る(自分の場合はplymouth)
MODULESにはnvidia系しかないので削れませんでした。

圧縮方式をlz4にしてオプションに-1を指定することでサイズは多少大きくなるかもしれませんが、最速の読み込みができます。

カーネルのコンパイル

カーネルをlinux-cachyos-gccからlinux-cachyos-eevdf-ltoに変えるついでに色々コンフィグをいじって自分のパソコンの構成に最適化するようにしました。

cachyos-kernel-managerを使ってコンパイルしたので実際の値の名前と異なっているかもしれません

名前
Enable LTO Thin
CPU compiler optimizations Native Intel
Disable NUMA 有効

カーネルパラメーター

systemd.zram=0を渡してzramを無効化しておきました。
効果があるのかは知りませんがRAMがおかしいほどにあるのでメモリが大量に消費されることになっても大丈夫でしょう多分

userspace (systemd)

ここに関してはsystemdからopenrcやrunitに乗り換えることも検討しましたが、仮想環境でやってみたらほぼ同じ速度(なんならsystemdの方がちょい早い)感じだったのと、systemdから乗り換えるならLinuxディストリビューションごと移動しないと互換性が終わってたりするのでsystemdのままにしました

ディスクのマウント

目標は起動速度の最適化なので/dev/sdc3(/home)や前のArch Linuxが入っていた場所、Windowsのデータがある場所は、それぞれのディスクに対してなにか要求(読み書き)があったときだけマウントするよう設定します。

/etc/fstab
# /dev/sdc2
UUID=..   /run/media/hayattgd/Arch    ext4    noauto,x-systemd.automount,x-systemd.idle-timeout=600 . . .

# /dev/sdb2 LABEL=HDD
UUID=..   /run/media/hayattgd/HDD    ntfs    noauto,x-systemd.automount,x-systemd.idle-timeout=600 . . .

# /dev/sdc3 LABEL=Linux\134x20home
UUID=..   /home    ext4    noauto,x-systemd.automount,x-systemd.idle-timeout=300 . . .

これでアクセスしたときにマウントされて、一定時間アクセスがなければアンマウントする仕組みになりました。
再起動してみて、普通にログインしてみてもあまり遅い印象はありませんでした。

.socketがあるサービス類

.serviceに対応する.socketがある場合はサービスを無効化しておいても必要に応じてソケットが有効化してくれるので、サービスだけ無効化しておくと起動時にサービスがつかないので早くなります。

.socketがないが起動してすぐには使わないサービス

systemd-hostnamedsystemd-timesyncdなどは必要に応じて手動で起動すればいいので無効化しました。

しかしNetworkManagerなど、起動に直接関係はないがログイン後に必要になるものは.timerとスクリプトを組み合わせて作りました。

/usr/local/bin/start-delayed-services.sh
#!/bin/bash
systemctl start libvirtd.service
systemctl start NetworkManager.service
systemctl start avahi-daemon.service
systemctl start tor.service
systemctl start cockpit.socket
/etc/systemd/system/start-delayed-services.service
[Unit]
Description=Start delayed services to speed up boot

[Service]
Type=oneshot
ExecStart=/usr/local/bin/start-delayed-services.sh
/etc/systemd/system/start-delayed-services.timer
[Unit]
Description=Actual timer file for delayed services

[Timer]
OnBootSec=30s
AccuracySec=1s

[Install]
WantedBy=timers.target

loader (GRUB -> systemd-boot -> efistub)

前は機能が豊富なGRUBを使っていたのですが、その次に速度を優先してsystemd-boot、その次に一つのOSだけを起動することを目的にefistubにしました。

systemd-boot

systemd-bootではtimeout 0にしていてもスペースキーを押しているとOSを選べます
このメリットは他のOSも起動できるようにしつつ、起動速度は早くなることです。

しかしこれをやった後に何故かfirmwareが劇的に減ってloaderがちょい増えるという謎現象が発生
前後にBIOSアップデートやらカーネルの更新やらも挟んだのでそれが原因かも?
まあ総合的に起動時間は減ってるので結果オーライ

efistub

しかし、やっぱりloaderが増えてfirmwareが減るという謎現象が気になったので、efistubにしました。
これはUEFIから直接Linuxを起動する方法で、ブートローダーを挟まない(firmwareを除き)ので、最速の方法だと思います。
ただ、直でLinuxへ行くため、他のOSへ行くにはBIOSを経由しないといけません。

$ efibootmgr --create
    --disk /dev/sda
    --part 1
    --label "CachyOS-boot"
    --loader /vmlinuz-linux-cachyos
    --unicode 'root=UUID=c3ba369e-e2fc-430e-9b86-d3dba462a742 rw ... initrd=\initramfs-linux-cachyos.img'

結果発表

$ systemd-analyze #前の起動時間
Startup finished in 17.469s (firmware) + 6.790s (loader) + 11.084s (kernel) + 7.852s (userspace) = 43.196s 
graphical.target reached after 4.802s in userspace.

$ systemd-analyze #現在の起動時間
Startup finished in 21.492s (firmware) + 1.702s (loader) + 3.752s (kernel) + 1.956s (userspace) = 28.903s 
graphical.target reached after 1.806s in userspace.

43.196 - 28.903 = 14.293

14.239秒短縮できた

firmwareの時間は結構気まぐれです

Discussion