はじめに
bitbakeではShared State Cache(sstate-cache)という仕組みを持っていて、今回ビルドしたいものが前回ビルドしたものと変更がなければ、成果物をそのまま再利用するようになっている。
手っ取り早い方法は複数のビルドディレクトリのlocal.confで設定されるSSTATE_DIR
を同じディレクトリに設定すること。
この仕組みをリモート間でも共有できるようにbitbake-hashserv
というツールが提供されている。
今回はbitbake-hashservをunix domain socketで使用してみる。
Shared State Cacheの仕組み
ざっくりとsstate-cacheの仕組みを説明すると下記のようになる。
初回実行時
- bitbakeで実行されるタスクのインプットデータについてハッシュを取っておく
- そのハッシュとタスクのアウトプットデータのマッピング情報を保存しておく
- アウトプットデータの情報は捨てずに取っておく
再実行時
- 今回実行されるタスクのインプットデータのハッシュとsstate-cache内のハッシュが一致するか確認する
- 一致した場合そのタスクは処理しない(一致しない場合はタスクを実行して3のプロセスはスキップ)
- 処理しないタスクのアウトプットデータをクライアントに供給する
bitbake-hashservについて
unix domain socketでの接続
bitbake-hashservはunix domain socketでも通信できるようになっていて、ローカルのPC内でもShared Stateを共有できるようになっている。 単にSSTATE_DIRを共有することとの違いは後から参照するbitbakeによってもともとあるsstate-cacheが破壊されづらいという利点がある。 bitbake-hashservは起動時にリードオンリーモードを指定できるため、更に安全に運用することができる。
短所としてはデータがコピーされるため同一PC内ではsstate-cacheに使用されるストレージ容量が増加してしまうところ。
BB_SIGNATURE_HANDLER
に「OEEquivHash」を設定してbitbakeを実行するとcache/hashserv.db
が作成される。
これはSQLiteのデータベースとなっており、タスクのインプットデータのハッシュとアウトプットデータのマッピング情報を持っている。
また、OEEquivHashの「Equiv」はEquivalenceの略で、インプットデータ中の空白など実体に関係ない差分は「同一とみなす」という処理を行っている。これによりsstate-cacheの適用可能性が高くなるようになっている。
bitbake-hashservの実行
サーバ側の設定
サーバとなる初回ビルドを行う環境についてはlocal.confにこのような設定があれば良い。
BB_HASHSERVE = "auto" BB_SIGNATURE_HANDLER = "OEEquivHash"
このままbitbakeを実行して「hashserv.db」と「sstate-cache」が生成されれば必要なデータは揃う。 もちろん初回実行時なので数時間はかかる。
サーバ側環境の構築
実際にbitbake-hashservを動かす環境を作成してみる。
$ mkdir -p ~/yocto/rpi-kirkstone $ cd ~/yocto/rpi-kirkstone $ git clone git://git.yoctoproject.org/poky.git -b kirkstone $ source poky/oe-init-build-env build-hashserv $ bitbake-layers layerindex-fetch meta-raspberrypi
local.confに下記を追加する。
MACHINE = "raspberrypi4-64" # setup for hashserv database BB_SIGNATURE_HANDLER = "OEEquivHash" # enable uart ENABLE_UART = "1" # systemd INIT_MANAGER = "systemd"
試しにcore-image-base
をビルドする。
今回はtimeコマンドで時間を計測する。
$ time bitbake core-image-base ... (snip) ... real 84m43.468s user 0m29.526s sys 0m9.020s
まっさらな状態でビルドした結果、約85分かかった。
bitbake-hashservの起動
この状態でcacheディレクトリを覗くと下記のようにhashserv.db
が生成されていることがわかる。
~/yocto/rpi-kirkstone/build-hashserv$ ls ./cache/ bb_codeparser.dat bb_unihashes.dat local_file_checksum_cache.dat bb_persist_data.sqlite3 hashserv.db sanity_info
これを使用してbitbake-hashserve
を起動する。接続状況を把握しやすいようにログレベルをdebugに指定している。
$ bitbake-hashserv -r -l debug -d ./cache/hashserv.db -b "unix://./hashserv.sock"
今回は「unix://./hashserv.sock」で待ち受けしているため、${HOME}/yocto/rpi-kirkstone/build-hashserv/hashserv.sock
に接続することでサーバと通信できる。
bitbake-hashservへの接続
クライアント側の設定
実行中のbitbake-hashservに接続するにはlocal.confに次のような設定を行う。
BB_SIGNATURE_HANDLER = "OEEquivHash" BB_HASHSERVE = "unix://${HOME}/yocto/rpi-kirkstone/build-hashserv/hashserv.sock" SSTATE_MIRRORS = "file://.* file://${HOME}/yocto/rpi-kirkstone/build-hashserv/sstate-cache/PATH"
BB_HASHSERVE
にはbitbake-hashserv実行時に作成されたunix domain socketのファイルを指定する。
SSTATE_MIRRORS
にはサーバ側の初回ビルド時に作成されたsstate-cacheの保存場所を指定する。
つまり、サーバが提供するsstate-cacheの在処となる。
PATH
と指定することでsstate-cacheディレクトリ以下の構造をbitbakeが展開できるようになる。
クライアント側環境の構築
実際にbitbake-hashservに接続する環境を作成してみる。
サーバ側とは別の端末を開き下記を実行する。
$ cd ~/yocto/rpi-kirkstone $ source poky/oe-init-build-env build-client $ bitbake-layers add-layer ../poky/meta-raspberrypi
local.confに下記を記載する。
MACHINE = "raspberrypi4-64" # setup for connecting to bitbake-hashserv BB_SIGNATURE_HANDLER = "OEEquivHash" BB_HASHSERVE = "unix://${HOME}/yocto/rpi-kirkstone/build-hashserv/hashserv.sock" SSTATE_MIRRORS = "file://.* file://${HOME}/yocto/rpi-kirkstone/build-hashserv/sstate-cache/PATH" # enable uart ENABLE_UART = "1" # systemd INIT_MANAGER = "systemd"
bitbake-hashservへの接続
接続のための設定をlocal.confに行ったため、bitbakeを実行してみる。
$ time bitbake core-image-base ... (snip) ... real 1m43.522s user 0m1.438s sys 0m0.472s
bitbake-hashservの提供するsstate-cacheを参照することでビルド時間が劇的に短くなることがわかる。
サーバ側のログ
この時のサーバ側のログの表示は下記のようになっており、外部から接続されデータを供給したことが伺える。
$ bitbake-hashserv -r -l debug -d ./cache/hashserv.db -b "unix://./hashserv.sock" Listening on './hashserv.sock' Client '' connected Handling get-stream Client disconnected
まとめ
bitbakeではもともと実装されていたsstate-cacheを他のビルド環境から参照することでビルド時間が劇的に改善することがわかった。 もちろん別のMACHINE向けのビルドだったり、参照するレシピが更新されていたりして保存されているsstate-cacheと入出力が異なる場合はタスクが実行されるためこの効果は薄いもしくは無い。
bitbake-hashservを使用することで直接SSTATE_DIR
を共有しなくても、既存のsstate-cacheを参照できることがわかった。
今回はunix domain socketで同一ホストのデータを参照したが、リモートで提供されているsstate-cacheを参照できそうなこともわかった。
機会があれば実際にリモートのsstate-cacheを提供/参照する方法も試してみたい。