JetsonNano起動高速化

JetsonNanoの起動を高速化する。 Systemdサービスで不要なものを止めて起動を高速化してみる。 結果としては倍以上高速化することができた。

制限事項

今回計測するのはKernelが起動してから、初期化処理が終わるまでです。 実際にはその前にBIOSなど(L4TだとBootROMやCboot)が入るので、電源ONからの起動時間は表記+10秒程度はかかっています。

使ったイメージ

Jetpack 4.4イメージを使用した。ただし、パッケージなどいろいろと追加で入れているので参考まで。

developer.nvidia.com

ユースケース

自分の使用方法は下のような感じなので、最低限これができる用になればいい。ほかはすべて止める。

現状確認

下のコマンドで起動にかかる時間が調べられる。

$ systemd-analyze 
Startup finished in 7.068s (kernel) + 4.819s (userspace) = 11.887s
graphical.target reached after 4.799s in userspace

現状は11.9秒ほどかかっている模様。

GUICLI起動へ変更

CLI起動へ変更する。結果は以下の通り。

$ sudo systemctl set-default multi-user.target
$ sudo rebot

~~~ after rebot ~~~

$ systemd-analyze 
Startup finished in 1.743s (kernel) + 7.076s (userspace) = 8.820s
multi-user.target reached after 7.053s in userspace

8.8秒まで短縮された。2.9秒の改善。

解析

以下のコマンドでサービスのうち、起動処理のクリチカルチェインがわかる。 見方としては、@の後ろに書いてある時間がそのサービスが起動開始した時間、+の後ろに書いてある時間が起動にかかった時間である。ちなみに.targetはそれに必要なサービスを集めたものなので、それ自体に処理は存在しない。(例えばmulti-user.target はCLI起動に必要なサービスを集めたもの。Networkなどが含まれる。)

$ systemd-analyze critical-chain
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

multi-user.target @7.053s
└─networkd-dispatcher.service @1.247s +5.805s
  └─basic.target @1.049s
    └─sockets.target @1.049s
      └─snapd.socket @1.043s +5ms
        └─sysinit.target @1.038s
          └─systemd-timesyncd.service @821ms +217ms
            └─systemd-tmpfiles-setup.service @701ms +65ms
              └─local-fs.target @692ms
                └─local-fs-pre.target @692ms
                  └─keyboard-setup.service @443ms +248ms
                    └─systemd-journald.socket @433ms
                      └─system.slice @429ms
                        └─-.slice @417ms

見てみるとnetworkd-dispatcher.serviceが5.8秒と大きく足を引っ張っていそう。これをどうにかできないか考える。

networkd-dispatcher.serviceって何ぞ?

下記コマンドでサービスの説明や状態が確認できる。 "Dispatcher daemon for systemd-networkd"らしい。わからん。

$ systemctl status networkd-dispatcher.service
● networkd-dispatcher.service - Dispatcher daemon for systemd-networkd
   Loaded: loaded (/lib/systemd/system/networkd-dispatcher.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2021-01-14 22:08:56 JST; 31min ago
 Main PID: 3991 (networkd-dispat)
    Tasks: 2 (limit: 4174)
   CGroup: /system.slice/networkd-dispatcher.service
           └─3991 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
...

どうやらPython3で/usr/bin/networkd-dispatcherを実行しているらしい。中身を見ると、Wifiの設定やリゾルバの設定などを行っていた。以下はNetworkManagerの説明だが、DispacherはNetwork接続時に実行するプログラムを管理するためのものである模様。

wiki.archlinux.jp

また、これはsystemd-networkd用のサービスである。今回はNetworkManagerに統一するので停止してしまう。

$ sudo systemctl disable networkd-dispatcher.service
Removed /etc/systemd/system/multi-user.target.wants/networkd-dispatcher.service.
$ sudo rebot

~~~ after rebot ~~~

$ systemd-analyze 
Startup finished in 1.833s (kernel) + 4.640s (userspace) = 6.473s
multi-user.target reached after 4.614s in userspace

6.5秒まで短縮した。2.3秒の短縮。

個別にサービス停止

これ以降は大きな差がなかったので、すべてのサービスを見て不要なものは停止する。

$ systemctl -t service
UNIT                      LOAD   ACTIVE SUB     DESCRIPTION
alsa-restore.service      loaded active exited  Save/Restor
apport.service            loaded active exited  LSB: automa
avahi-daemon.service      loaded active running Avahi mDNS/
console-setup.service     loaded active exited  Set console
containerd.service        loaded active running containerd 
cron.service              loaded active running Regular bac
dbus.service              loaded active running D-Bus Syste
getty@tty1.service        loaded active running Getty on tt
grub-common.service       loaded active exited  LSB: Record
haveged.service           loaded active running Entropy dae
kerneloops.service        loaded active running Tool to aut
keyboard-setup.service    loaded active exited  Set the con
kmod-static-nodes.service loaded active exited  Create list
ModemManager.service      loaded active running Modem Manag
networking.service        loaded active exited  Raise netwo
NetworkManager.service    loaded active running Network Man
nv-l4t-usb-device-mode.service loaded active exited  Config
nvargus-daemon.service    loaded active running Argus daemo
nvgetty.service           loaded active running UART on tty
nvmemwarning.service      loaded active running Display Low
nvphs.service             loaded active running PHS daemon
nvs-service.service       loaded active running NVS-SERVICE
polkit.service            loaded active running Authorizati
resolvconf.service        loaded active exited  Nameserver 
rpcbind.service           loaded active running RPC bind po
rsyslog.service           loaded active running System Logg
serial-getty@ttyGS0.service loaded active running Serial Ge
serial-getty@ttyS0.service loaded active running Serial Get
setvtrgb.service          loaded active exited  Set console
snapd.seeded.service      loaded active exited  Wait until 
speech-dispatcher.service loaded active exited  LSB: Speech
ssh.service               loaded active running OpenBSD Sec
systemd-journal-flush.service loaded active exited  Flush J
systemd-journald.service  loaded active running Journal Ser
systemd-logind.service    loaded active running Login Servi
systemd-modules-load.service loaded active exited  Load Ker
systemd-random-seed.service loaded active exited  Load/Save
systemd-remount-fs.service loaded active exited  Remount Ro
systemd-resolved.service  loaded active running Network Nam
systemd-sysctl.service    loaded active exited  Apply Kerne
systemd-timesyncd.service loaded active running Network Tim
systemd-tmpfiles-setup-dev.service loaded active exited  Cr
systemd-tmpfiles-setup.service loaded active exited  Create
systemd-udev-trigger.service loaded active exited  udev Col
systemd-udevd.service     loaded active running udev Kernel
systemd-update-utmp.service loaded active exited  Update UT
systemd-user-sessions.service loaded active exited  Permit 
ubuntu-fan.service        loaded active exited  Ubuntu FAN 
user@1000.service         loaded active running User Manage
whoopsie.service          loaded active running crash repor
wpa_supplicant.service    loaded active running WPA supplic

  • alsa-restore.service: サウンド。停止。
  • apport.service: クラッシュ時のログ収集。残す。
  • avahi-daemon.service: ローカルネットワーク上のサービス検出(プリンタとか)。停止。
  • console-setup.service: コンソールの設定。サービスでわざわざ設定しなくても大丈夫では?停止。
  • containerd.service: Dockerの関係者。残す。
  • cron.service: プログラムなどを自動実行。停止。
  • dbus.service: Dbus。残す。
  • getty@tty1.service: TTY。残す。
  • grub-common.service: grubのなにか。grubは使ってないので停止。
  • ModemManager.service: モデム。使う予定ないので停止。(LTEとかつかうならいるかも。)

ちょっと多すぎるのでここまでで一旦試してみる。

$ sudo systemctl disable alsa-restore.service avahi-daemon.service console-setup.service cron.service grub-common.service ModemManager.service


Synchronizing state of avahi-daemon.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable avahi-daemon
Synchronizing state of cron.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable cron
grub-common.service is not a native service, redirecting to systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable grub-common
Removed /etc/systemd/system/dbus-org.freedesktop.Avahi.service.
Removed /etc/systemd/system/multi-user.target.wants/console-setup.service.
Removed /etc/systemd/system/sockets.target.wants/avahi-daemon.socket.
Removed /etc/systemd/system/dbus-org.freedesktop.ModemManager1.service.
Removed /etc/systemd/system/multi-user.target.wants/ModemManager.service.

ログを見ると、alsa-restore.service はDisableできていない。このように依存関係などによってDisableできない場合がある。そのときはDisableより強いmaskを使用する。これはそのサービスを/dev/nullにリンクしてしまう。そのため十分に注意して操作を行い、動作確認をしっかり行うこと。

$ sudo systemctl mask alsa-restore.service
Created symlink /etc/systemd/system/alsa-restore.service → /dev/null.

これで無効化できた。再起動して起動時間を計測。

$ sudo rebot

~~~ after rebot ~~~

$ systemd-analyze 
Startup finished in 1.767s (kernel) + 3.764s (userspace) = 5.532s
multi-user.target reached after 3.741s in userspace

結果

5.5秒まで短縮。最初と比較すると倍以上高速化することができた。

すべてのサービスは確認できていないので、また時間があるときにつづきやります。

また、maskした影響で、他のサービスがエラーになったりしていないか、下記のコマンドで確認しておく。

$ systemctl -t service