動的実行 は、Bazel の機能です。同じアクションのローカル実行とリモート実行を並行して開始し、最初に完了したブランチの出力を使用して、他のブランチをキャンセルします。リモートビルド システムの実行能力 や大規模な共有キャッシュと、ローカル 実行の低レイテンシを組み合わせることで、クリーンビルドと増分ビルド の両方で最高のパフォーマンスを実現します。
このページでは、動的実行を有効化、チューニング、デバッグする方法について説明します。ローカル実行とリモート実行の両方を設定していて、パフォーマンスを向上させるために Bazel の設定を調整しようとしている場合は、このページをご覧ください。リモート実行を設定していない場合は、まず Bazel リモート実行 の概要をご覧ください。
動的実行を有効にする
動的実行モジュールは Bazel の一部ですが、動的 実行を利用するには、同じ Bazel 設定からローカルとリモートの両方でコンパイルできる必要があります。
動的実行モジュールを有効にするには、--internal_spawn_scheduler
フラグを Bazel に渡します。これにより、dynamic という新しい実行戦略が追加されます。たとえば、
`--strategy=Javac=dynamic` のように、動的に実行するニーモニックの戦略として使用できます。--strategy=Javac=dynamic動的実行を有効にするニーモニックを選択する方法については、次のセクションをご覧ください。
動的戦略を使用するニーモニックの場合、リモート実行戦略は
--dynamic_remote_strategyフラグから取得され、ローカル戦略は
--dynamic_local_strategyフラグから取得されます。
--dynamic_local_strategy=worker,sandboxed を渡すと、動的実行のローカル
ブランチのデフォルトが、ワーカーまたはサンドボックス化された実行で試行されるその
順序で設定されます。--dynamic_local_strategy=Javac=worker を渡すと、
Javac ニーモニックのデフォルトのみがオーバーライドされます。リモート バージョンも同様に機能します。どちらのフラグも
複数回指定できます。アクションをローカルで実行できない場合は、
通常どおりリモートで実行されます。逆も同様です。
リモート システムにキャッシュがある場合、--dynamic_local_execution_delay フラグ
は、リモート システムが
キャッシュ ヒットを示した後、ローカル実行にミリ秒単位の遅延を追加します。これにより、キャッシュ ヒットが発生する可能性が高い場合にローカル実行が実行されるのを防ぎます。デフォルト値は 1, 000 ミリ秒ですが、通常キャッシュ ヒットにかかる時間より少し
長くするように調整する必要があります。実際の時間は、リモート
システムとラウンドトリップにかかる時間の両方によって異なります。通常、ラウンドトリップ レイテンシが発生するほど離れていない限り、特定のリモート システムのすべてのユーザーで値は同じになります。Bazel のプロファイリング機能を使用して、一般的なキャッシュ ヒットにかかる時間を確認できます。
動的実行は、ローカルのサンドボックス化された戦略と
永続的なワーカーで使用できます。永続的なワーカーは、動的実行で使用すると自動的に
サンドボックス化で実行され、マルチプレックス
ワーカーを使用できません。Darwin システムと Windows システムでは、サンドボックス化された
戦略が遅くなる可能性があります。--reuse_sandbox_directories を渡すと、これらのシステムでサンドボックスを作成する
オーバーヘッドを削減できます。
動的実行は standalone 戦略でも実行できますが、
standalone 戦略は実行開始時に出力ロックを取得する必要があるため、it
リモート戦略が最初に完了するのを効果的にブロックします。
--experimental_local_lockfree_output フラグを使用すると、ローカル実行が出力に直接書き込むことができますが、リモート実行が先に完了した場合は中止されます。
動的実行のブランチのいずれかが最初に完了しても失敗した場合、 アクション全体が失敗します。これは、ローカル実行とリモート実行の違いが検出されないようにするための意図的な選択です。
動的実行とそのロックの仕組みについて詳しくは、Julio Merino の優れた ブログ 投稿をご覧ください。
動的実行を使用するタイミング
動的実行には、何らかのリモート実行システムが必要です。 キャッシュミス は失敗したアクションと見なされるため、キャッシュ専用のリモート システムは現在使用できません。
すべての種類のアクションがリモート実行に適しているわけではありません。最適な 候補は、永続的なワーカーの使用などにより、ローカルで本質的に高速なアクションや、リモート実行のオーバーヘッドが実行時間を支配するほど高速に実行されるアクションです。ローカルで実行されるアクションは、CPU リソースとメモリリソースの一部をロックするため、 これらのカテゴリに該当しないアクションを実行すると、該当するアクションの実行が遅延します。
リリース
5.0.0-pre.20210708.4以降、
パフォーマンス プロファイリングには、動的実行の競合に負けた後に作業リクエストを完了するのにかかった時間など、
ワーカーの実行に関するデータが含まれています。動的実行ワーカー スレッド
がリソースの取得にかなりの時間を費やしている場合や、
async-worker-finishに多くの時間を費やしている場合は、ワーカー
スレッドを遅延させるローカル アクションが遅い可能性があります。
上記のプロファイルでは、8 つの Javac ワーカーを使用しています。多くの Javac ワーカーが競合に負け、async-worker-finish
スレッドで作業を完了しています。これは、ワーカー以外のニーモニックがワーカーを遅延させるのに十分なリソースを消費したことが原因です。
Javac のみが動的実行で実行される場合、作業を開始した ワーカーの約半数が作業開始後に競合に負けます。
以前推奨されていた --experimental_spawn_scheduler フラグは非推奨になりました。
このフラグは動的実行を有効にし、dynamicをすべての
ニーモニックのデフォルト戦略として設定するため、このような問題が発生することがよくありました。
パフォーマンス
動的実行アプローチでは、全体的なパフォーマンスを向上させるために追加のリソースを費やす価値があるほど、ローカルとリモートで十分なリソースが利用可能であることを前提としています。ただし、リソースの使用量が多すぎると、Bazel 自体や 実行されるマシンが遅くなったり、リモート システムに予期しない負荷がかかったりする可能性があります。動的実行の動作を変更するには、 次のオプションがあります。
--dynamic_local_execution_delay は、リモート ブランチが開始してからミリ秒単位でローカル ブランチの開始を遅らせます。ただし、現在のビルド中にリモート キャッシュ ヒットが発生した場合に限ります。これにより、リモート キャッシュのメリットを活かしたビルドでは、ほとんどの出力がキャッシュで見つかる可能性が高い場合に、ローカル リソースを無駄にすることがなくなります。キャッシュの品質によっては、
この値を小さくすると、ローカル
リソースの使用量が増える代わりにビルド速度が向上する可能性があります。
--experimental_dynamic_local_load_factor は、試験運用版の高度なリソース
管理オプションです。0 ~ 1 の値を取ります。0 にすると、この機能が無効になります。
0 より大きい値に設定すると、スケジュール設定を待機しているアクションが多い場合に、Bazel はローカルでスケジュール設定されたアクションの数を調整します。1 に設定すると、使用可能な CPU の数(--local_cpu_resources に準拠)と同じ数のアクションをスケジュール設定できます。値が小さいほど、実行できるアクションの数が少なくなるため、スケジュール設定されるアクションの数が少なくなります。直感に反するかもしれませんが、優れたリモート
システムを使用すると、多くのアクションが実行されている場合、ローカル実行はあまり役に立ちません。
ローカル CPU はリモート アクションの管理に費やす方が適切です。
--experimental_dynamic_slow_remote_time は、リモート ブランチが少なくともこの時間実行されている場合に、ローカル ブランチの開始を優先します
。通常、最後にスケジュール設定されたアクションが優先されます。これは、競合に勝つ可能性が最も高いためです。ただし、リモート システムがハングしたり、時間がかかりすぎたりする場合は、ビルドを進めることができます。これはデフォルトでは有効になっていません。
修正する必要があるリモート システムの問題が隠される可能性があるためです。このオプションを有効にする場合は、
リモート システムのパフォーマンスをモニタリングしてください。
--experimental_dynamic_ignore_local_signals を使用すると、特定のシグナルが原因でローカル スポーンが終了した場合に、リモート
ブランチが引き継ぐことができます。これは
主に、ワーカー リソースの上限(
--experimental_worker_memory_limit_mb、
--experimental_worker_sandbox_hardening、
および
--experimental_sandbox_memory_limit_mb)とともに使用すると便利です。
ワーカー プロセスがリソースを使いすぎると強制終了されることがあります。
JSON トレース プロファイルには、パフォーマンスとリソース使用量のトレードオフを改善する方法を特定するのに役立つ、パフォーマンス関連のグラフが 多数含まれています。
トラブルシューティング
動的実行の問題は、ローカル実行とリモート実行の特定の組み合わせでのみ発生する可能性があるため、微妙でデバッグが難しい場合があります。--debug_spawn_scheduler を使用すると、動的実行
システムから追加の出力が生成され、これらの問題のデバッグに役立ちます。
--dynamic_local_execution_delay フラグとリモート ジョブとローカル ジョブの数を調整して、
問題を再現しやすくすることもできます。
standalone
戦略を使用して動的実行で問題が発生している場合は、--experimental_local_lockfree_output を指定せずに実行するか、ローカル アクションをサンドボックス化して実行してみてください。これにより、ビルドが少し遅くなる可能性がありますが(Mac または Windows を使用している場合は上記をご覧ください
)、障害の原因となる可能性がいくつか解消されます。