動的実行

問題を報告 ソースを表示 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

動的実行は、Bazel の機能です。同じアクションのローカル実行とリモート実行が並行して開始され、最初に完了したブランチの出力が使用され、他のブランチがキャンセルされます。リモートビルド システムの実行能力や大規模な共有キャッシュと、ローカル実行の低レイテンシを組み合わせることで、クリーンビルドと増分ビルドの両方で最高のパフォーマンスを実現します。

このページでは、動的実行を有効化、チューニング、デバッグする方法について説明します。ローカル実行とリモート実行の両方が設定されていて、パフォーマンスを向上させるために Bazel の設定を調整しようとしている場合は、このページをご覧ください。リモート実行がまだ設定されていない場合は、まず Bazel のリモート実行の概要をご覧ください。

動的実行を有効にする

動的実行モジュールは Bazel の一部ですが、動的実行を利用するには、同じ Bazel 設定からローカルとリモートの両方でコンパイルできる必要があります。

動的実行モジュールを有効にするには、--internal_spawn_scheduler フラグを Bazel に渡します。これにより、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 戦略は実行開始時に出力ロックを取得する必要があるため、リモート戦略が先に完了するのを効果的にブロックします。--experimental_local_lockfree_output フラグを使用すると、ローカル実行で出力を直接書き込むことができ、リモート実行が先に完了した場合はローカル実行が中止されるため、この問題を回避できます。

動的実行のブランチの 1 つが最初に終了しても失敗した場合、アクション全体が失敗します。これは、ローカル実行とリモート実行の違いが見過ごされないようにするための意図的な選択です。

動的実行とそのロックの仕組みについて詳しくは、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 を使用している場合は上記を参照)。ただし、失敗の原因となる可能性のあるものがいくつか取り除かれます。