動的実行

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

このページでは、動的実行を有効化、調整、デバッグする方法について説明します。ローカル実行とリモート実行の両方を設定していて、パフォーマンスを向上させるために 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 ニーモニックのデフォルトのみがオーバーライドされます。リモート バージョンも同様に動作します。どちらのフラグも複数回指定できます。アクションをローカルで実行できない場合は、通常どおりリモートで実行されます。その逆も同様です。

リモート システムにキャッシュがある場合、--local_execution_delay フラグは、リモート システムがキャッシュ ヒットを示した後、ローカル実行にミリ秒単位の遅延を追加します。これにより、キャッシュ ヒットが発生する可能性が高い場合にローカル実行が実行されるのを防ぎます。デフォルト値は 1000 ミリ秒ですが、通常キャッシュ ヒットにかかる時間より少し長く調整する必要があります。実際の時間は、リモート システムとラウンドトリップにかかる時間の両方によって異なります。通常、ラウンドトリップ レイテンシが発生するほど離れていない限り、特定のシステムのリモート ユーザー全バージョンに対し有効になります。Bazel プロファイリング機能を使用して、一般的なキャッシュヒットにかかる時間を確認できます。

動的実行は、ローカル サンドボックス化戦略と 永続ワーカーで使用できます。永続ワーカーは 動的実行で使用すると自動的にサンドボックス化されて実行され、 マルチプレックス ワーカーを使用できません。Darwin システムと Windows システムでは、サンドボックス化された戦略が遅くなる可能性があります。--reuse_sandbox_directories を渡すと、これらのシステムでサンドボックスを作成するオーバーヘッドを削減できます。

動的実行は standalone 戦略でも実行できますが、standalone 戦略では実行開始時に出力ロックを取得する必要があるため、リモート戦略が最初に完了するのを効果的にブロックします。--experimental_local_lockfree_output フラグを使用すると、ローカル実行が出力に直接書き込むことができるため、この問題を回避できますが、リモート実行が先に完了した場合は中止されます。

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

動的実行とそのロックの仕組みについて詳しくは、Julio Merino's excellent ブログ投稿をご覧ください

動的実行を使用するタイミング

動的実行には、何らかの リモート実行システムが必要です。キャッシュミスは失敗したアクションと見なされるため、キャッシュ専用のリモート システムは現在使用できません。

すべての種類のアクションがリモート実行に適しているわけではありません。最適な 候補は、永続ワーカーの使用などにより、ローカルで本質的に高速なアクション、またはリモート実行のオーバーヘッドが実行時間を支配するほど高速に実行されるアクションです。ローカルで実行されるアクションはそれぞれ、一定量の CPU リソースとメモリリソースをロックするため、これらのカテゴリに該当しないアクションを実行すると、該当するアクションの実行が遅延するだけです。

リリース 5.0.0-pre.20210708.4以降、 パフォーマンスプロファイリング には、動的実行の競合に負けた後に作業 リクエストを完了するのにかかった時間など、ワーカーの実行に関するデータが含まれています。動的実行ワーカー スレッドがリソースの取得にかなりの時間を費やしている場合や、async-worker-finish に多くの時間を費やしている場合は、ワーカー スレッドを遅延させるローカル アクションが遅い可能性があります。

動的実行パフォーマンスが低いデータのプロファイリング

上記のプロファイルでは、8 つの Javac ワーカーを使用しており、多くの Javac ワーカーが競合に負け、async-worker-finish スレッドで作業を完了しています。これは、ワーカー以外のニーモニックがワーカーを遅延させるのに十分なリソースを消費したことが原因です。

動的実行パフォーマンスが向上したプロファイリング データ

Javac のみが動的実行で実行される場合、作業を開始したワーカーの約半数が作業開始後に競合に負けます。

以前推奨されていた --experimental_spawn_scheduler フラグは非推奨になりました。 このフラグは動的実行を有効にし、すべてのニーモニックのデフォルト戦略として dynamic を設定するため、このような問題が発生することがよくありました。

トラブルシューティング

動的実行の問題は、ローカル実行とリモート実行の特定の組み合わせでのみ発生する可能性があるため、デバッグが難しい場合があります。--debug_spawn_scheduler を使用すると、動的実行システムから追加の出力が生成され、これらの問題のデバッグに役立ちます。--local_execution_delay フラグとリモート ジョブとローカル ジョブの数を調整して、問題を再現しやすくすることもできます。

standalone 戦略を使用して動的実行で問題が発生している場合は、--experimental_local_lockfree_output なしで実行するか、ローカル アクションをサンドボックス化して実行してみてください。これによりビルドが少し遅くなる可能性がありますが(Mac または Windows を使用している場合は上記をご覧ください)、障害の原因となる可能性がいくつか解消されます。