Bazel は複雑で、ビルドの過程でさまざまな処理を行います。 その一部はビルドのパフォーマンスに影響する可能性があります。このページでは、Bazel のコンセプトとビルドのパフォーマンスへの影響を関連付けます。網羅的ではありませんが、指標を抽出してビルドのパフォーマンス の問題を検出する方法と、問題を解決する方法の例をいくつか紹介します。ビルドのパフォーマンスの低下を調査する際に、これらのコンセプトを適用していただければ幸いです。
クリーンビルドと増分ビルド
クリーンビルドはすべてをゼロからビルドするビルドですが、増分 ビルドはすでに完了している作業の一部を再利用します。
クリーンビルドと増分ビルドは別々に確認することをおすすめします。特に、 Bazel のキャッシュの状態に依存する指標(たとえば ビルド リクエスト サイズの指標 など)を収集または集計する場合は、別々に確認してください。また、クリーンビルドと増分ビルドは、ユーザー エクスペリエンスも異なります。クリーンビルドをゼロから開始する場合(コールドキャッシュのため時間がかかる)と比較して、増分 ビルドは、デベロッパーがコードを反復処理する際に頻繁に発生します(通常、キャッシュはすでにウォームであるため高速です)。
BEP の CumulativeMetrics.num_analyses フィールドを使用して、ビルドを分類できます。num_analyses <= 1 の場合はクリーンビルドです。それ以外の場合は、増分ビルドである可能性が高いと大まかに
分類できます。ユーザーが別のフラグまたは別のターゲットに切り替えたため、事実上クリーンビルドになる可能性があります。増分性のより厳密な定義は、ヒューリスティックの形式になる可能性があります。たとえば、読み込まれたパッケージの数(PackageMetrics.packages_loaded)を確認します。
ビルドのパフォーマンスのプロキシとしての決定論的ビルド指標
特定の指標(Bazel の CPU 時間やリモート クラスタのキュー時間など)の非決定論的な性質 により、ビルドのパフォーマンスの測定は困難になる可能性があります。そのため、決定論的な指標を Bazel が行った作業量のプロキシとして使用すると便利です。これは、Bazel のパフォーマンスに影響します。
ビルド リクエストのサイズは、ビルドのパフォーマンスに大きな影響を与える可能性があります。ビルドが大きいほど、ビルドグラフの分析と 構築に多くの作業が必要になる可能性があります。依存関係が追加または作成されるにつれて、ビルドは自然に 増加します。そのため、複雑さが増し 、ビルドのコストが高くなります。
この問題はさまざまなビルドフェーズに分割できます。次の 指標を、各フェーズで行われた作業のプロキシ指標として使用します。
PackageMetrics.packages_loaded: 正常に読み込まれたパッケージの数。 この値が低下すると、読み込みフェーズで追加の BUILD ファイルを読み取って解析するために必要な作業が増えます 。TargetMetrics.targets_configured: ビルドで構成されたターゲットと アスペクトの数を表します。この値が低下すると、構成されたターゲット グラフの構築とトラバースに 多くの作業が必要になります。- 多くの場合、これは依存関係の追加と、その推移的閉包のグラフを構築する必要があることが原因です。
- cquery を使用して、新しい 依存関係が追加された場所を確認します。
ActionSummary.actions_created: ビルドで作成されたアクションを表します。 この値が低下すると、アクション グラフの構築に多くの作業が必要になります。これには、実行されていない可能性のある未使用のアクションも含まれます。- 低下のデバッグには aquery を使用します。
--skyframe_stateでさらにドリルダウンする前に、--output=summaryから始めることをおすすめします。
- 低下のデバッグには aquery を使用します。
ActionSummary.actions_executed: 実行されたアクションの数。 この値が低下すると、これらのアクションの実行に多くの作業が必要になります。- BEP は、最も実行されたアクション タイプを示すアクション統計
ActionDataを書き出します。デフォルトでは、上位 20 個のアクション タイプが収集されますが、--experimental_record_metrics_for_all_mnemonicsを渡して、実行されたすべてのアクション タイプについてこのデータを収集できます。 - これにより、実行されたアクションの種類を把握できます 。
- BEP は、最も実行されたアクション タイプを示すアクション統計
BuildGraphSummary.outputArtifactCount: 実行されたアクションによって作成されたアーティファクトの数。- 実行されたアクションの数が増加していない場合は、 ルール実装が変更された可能性があります。
これらの指標はすべてローカル キャッシュの状態の影響を受けるため、これらの指標を抽出するビルドが クリーンビルドであることを確認する必要があります。
これらの指標のいずれかが低下すると、 実時間、CPU 時間、メモリ使用量も低下する可能性があります。
ローカル リソースの使用
Bazel は、ローカルマシンでさまざまなリソースを消費します(ビルドグラフの分析 と実行の推進、ローカルアクションの実行の両方)。これにより、ビルドの実行時や他のタスクの実行時に、マシンのパフォーマンスや可用性に影響する 可能性があります。
かかった時間
ノイズの影響を受けやすく、ビルド
ごとに大きく異なる可能性のある指標は、時間です。特に、実時間、CPU 時間、システム時間です。bazel-bench
を使用してこれらの指標のベンチマークを取得できます。--runs の数を十分に増やすと、測定の統計的有意性を高めることができます。
実時間 は、経過した実際の時間です。
- 実時間のみが低下する場合は、 JSON トレース プロファイルを収集して 違いを確認することをおすすめします。それ以外の場合は、他の低下した指標を 調査する方が効率的です。実時間に影響している可能性があります。
CPU 時間 は、CPU がユーザーコードの実行に費やした時間です。
- 2 つのプロジェクト コミット間で CPU 時間が低下する場合は、
Starlark CPU プロファイルを収集することをおすすめします。また、CPU の負荷が高い作業のほとんどが分析フェーズで行われるため、
--nobuildを 使用してビルドを分析フェーズに制限することをおすすめします。
- 2 つのプロジェクト コミット間で CPU 時間が低下する場合は、
Starlark CPU プロファイルを収集することをおすすめします。また、CPU の負荷が高い作業のほとんどが分析フェーズで行われるため、
システム時間は、CPU がカーネルで費やした時間です。
- システム時間が低下した場合、Bazel が ファイル システムからファイルを読み取るときに I/O と相関することがほとんどです。
システム全体の負荷プロファイリング
Bazel 6.0 で導入された
--experimental_collect_load_average_in_profiler
フラグを使用すると、
JSON トレース プロファイラは呼び出し中に
システム負荷の平均を収集します。

図 1.システム負荷の平均を含むプロファイル。
Bazel の呼び出し中に負荷が高い場合は、Bazel がマシンに対してローカル アクションを並行してスケジュールしすぎている可能性があります。の調整を検討してください。特にコンテナ環境では(
#16512 がマージされるまで)。--local_cpu_resources--local_ram_resources
Bazel のメモリ使用量のモニタリング
Bazel のメモリ使用量を取得するには、Bazel info と
BEP の 2 つの主なソースがあります。
bazel info used-heap-size-after-gc: の呼び出し後の使用済みメモリ量(バイト単位)。System.gc()- Bazel ベンチマーク では、この指標のベンチマークも提供されます。
- また、
peak-heap-size、max-heap-size、used-heap-size、committed-heap-sizeもありますが( ドキュメントを参照)、 関連性は低くなります。
BEP の
MemoryMetrics.peak_post_gc_heap_size:GC 後の JVM ヒープサイズのピークのサイズ( バイト単位)(完全な GC を強制しようとする--memory_profileの設定が必要)。
メモリ使用量の低下は通常、 ビルド リクエスト サイズの指標の低下が原因です。 これは多くの場合、依存関係の追加またはルール 実装の変更が原因です。
Bazel のメモリ使用量をより詳細に分析するには、 ルール用の組み込みメモリ プロファイラ を使用することをおすすめします。
永続ワーカーのメモリ プロファイリング
永続ワーカーはビルドを
大幅に高速化できますが(特にインタープリタ言語の場合)、メモリ使用量が
問題になる可能性があります。Bazel はワーカーに関する指標を収集します。特に、
WorkerMetrics.WorkerStats.worker_memory_in_kb フィールドは、ワーカーが使用するメモリ量(ニーモニック別)を示します。
JSON トレース プロファイラは、
フラグ(Bazel 6.0 で新しく追加)を渡すことで、呼び出し中に永続ワーカーのメモリ使用量も
収集します。--experimental_collect_system_network_usage

図 2.ワーカーのメモリ使用量を含むプロファイル。
--worker_max_instances
の値(デフォルトは 4)を小さくすると、永続ワーカーが使用するメモリ量を減らすことができます。Google は、Bazel のリソース マネージャーとスケジューラをよりスマートにするために積極的に取り組んでいます。これにより、今後このような微調整が必要になる頻度が減ります。
リモートビルドのネットワーク トラフィックのモニタリング
リモート実行では、Bazel はアクションの実行結果としてビルドされたアーティファクトをダウンロードします。そのため、ネットワーク帯域幅はビルドのパフォーマンスに影響する可能性があります 。
ビルドにリモート実行を使用している場合は、
呼び出し中のネットワーク トラフィックを
NetworkMetrics.SystemNetworkStats proto を使用してモニタリングすることを検討してください(BEP
--experimental_collect_system_network_usage を渡す必要があります)。
さらに、JSON トレース プロファイル
を使用すると、ビルド全体でシステム全体のネットワーク使用量を確認できます
。これには、--experimental_collect_system_network_usage フラグ(Bazel
6.0 で新しく追加)を渡します。

図 3.システム全体のネットワーク使用量を含むプロファイル。
リモート実行を使用しているときにネットワーク使用量が高く、フラットな場合は、ネットワークがビルドのボトルネックになっている可能性があります。まだ使用していない場合は、--remote_download_minimal を渡して、バイトなしでビルドを有効にすることを検討してください。これにより、不要な中間アーティファクトのダウンロードを回避することで、ビルドを高速化できます。
別の方法として、ローカル ディスク キャッシュを構成して ダウンロード帯域幅を節約することもできます。