Bazel の並列評価とインクリメンタリティ モデル。
データモデル
データモデルは次の項目で構成されます。
SkyValue
。ノードとも呼ばれます。SkyValues
は変更不可オブジェクトであり、 構築の過程で構築されたすべてのデータと、 表示されます。例: 入力ファイル、出力ファイル、ターゲット、構成済み できます。SkyKey
。SkyValue
を参照する短い不変名。例:FILECONTENTS:/tmp/foo
またはPACKAGE://foo
。SkyFunction
。鍵と依存ノードに基づいてノードを構築する。- ノードグラフ。依存関係を含むデータ構造は、 説明します。
Skyframe
。増分評価フレームワーク Bazel のコードネームは次のとおりです。 基づきます。
評価
ビルドは、ビルド リクエストを表すノードを評価することによって行われます。
まず、Bazel は、トップレベルのキーに対応する SkyFunction
を検出します。
SkyKey
。関数が次に、実行する必要があるノードの評価を
最上位ノードを評価して、他の SkyFunction
呼び出しを発生させます。
到達するまで待機しますリーフノードは通常
入力ファイルに保存することもできます。最後に、Bazel は
トップレベルの SkyValue
、一部の副作用(ファイル内の出力ファイルなど)
システム)とノード間の依存関係の有向非巡回グラフ
関係します。
SkyFunction
は、認識できない場合、複数のパスで SkyKeys
をリクエストできます。
すべてのノードを前進させることができます簡単な例を挙げると
入力ファイル ノードがシンボリック リンクになることが判明した場合: この関数は
そのファイルがシンボリック リンクであると認識し、ファイル システム ノードをフェッチします。
シンボリック リンクのターゲットを表します。しかし、それ自体がシンボリック リンクになり得ます。
この場合、元の関数もターゲットをフェッチする必要があります。
関数は、コードではインターフェース SkyFunction
と
SkyFunction.Environment
というインターフェースによって提供されるサービス。これらの
関数でできることは次のとおりです。
env.getValue
を呼び出して、別のノードの評価をリクエストします。条件 ノードが使用可能である場合はその値が返されます。それ以外の場合はnull
が返されます 関数自体はnull
を返すことが想定されています。後者の場合 依存ノードが評価され、元のノードビルダーが 再度呼び出されましたが、今回は同じenv.getValue
呼び出しにより 非null
値。env.getValues()
を呼び出して、他の複数のノードの評価をリクエストします。 これは基本的に同じです。ただし、依存ノードが 並列して評価されます- 呼び出し中に計算を実行する
- ファイル システムへのファイルの書き込みなど、副作用がある。治療ニーズ 2 つの異なる関数が互いの処理を 回避できるようにすることを つま先。一般的に、書き込みの副作用(データが Bazel から外部に流れる) 読み取りの副作用(データが内部に流れ込み、 登録済みの依存関係)は、未登録の依存関係であるため、該当しません。 不正確な増分ビルドが発生する可能性があります。
SkyFunction
を適切に実装することで、他のいかなる方法でもデータへのアクセスを回避できます
(ファイル システムを直接読み取るなどの方法で)リクエストするよりも、
Bazel でデータの依存関係がファイルに登録されなくなるためです。
正しくない増分ビルドが発生していました。
関数がジョブの実行に十分なデータを取得すると、null
以外の値を返す必要があります。
完了を示す値。
この評価戦略には、次のような利点があります。
- 密閉性。関数が入力データをリクエストするのは、 Bazel は、入力状態が同じであれば、すべての Pod が 同じデータが返されますすべての Sky 関数が決定論的であれば、 ビルド全体が決定的になります。
- 正確かつ完全なインクリメンタリティすべての関数のすべての入力データが 記録された場合、Bazel は必要な一連のノードのみを 入力データが変更されたときに無効になります。
- 並列処理。関数同士を相互作用させるには、 互いに依存しない関数は、別のモジュールへの 実行すれば、Bazel は実行時と同じ結果を 順番に実行されました
インクリメンタリティ
関数は他のノードに依存してのみ入力データにアクセスできるため、Bazel 入力ファイルから出力までの完全なデータフロー グラフを この情報を使用して、実際に必要なノードのみを 再ビルド対象: 変更された入力ファイルセットの逆推移的クロージャ。
特にインクリメンタリティ戦略として、ボトムアップ戦略が 2 つ考えられる。 2 つのタイプがありますどちらが最適かは、依存関係グラフがどのように どう見えるでしょうか
ボトムアップの無効化中に、グラフが作成されて変更セットのセットが 入力がわかっていると、そのノードに推移的に依存するすべてのノードが 表示されます。同じトップレベル ノードをビルドする場合に最適です。 もう一度クリックします。なお、ボトムアップの無効化を行うには、すべての対象で
stat()
を実行する必要があります。 以前のビルドの入力ファイルを確認して、変更済みかどうかを判断します。このinotify
または同様のメカニズムを使用して、 表示されます。トップダウンの無効化中に、トップレベル ノードの推移的クロージャ チェックされ、推移的クロージャがクリーンなノードのみが保持されます。 ノードグラフが大きい場合はこの方法が適していますが、次のビルドで必要なのは 小さなサブセット: ボトムアップの無効化により、より大きなグラフが無効になる 最初のビルドでしか確認できませんが、トップダウンの無効化では 2 回目のビルドのグラフです
Bazel はボトムアップの無効化のみを行います。
Bazel では、さらにインクリメンタリティを高めるため、変更のプルーニングが使用されます。 無効化されたものの、再ビルド時に新しい値が以前と同じであることが 古い値として認識されますが、このノードの変更により無効化されたノードは、 「復活」します。
これは、たとえば、C++ ファイルのコメントを変更した場合、
そこから生成された .o
ファイルは同じものになるため、呼び出す必要はありません。
再実行します。
増分リンク / コンパイル
このモデルの主な制限は、ノードの無効化が 依存関係が変化しても、依存するノードは常に 仮に、より優れたアルゴリズムが存在していたとしても、ゼロから 変更に基づいてノードの古い値が更新されます。これが実際に利用されるケースは 有用である:
- 増分リンク
- JAR ファイルで 1 つのクラスファイルが変更された場合、 JAR ファイルを最初から再ビルドするのではなく、インプレースで変更します。
Bazel が原則的にこれらのことをサポートしない理由 次の 2 つがあります。
- パフォーマンスの向上は限定的でした。
- ミューテーションの結果が結果と同じかどうかを検証するのが困難 Google ではビット単位のビルドを重視しています。 再現可能であることです。
これまでは、古い ReplicaSet を分離することで、 部分的な再評価を行う必要がありましたたとえば Android アプリでは、すべてのクラスを複数のグループに分割し、dex 変換を行う 個別に選択できます。これにより、グループ内のクラスが変更されていない場合に、dex 変換によって やり直す必要はありません。
Bazel のコンセプトへのマッピング
これはキー SkyFunction
と SkyValue
の概要です
Bazel がビルドの実行に使用する実装です。
- FileStateValue を返します。
lstat()
の結果。既存のファイルについては、 この関数は、リソースの変更を検出するために、 表示されます。これは SkyFrame グラフの最下位のノードで、 確認します。 - FileValue。実際のコンテンツやシステムに関心を持つ
解決されます。対応する
FileStateValue
と 解決する必要があるシンボリック リンク(a/b
のFileValue
など)a
の解決済みパスとa/b
の解決済みパスが必要)。「 次の理由から、FileValue
とFileStateValue
の区別は重要です。 後者は、ファイルの内容が保存されていない場合に便利です。 必要があります。たとえば、ファイルの内容に関連性がない場合や、 ファイル システムの glob の評価(srcs=glob(["*/*.java"])
など)。 - DirectoryListingStateValue を渡しています。
readdir()
の結果。高評価FileStateValue
: 最下位レベルのノードで、依存関係はありません。 - DirectoryListingValue。ログエントリに関連する
作成します。対応する
DirectoryListingStateValue
によって異なります。 および関連するディレクトリのFileValue
。 - PackageValue。BUILD ファイルの解析済みバージョンを表します。影響される
関連する
BUILD
ファイルのFileValue
。また、任意の パッケージ内の glob を解決するために使用されるDirectoryListingValue
(BUILD
ファイルのコンテンツを内部的に表すデータ構造)。 - ConfiguredTargetValue。構成されたターゲットを表します。これはタプルです
標的の解析中に生成された一連の活動と、
依存する構成ターゲットに提供される情報です。影響する
PackageValue
: 対応するターゲットが存在する、ConfiguredTargetValues
ビルドを表す特別なノードを含む特別なノードが できます。 - ArtifactValue。ビルド内のファイルを表します。ソースまたは
出力アーティファクトです。アーティファクトはファイルにほぼ等しく、
ビルドステップの実際の実行時にファイルを参照します。ソースファイル
関連するノードの
FileValue
と出力アーティファクトに依存 生成されるアクションのActionExecutionValue
に依存し、 表示されます。 - ActionExecutionValue。アクションの実行を表します。影響される
入力ファイルの
ArtifactValues
。実行するアクションは これは SkyKey のみを使用するという概念に反します。 小さくなります。なお、ActionExecutionValue
とArtifactValue
は、 実行フェーズは実行されません。
この図は、視覚的な参考として、 Bazel 自体のビルド後の SkyFunction の実装: