【Linux】カーネルビルドでも進捗が見たい!

2020/04/27

top view 1

top view 2

私はカジュアルにLinux kernelをビルドするのですが,進捗が表示されないのは困ります.

そこで, ビルドの進捗状況を表示するCLIツール「kbuild-progress」を作りました. より効率的な手法を思いつきましたので実装し直しました.こちらのkbuild-progressをお使いください(2021/07/31追記)

背景

私は大学院でLinux kernelに関する研究をしているため,1日に何度もkernelをビルドします.kernelはとても巨大なプログラムなので,(設定にもよりますが)新しめのノートPCでも ビルドに約30分 かかります.

ビルド作業といっても,基本的にコマンドを実行して待つだけです.ビルドを実行すると次のようなログが表示されます.

kernel buildの様子1

あとはひたすら待つだけです.

「…」

kernel buildの様子2

「…」

「これどのくらいかかるんだろう…」

「…」

kernel buildの様子3

「…」

「早く終わんねーかな」

「…」

kernel buildの様子4

「…」

「ビルドしてて暇だし,息抜きにゲームでもするかな!」

(ゲームを起動する)

kernel buildの様子5

「よーし,osuやるぞー!」

「…ん?」

kernel buildの様子6

ビルドおわってる…

(ゲームを終了する)

そうです.ビルドがどのくらい進んでいるのか,あとどのくらいで終わるのか, ビルドログからわからない のです.ビルドの進捗状況がわかれば,カジュアルにゲームをしたり,カジュアルにコンビニに行ったり,時間を有効に使えます.

kernelビルドでもプログレスバーのようなものが表示されたら便利ですよね.

タイトルロゴ

実装

ある時点での進捗は,「完了している仕事数 / 全体の仕事数」で表せます.どうにかしてこれら2つの数を取得しなくてはなりません.

そこでいろいろ考えた結果,ビルドをドライランする方法を思いつきました.kernelビルドにも使われているGNU Makeには,ドライランを行うオプションがあります.説明を見てみましょう.

-n, --just-print, --dry-run, --recon
実行するコマンドの表示だけを行い、 (特定の状況を除いては) 実際の実行を行わない。

https://linuxjm.osdn.jp/html/GNU_make/man1/make.1.html

いいですね.これでビルドコマンドの一覧がわかれば,ビルド対象ファイルの一覧が得られ,「全体の仕事数」がわかるかも.

make -n vmlinuxして,試しにコマンドを1つ見てみます.

set -e;  echo '  CC      scripts/mod/empty.o'; gcc -Wp,-MD,scripts/mod/.empty.o.d  -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/7/include -I./arch/x86/inclu
de -I./arch/x86/include/generated  -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -includ
e ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -
fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Wno-format-security -std=gnu89 -mno-sse -mno-mmx -mno-sse2 -mno-3d
now -mno-avx -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmo
del=kernel -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_AVX5
12=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -DCONFIG_AS_ADX=1 -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect
-branch-register -fno-jump-tables -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -O2 --param=allow-store-data-ra
ces=0 -Wframe-larger-than=2048 -fstack-protector-strong -Wno-unused-but-set-variable -Wimplicit-fallthrough -Wno-unused-const-variable -fomit-frame-pointer -fno
-var-tracking-assignments -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check
 -fconserve-stack -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init    -DKBUILD_MODFILE='"scripts/mod/empty"' -DKBUILD_BASENAME='"emp
ty"' -DKBUILD_MODNAME='"empty"' -c -o scripts/mod/empty.o scripts/mod/empty.c; scripts/basic/fixdep scripts/mod/.empty.o.d scripts/mod/empty.o 'gcc -Wp,-MD,scri
pts/mod/.empty.o.d  -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/7/include -I./arch/x86/include -I./arch/x86/include/generated  -I./include -I./arch/x86/inc
lude/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -include ./include/linux/compiler_t
ypes.h -D__KERNEL__ -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-dec
laration -Werror=implicit-int -Wno-format-security -std=gnu89 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -m
no-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DC
ONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_AVX512=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -DCONFIG_AS_
ADX=1 -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -fno-jump-tables -fno-delete-null-pointer-chec
ks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -O2 --param=allow-store-data-races=0 -Wframe-larger-than=2048 -fstack-protector-strong -Wno-un
used-but-set-variable -Wimplicit-fallthrough -Wno-unused-const-variable -fomit-frame-pointer -fno-var-tracking-assignments -Wdeclaration-after-statement -Wvla -
Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=date-time -Werror=incompatible-pointe
r-types -Werror=designated-init    -DKBUILD_MODFILE='\''"scripts/mod/empty"'\'' -DKBUILD_BASENAME='\''"empty"'\'' -DKBUILD_MODNAME='\''"empty"'\'' -c -o scripts
/mod/empty.o scripts/mod/empty.c' > scripts/mod/.empty.o.cmd; rm -f scripts/mod/.empty.o.d

長すぎぃ!

おちついて興味のない部分を消します…

gcc -o scripts/mod/empty.o scripts/mod/empty.c

おー!ビルド対象のオブジェクトファイルがわかりますね!テキスト処理でなんとかなりそうです!

では,「ある時点で完了している仕事数」はどのように分かるでしょうか.つまり,「各オブジェクトファイルのビルドが完了したか」判定したいわけです.

いろいろ考えた結果,タイムスタンプを見るのがもっとも手軽だろうと判断しました..configファイルと各オブジェクトファイルのタイムスタンプを比較します.

.configというファイルには,kernelビルドのための設定が書き込まれており,ビルドを実行するごとに更新されます.そのため,

  • .configより新しいタイムスタンプを持つオブジェクトファイルは,ビルドが完了しているファイル
  • .configより古いタイムスタンプを持っていたり,そもそもオブジェクトファイルが存在していない場合は,まだビルドが完了していないファイル

ということです.

Node.js + TypeScriptでCLIツール を書く

フロントエンドの人間なので,TSでさっくり書こうと思います.

まず,node.jsのspawnでmakeを呼び出し,ビルド対象のオブジェクトファイルの一覧を得ます.そして,定期的に,findコマンドの-newerオプションを使って,.configファイルよりも新しいオブジェクトファイルをリストします.ビルド対象のオブジェクトファイルが全て更新されたら,kernelビルド完了です!

プログレスバーの表示や残り時間の計算にはnpmのprogressを使います.シンプルでおすすめです.

あとはゴリゴリ実装すれば…

kbuild-progress demo

kbuild-progress

エモい!

さいごに

最近は新型コロナウイルスのせいで大学の高性能なサーバーが使えず,自宅のラップトップでビルド作業を行っていました.そのため,ビルドにかかる時間が大幅に伸びてしまい,暇だったのです.

今回のツールによって,暇な時間を有効活用できそうですし,開発自体が良い暇つぶしになりました.

ツールの開発をしていく上でLinux kernelのMakefileを読んだ話を別の記事に書きました.makeに興味がある方はどうぞご覧ください.

kernelビルドにプログレスバーがついて大変満足です.

続けて読む…

Linux kernelのMakefileを雰囲気で読んだ話

2020/04/28

シングルユーザーモードのUbuntuにSSHする(SSH to Single User Mode Ubuntu 18.04)

2020/10/25

Blenderでアニメ調にレンダリングしてみる

2017/01/28

Dockerで簡単TeX環境構築

2020/01/07

夏だからGatsbyのランタイム全部消す

2021/08/02

モーショントラッキングリベンジ(Blender)

2017/06/19

書いた人

sititou70のアイコン画像
sititou70

都内の社会人エンジニア3年生。Web技術、3DCG、映像制作が好き。