【前文】
公式 にもある通り、カーネルのビルド方法は大きく分けて以下の 2パターン。
- Raspberry Pi本体でのローカルビルド
- PC や 仮想環境(VirtualBox や VMWare)でのクロスビルド
前者は Raspberry Pi本体だけで済むし、ビルド、インストールをシームレスに行うことができて初学者向け。
しかし Pi4B でもビルドに 1時間強もかかるのが。膨大な量のソースをコンパイルするから、せめて RAMディスク上で作業すれば速くなるのかな?
という素朴な疑問が出発点。
しかし目を見張るほどの時間短縮はせず。何がボトルネック? やはり CPUパワー? ならばオーバークロックでしょ。
と試してみるも、やはりあまり変わらなかった。
残念な結果だったけど折角なので記録として残す。
ビルド時間は以下。
ケース | ビルド時間 |
---|---|
microSDカード上ビルド | 61m42.817s |
RAMディスク上ビルド | 57m33.457s |
RAMディスク上 + オーバークロックでビルド | 56m42.724s |
作業環境は以下。
Pi | OS | Kernel |
---|---|---|
Raspberry Pi4B 4G | Raspberry Pi OS Lite / Raspbian GNU/Linux 10 (buster) | 5.10.17-v7l+ |
と書いていて気が付いたけど、「Raspberry Pi OS」に名称が変更された筈なのに、内部的にはまだ「Raspbian」なんだね。
pi@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 10 (buster)
Release: 10
Codename: buster
pi@raspberrypi:~ $
CUI環境での作業になるので Raspberry Pi OS Lite を使用。
RAMディスク設定、CPUオーバークロック設定、カーネルビルド方法はぐぐれば沢山出てくるけど、ワンセットとなると見かけないので以下に手順を記す。
【RAMディスク設定】
microSDカードの寿命延命目的でRAMディスクの利用は Raspberry Pi で鉄板ネタ。
解説サイトは沢山あるけど、こちら がシンプルで分かりやすい。必要にして十分な内容。これを参考に設定した。
pi@raspberrypi:~ $ cat /etc/fstab
proc /proc proc defaults 0 0
PARTUUID=b8f462a2-01 /boot vfat defaults 0 2
PARTUUID=b8f462a2-02 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
tmpfs /mnt/ramdisk tmpfs defaults,noatime,mode=755,uid=pi,gid=pi,size=3g,nofail 0 0
pi@raspberrypi:~ $
但し、カーネルビルドに 2G では足りないので、3Gに設定している。
因みに size
パラメータに小数指定は許可されていないようで、「3G じゃなくて 2.7G」とか思って設定するとコケるので注意。
更に fstab って記述にミスがあるとそれだけで起動に失敗する(Linuxあるある)。念の為、オプションに nofail
を追加した。
4G中、3G も RAMディスクに割り当てるのはバランスが悪い気もするけど、ソースだけで 1Gを超えるしデバッグオプションを有効にしたビルドとなれば 3Gでも足りない。8G版で 4~5G を RAMディスクに割り当てての作業になると思う。
8G版なんて、そんなにメモリ必要ないでしょ、と個人的には思っていたけど、RAMディスクを活用しようとすると考え方も変わってくるね。
fstab に RAMディスクの設定を追記し再起動したら、df
コマンドで /mnt/ramdisk
にマウントされていることを確認。
pi@raspberrypi:~ $ df -h
ファイルシス サイズ 使用 残り 使用% マウント位置
/dev/root 3.9G 2.6G 1.1G 71% /
devtmpfs 1.8G 0 1.8G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 1.9G 8.5M 1.9G 1% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
tmpfs 3.0G 0 3.0G 0% /mnt/ramdisk
/dev/mmcblk0p1 253M 48M 205M 19% /boot
tmpfs 383M 0 383M 0% /run/user/1000
pi@raspberrypi:~ $
ついでに以下のコマンドでベンチマーク。
dd if=/dev/zero of=temp.txt bs=1M count=1024
sync; echo 3 > /proc/sys/vm/drop_caches
dd if=temp.txt of=/dev/null bs=1M count=1024
dd if=/dev/zero of=temp.txt bs=1G count=1
sync; echo 3 > /proc/sys/vm/drop_caches
dd if=temp.txt of=/dev/null bs=1G count=1
コマンドはやはり前述のサイトを参考にさせて頂いた。しかしキャッシュクリア処理が無かったので追加した。
これをやらないと microSDカード上の読込が RAMディスクと変わらないという結果になるので。(キャッシュの有用性が良く分かる事例ではあるけど)
結果は以下。
デバイス | データ量 | 書込 | 読込 |
---|---|---|---|
microSD | 1.0GiB(1M×1024) | 18.2 MB/s | 45.4 MB/s |
microSD | 1.0GiB(1G×1) | 16.0 MB/s | 45.5 MB/s |
RAMディスク | 1.0GiB(1M×1024) | 310 MB/s | 583 MB/s |
RAMディスク | 1.0GiB(1G×1) | 180 MB/s | 265 MB/s |
厳密には 5~10回計測しその平均、とかだろうから、上記は参考記録程度に。
【オーバークロック設定】
これも鉄板ネタなので解説サイトは沢山あるけど、こちら を参考にさせて頂いた。
/boot/config.txt
の設定値は以下。
over_voltage=2
arm_freq=1750
CPUクロック数、温度、電圧確認コマンドは以下。
vcgencmd measure_clock arm && vcgencmd measure_temp && vcgencmd measure_volts
アイドル時の計測結果は以下。
frequency(48)=600169920
temp=45.7'C
volt=0.9125V
ビルド中の計測結果は以下。
frequency(48)=1750412160
temp=58.4'C
volt=0.9125V
CPU冷却ファンクーラ付きケース が早速役に立った。常時運用でも問題ないかな?
というかそもそも 1.75GHz ってのが弱いのかなぁ。2GHz はいけるって話もあるけどそこまでは未確認。
【RAMディスク上でのカーネルビルド】
1. ビルドツールインストール
公式 に従い、以下のコマンドでGitとビルドの依存関係をインストール。
sudo apt install git bc bison flex libssl-dev make -y
更に こちら によれば、以下も必要らしいので実行。
sudo apt-get install -y -qq --no-install-recommends make libncurses-dev kernel-package
sudo apt-get install -y -qq --no-install-recommends bison flex
2. バックアップ
必要があれば現在の microSDをイメージバックアップ。
カーネル関連のファイル単位でバックアップする手もあるけど、リカバリの際カーネルドライバはファイルだけ戻せば良いって話でもないし。
ここら辺を分かっていない場合はイメージバックアップの方が確実。
3. カーネルソース取得
明示的に取得パスを指定しない場合、/usr/src/
配下にダウンロードされる。
今回は RAMディスク上での作業なので、以下のようにパスを指定し実行。
sudo git clone --depth=1 https://github.com/raspberrypi/linux /mnt/ramdisk/linux
実行結果は以下。
pi@raspberrypi:~ $ sudo git clone --depth=1 https://github.com/raspberrypi/linux /mnt/ramdisk/linux
Cloning into '/mnt/ramdisk/linux'...
remote: Enumerating objects: 75497, done.
remote: Counting objects: 100% (75497/75497), done.
remote: Compressing objects: 100% (72055/72055), done.
remote: Total 75497 (delta 6055), reused 15825 (delta 2645), pack-reused 0
Receiving objects: 100% (75497/75497), 199.16 MiB | 3.25 MiB/s, done.
Resolving deltas: 100% (6055/6055), done.
Checking out files: 100% (71110/71110), done.
pi@raspberrypi:~ $
取得したソースディレクトリに移動し取得したブランチを確認。
cd /mnt/ramdisk/linux
git branch
実行結果は以下。
pi@raspberrypi:~ $ cd /mnt/ramdisk/linux
pi@raspberrypi:/mnt/ramdisk/linux $ git branch
* rpi-5.10.y
pi@raspberrypi:/mnt/ramdisk/linux $
rpi-5.10.y
であることが分かる。
因みに明示的にブランチを指定し取得する場合は以下。
sudo git clone --depth=1 --branch rpi-5.10.y https://github.com/raspberrypi/linux /mnt/ramdisk/linux
リモート側のブランチの一覧を確認したい場合は、git ls-remote
コマンドで。
pi@raspberrypi:/mnt/ramdisk/linux $ git ls-remote | grep rpi-5.
From https://github.com/raspberrypi/linux
0222b82b2f1fcf1e0c477f77c50688c98f35e2bf refs/heads/rpi-5.0.y
29ee73a82540e8b94c6bde0ad1acae65f73653ea refs/heads/rpi-5.1.y
13c43880f2ee6db7d26949cb6a3e8db1a4b76736 refs/heads/rpi-5.10.y
2cbd302b1e200073ecf52b2f96e619c9561625a1 refs/heads/rpi-5.11.y
425ed5a960386760d811aee0ad7fd5b0a6e37b22 refs/heads/rpi-5.12.y
94dbfa7606fc2f3df44979ed9c2d1d3676f2c159 refs/heads/rpi-5.2.y
32ba05a62a8071d091d7582cc37b4bac2962b1dd refs/heads/rpi-5.3.y
93349cdffc3fbb446c7c1fc7354215a5b8e30b97 refs/heads/rpi-5.4.y
96a3278497cc6540d32dc4a7dba9100da6df16f0 refs/heads/rpi-5.5.y
ff0aa78166a59d44bc8d472386699624c8db6da5 refs/heads/rpi-5.6.y
fe872d026d3a280a5151af08eb949eddf586fa1b refs/heads/rpi-5.7.y
9b3199ca416d89b1f810fc65d8ffe1ad2a03ac0e refs/heads/rpi-5.8.y
104137d44c6365fafc36ec1ea59db06f58ef5dfc refs/heads/rpi-5.9.y
e850ab437a2d0fa607d410b7bae62f90fb941430 refs/tags/rpi-5.10.y_20201122
pi@raspberrypi:/mnt/ramdisk/linux $
rpi-5系は 12 まである模様。
取得したカーネルソースのバージョン確認。
pi@raspberrypi:/mnt/ramdisk/linux $ head Makefile -n 5
# SPDX-License-Identifier: GPL-2.0
VERSION = 5
PATCHLEVEL = 10
SUBLEVEL = 23
EXTRAVERSION =
pi@raspberrypi:/mnt/ramdisk/linux $
5.10.23
ってことになるだんけど、現在最新の安定バージョンは 5.10.17
。
pi@raspberrypi:/mnt/ramdisk/linux $ uname -r
5.10.17-v7l+
pi@raspberrypi:/mnt/ramdisk/linux $
最新の安定バージョンのソースを取得したい場合は? という疑問が湧いてくるけどそれは後述。
4. カーネルソースバックアップ
取得したカーネルソースは RAMディスク上なので電源を落とせば消えてしまう。後日再実行する場合など、再取得は面倒で時間がかかる。必要があればバックアップを取り、再実行時はそれを展開する。
/usr/src/linux.rpi-5.10.y.tar.gz
として圧縮バックアップするコマンド例は以下。
sudo tar -C /mnt/ramdisk -zcf /usr/src/linux.rpi-5.10.y.tar.gz linux
それをリストアするコマンド例は以下。
sudo rm -rf /mnt/ramdisk/linux
sudo tar -zxf /usr/src/linux.rpi-5.10.y.tar.gz -C /mnt/ramdisk
と書いていて思ったんだけど、だったら最初っから圧縮形式でダウンロードした方が速くないかい? って話もあり、その場合は以下。
curl -L https://github.com/raspberrypi/linux/archive/refs/heads/rpi-5.10.y.zip > rpi-5.10.y.zip
5. カーネルビルド
ローカルビルドの場合、公式配布のカーネルと区別する為、Makefile
の EXTRAVERSION
定義にそれとわかる文字列を設定しておくのがお約束。ログイン時や uname
コマンド等でカーネルバージョンが表示される場合、この定義も表示される。
設定コマンド例は以下。
cd /mnt/ramdisk/linux
sudo sed -i 's/EXTRAVERSION =/EXTRAVERSION = -god/g' Makefile
grep 'EXTRAVERSION =' Makefile
実行結果は以下。
pi@raspberrypi:/mnt/ramdisk/linux $ cd /mnt/ramdisk/linux
pi@raspberrypi:/mnt/ramdisk/linux $ sudo sed -i 's/EXTRAVERSION =/EXTRAVERSION = -god/g' Makefile
grep 'EXTRAVERSION =' Makefilepi@raspberrypi:/mnt/ramdisk/linux $ grep 'EXTRAVERSION =' Makefile
EXTRAVERSION = -god
pi@raspberrypi:/mnt/ramdisk/linux $
以下コマンドでビルド。
KERNEL=kernel7l
sudo make bcm2711_defconfig
time sudo make -j4 zImage modules dtbs
ビルド時間が分かるよう time
コマンドで実行している。ここで 1時間前後かかる。不要であれば勿論単に sudo make -j4 zImage modules dtbs
で構わない。
実行結果は以下。
pi@raspberrypi:/mnt/ramdisk/linux $ KERNEL=kernel7l
pi@raspberrypi:/mnt/ramdisk/linux $ sudo make bcm2711_defconfig
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
HOSTCC scripts/kconfig/confdata.o
HOSTCC scripts/kconfig/expr.o
LEX scripts/kconfig/lexer.lex.c
YACC scripts/kconfig/parser.tab.[ch]
HOSTCC scripts/kconfig/lexer.lex.o
HOSTCC scripts/kconfig/parser.tab.o
HOSTCC scripts/kconfig/preprocess.o
HOSTCC scripts/kconfig/symbol.o
HOSTCC scripts/kconfig/util.o
HOSTLD scripts/kconfig/conf
#
# configuration written to .config
#
pi@raspberrypi:/mnt/ramdisk/linux $ time sudo make -j4 zImage modules dtbs
(中略)
LD [M] sound/usb/hiface/snd-usb-hiface.ko
LD [M] sound/usb/misc/snd-ua101.ko
LD [M] sound/usb/snd-usb-audio.ko
LD [M] sound/usb/snd-usbmidi-lib.ko
real 56m42.724s
user 193m28.695s
sys 29m5.682s
pi@raspberrypi:/mnt/ramdisk/linux $
6. カーネル更新
カーネルビルドに成功したら、以下コマンドで自身のカーネルを上書き更新。
sudo make modules_install
sudo cp arch/arm/boot/dts/*.dtb /boot/
sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/
sudo cp arch/arm/boot/zImage /boot/$KERNEL.img
因みに最初の 1行目はカーネルドライバの更新。
make modules_install
コンパイルされたモジュールが /lib/modules/<kernel version>-<config local version> にコピーされます
手動でインストールしていたドライバがあれば入れ直すこと。
sudo reboot
で再起動。
再起動後、ログインしカーネルのバージョン確認。
Linux raspberrypi 5.10.23-god-v7l+ #1 SMP Sat Mar 20 23:10:25 JST 2021 armv7l
(中略)
pi@raspberrypi:~ $ uname -a
Linux raspberrypi 5.10.23-god-v7l+ #1 SMP Sat Mar 20 23:10:25 JST 2021 armv7l GNU/Linux
pi@raspberrypi:~ $ uname -r
5.10.23-god-v7l+
pi@raspberrypi:~ $
【任意のカーネルソースの取得】
ピンポイントでの任意のカーネルソースの取得方法が良く分からず悩んだ。
2021年3月現在、安定バージョンの最新は 5.10.17
。これを取得したいとする。
最初は こちら を参考にさせて頂いたが上手くいかず。
糸口になったのが こちら。そしてやっと辿り着いたのが こちら。
ハッシュ値 13b6016e96f628ac1cfb3c0b342911fd91c9c005
が分かれば以下のように取得できる。
pi@raspberrypi:/mnt/ramdisk $ curl -L https://github.com/raspberrypi/linux/archive/13b6016e96f628ac1cfb3c0b342911fd91c9c005.tar.gz > linux.rpi-5.10.17.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 159 100 159 0 0 398 0 --:--:-- --:--:-- --:--:-- 398
100 176M 0 176M 0 0 3522k 0 --:--:-- 0:00:51 --:--:-- 3524k
pi@raspberrypi:/mnt/ramdisk $
更に確認すると、これって要するに リリース一覧 の最新である raspberrypi-kernel_1.20210303-1
。


リリース一覧の最新がつまり安定板の最新って当たり前か。
でもこの年月日系のタグからカーネルのバージョンはどうやって判断するの? 月一で SUBLEVEL
が上がっているっぽいからそこから判断?
ここら辺は運用を知らないと分からないよね。慣れていくしかないのかな。
それと最後に。
速度面ではあまり真価を発揮できなかった RAMディスクだけど、microSDカードの消耗を抑える点では有用なので活用すべきでは。