前回は主にsystemctlを使っていろいろいじってだいたい17秒短縮できました。
しかし、「やっぱり30秒近くあるのって長くね?」と思ってしまいました。
そこで今回はできるだけではなく極限まで短くするというのを目標にしていきます。
(前回やった最適化もここに書きますのでわざわざ前のは見なくても大丈夫です)
環境
$ 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)
後からカスタマイズしやすいものは
- Artix Linux(いろいろなinitから選べる)
- CachyOS(またはArch Linux)(カーネルがカスタマイズされてる)
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.confのHOOKで使わないものを削る(自分の場合はplymouth)
MODULESにはnvidia系しかないので削れませんでした。
圧縮方式をlz4にしてオプションに-1を指定することでサイズは多少大きくなるかもしれませんが、最速の読み込みができます。
カーネルのコンパイル
カーネルをlinux-cachyos-gccからlinux-cachyos-eevdf-ltoに変えるついでに色々コンフィグをいじって自分のパソコンの構成に最適化するようにしました。
カーネルのコンフィグでmodprobed-dbというものを使うと今の起動で使われたモジュールのみを含むようになるのでコンパイルは早く、サイズも小さくなります。
ですが、逆に今使っていないキーボードなどが使えないので気をつけましょう
なので今回はmodprobed-dbを無効化した構成になります
cachyos-kernel-managerを使ってコンパイルしたので実際の値の名前と異なっているかもしれません
| 名前 | 値 |
|---|---|
| Enable LTO | Thin |
| CPU compiler optimizations | Native Intel |
| Disable NUMA | 有効 |
カーネルパラメーター
systemd.zram=0を渡してzramを無効化しておきました。
効果があるのかは知りませんがRAMがおかしいほどにあるのでメモリが大量に消費されることになっても大丈夫でしょう多分きっとおそらく99%
userspace (systemd)
ここに関してはsystemdからopenrcやrunitに乗り換えることも検討しましたが、仮想環境でやってみたらほぼ同じ速度(なんならsystemdの方がちょい早い)感じだったのと、systemdから乗り換えるならLinuxディストリビューションごと移動しないと互換性が終わってたりするのでsystemdのままにしました
ディスクのマウント
目標は起動速度の最適化なので/dev/sdc3(/home)や前のArch Linuxが入っていた場所、Windowsのデータがある場所は、それぞれのディスクに対してなにか要求(読み書き)があったときだけマウントするよう設定します。
# /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 . . .
これでアクセスしたときにマウントされて、一定時間アクセスがなければアンマウントする仕組みになりました。
再起動してみて、普通にログインしてみてもあまり遅い印象はありませんでした。
ここで指定しても自動的にマウントされてしまう場合はなにかのサービスがそのディスクを必要としていないか確認(特にlibvirtd)
.socketがあるサービス類
.serviceに対応する.socketがある場合はサービスを無効化しておいても必要に応じてソケットが有効化してくれるので、サービスだけ無効化しておくと起動時にサービスがつかないので早くなります。
.socketがないが起動してすぐには使わないサービス
systemd-hostnamedやsystemd-timesyncdなどは必要に応じて手動で起動すればいいので無効化しました。
しかしNetworkManagerなど、起動に直接関係はないがログイン後に必要になるものは.timerとスクリプトを組み合わせて作りました。
#!/bin/bash
systemctl start libvirtd.service
systemctl start NetworkManager.service
systemctl start avahi-daemon.service
systemctl start tor.service
systemctl start cockpit.socket
[Unit]
Description=Start delayed services to speed up boot
[Service]
Type=oneshot
ExecStart=/usr/local/bin/start-delayed-services.sh
[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の時間は結構気まぐれです
