動的実行

問題を報告 ソースを表示

「動的実行」は、同じアクションのローカル実行とリモート実行を並行して開始する 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 より大きい値に設定すると、多くのアクションのスケジュール設定を待機している状況で、Bazel はローカルでスケジュール設定されたアクションの数を調整します。1 に設定すると、(--local_cpu_resources に従って)使用可能な CPU の数と同じ数のアクションをスケジュールできます。値が小さいほど、実行可能なアクション数が多くなるほど、スケジュールされるアクションの数が少なくなります。これは直感に反するように聞こえるかもしれませんが、優れたリモート システムでは、多くのアクションが実行されている場合、ローカル実行はあまり役に立ちません。また、ローカル 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 の場合は上記の説明をご覧ください)。ただし、失敗の原因を取り除くことができます。