このページでは、永続ワーカーの使用方法、メリット、要件、 サンドボックス化にワーカーが及ぼす影響を確認できます
永続ワーカーは、Bazel サーバーが開始する長時間実行プロセスです。実際のツール(通常はコンパイラ)のラッパーとして機能するか、ツール自体です。永続ワーカーのメリットを享受するには、ツールが連続したコンパイルをサポートしている必要があります。また、ラッパーは、ツールの API と後述のリクエスト / レスポンス形式を変換する必要があります。同じ
ワーカーは、--persistent_worker
フラグの有無にかかわらず、
適切に起動して通信する責任を負います。
終了時にワーカーをシャットダウンできます各ワーカー インスタンスには
別の作業ディレクトリに(ただし chroot はされません)
<outputBase>/bazel-workers
。
永続ワーカーを使用することは、起動のオーバーヘッドを減らし、より多くの JIT コンパイルを可能にし、アクション実行の抽象構文木などのキャッシュを有効にする実行戦略です。この戦略では、長時間実行プロセスに複数のリクエストを送信することで、これらの改善を実現します。
NodeJS ランタイムを使用するプログラムは、@bazel/worker ヘルパー ライブラリを使用してワーカー プロトコルを実装できます。
永続ワーカーの使用
Bazel 0.27 以降
ビルド実行時にデフォルトで永続ワーカーを使用するが、リモート
実行が優先されます。永続ワーカーをサポートしていないアクションの場合、Bazel はアクションごとにツール インスタンスを開始します。明示的に
worker
を設定して、ビルドが永続ワーカーを使用するように設定します。
該当するツールの戦略
できます。ベスト プラクティスとして、この例では、local
を
worker
戦略にフォールバックします。
bazel build //my:target --strategy=Javac=worker,local
ローカル戦略ではなくワーカー戦略を使用すると、コンパイルを促進できる 大幅に向上する可能性があります。Java の場合、ビルドは 2~4 倍高速化されます。増分コンパイルではさらに高速化されることもあります。Bazel のコンパイルは、ワーカーを使用すると約 2.5 倍速くなります。詳細については、ワーカー数の選択をご覧ください。
ローカルビルドと一致するリモートビルド環境もある場合
試験運用版の Terraform を使用して、
動的な戦略
リモート実行とワーカー実行で競合します動的戦略を有効にするには、--experimental_spawn_scheduler フラグを渡します。この戦略では、ワーカーが自動的に有効化されるため、何もする必要がない
worker
戦略を指定しますが、local
または sandboxed
を
使用します。
ワーカー数の選択
メモニカあたりのデフォルトのワーカー インスタンス数は 4 ですが、worker_max_instances
フラグで調整できます。使用可能な CPU の有効活用と、
JIT コンパイルとキャッシュヒットの
合計時間を表しますワーカーが増えると、
JIT されていないコードの実行やコールド ヒットが発生するため、
キャッシュです。ビルドするターゲットが少ない場合、1 つのワーカーでコンパイル速度とリソース使用量の最適なトレードオフが得られる場合があります(問題 #8586 などをご覧ください)。worker_max_instances
フラグは、インスタンスあたりのワーカー インスタンスの最大数を設定します。
ニモニックとフラグセットの両方を使用するため(下記参照)、これらが混在するシステムでは、
多くのメモリを消費します増分ビルドの場合、複数のワーカー インスタンスのメリットはさらに小さくなります。
このグラフは、64 GB の RAM を搭載した 6 コア ハイパースレッドの Intel Xeon 3.5 GHz Linux ワークステーションでの Bazel(ターゲット //src:bazel
)のゼロからのコンパイル時間を示しています。ワーカー構成ごとに 5 件のクリーンビルドが実行され、最後の 4 件の平均が使用されます。
図 1. クリーンビルドのパフォーマンス向上のグラフ。
この構成では、2 つのワーカーが最も高速なコンパイルを実現しますが、1 つのワーカーと比較してわずか 14% の改善にしかなりません。必要な場合は 1 つのワーカーが メモリの使用量が減ります
一般的に、増分コンパイルの方が大きなメリットがあります。クリーンビルドは比較的まれですが、コンパイル間で単一のファイルを変更することは、特にテスト駆動開発で一般的です。上の例では、Java 以外の言語も 追加のコンパイル時間に影響が及ぶおそれがあるからです。
Java ソースのみを再コンパイルする
(//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar
)
terraform plan または terraform apply で
AbstractContainerizingSandboxedSpawn.java
3 倍の高速化(1 回のウォームアップ ビルドで平均 20 個の増分ビルド)
破棄される):
図 2. 増分ビルドのパフォーマンス向上のグラフ。
速度の向上は、変更内容によって異なります。上記の状況で、よく使用される定数が変更されると、6 倍の高速化が測定されます。
永続ワーカーの変更
渡すには、
--worker_extra_flag
ワーカーに起動フラグを指定するフラグ。キーがニモニックです。たとえば、--worker_extra_flag=javac=--debug
を渡すと、Javac のデバッグのみが有効になります。このフラグの使用ごとに設定できるワーカーフラグは 1 つだけです。また、1 つのメモニクスにのみ設定できます。ワーカーは、各メモニカだけでなく、起動フラグの違いごとに個別に作成されます。ニモニックとスタートアップの各組み合わせは
フラグは WorkerKey
に結合され、WorkerKey
ごとに最大
worker_max_instances
ワーカーが作成される可能性があります。アクションの構成で設定フラグを指定する方法については、次のセクションをご覧ください。
--high_priority_workers
フラグを使用して、通常の優先度のメモニカよりも優先して実行するメモニカを指定できます。これにより、常に危機的状況にあるアクションに優先順位を付けることができる
あります。優先度の高いワーカーが 2 つ以上ある場合、すべてのワーカーが
他のワーカーの実行は阻止されますこのフラグは複数回使用できます。
--worker_sandboxing
フラグを渡すと、各ワーカー リクエストはすべての入力に個別のサンドボックス ディレクトリを使用します。サンドボックスの設定には、特に macOS で時間がかかりますが、正確性が保証されます。
「
--worker_quit_after_build
フラグは主にデバッグとプロファイリングに役立ちます。このフラグを使用すると、ビルドが完了するとすべてのワーカーが強制的に終了します。--worker_verbose
を渡して、ワーカーの処理内容に関する詳細な出力を取得することもできます。このフラグは WorkRequest
の verbosity
フィールドに反映され、ワーカーの実装も詳細にできます。
ワーカーはログを <outputBase>/bazel-workers
ディレクトリ(/tmp/_bazel_larsrc/191013354bebe14fdddae77f2679c3ef/bazel-workers/worker-1-Javac.log
など)に保存します。ファイル名には、ワーカー ID とメモニクスが含まれています。画像アセットは
WorkerKey
が複数ある場合、worker_max_instances
または
1 つのニモニックに対して
ログファイルを 1 つ作成します
Android ビルドについて詳しくは、 Android のビルド パフォーマンスに関するページ
永続ワーカーの実装
詳細については、永続ワーカーの作成のページをご覧ください。 ワーカーの作成方法に関する情報です
次の例は、JSON を使用するワーカーの Starlark 構成を示しています。
args_file = ctx.actions.declare_file(ctx.label.name + "_args_file")
ctx.actions.write(
output = args_file,
content = "\n".join(["-g", "-source", "1.5"] + ctx.files.srcs),
)
ctx.actions.run(
mnemonic = "SomeCompiler",
executable = "bin/some_compiler_wrapper",
inputs = inputs,
outputs = outputs,
arguments = [ "-max_mem=4G", "@%s" % args_file.path],
execution_requirements = {
"supports-workers" : "1", "requires-worker-protocol" : "json" }
)
この定義では、このアクションの最初の使用は、コマンドライン /bin/some_compiler -max_mem=4G --persistent_worker
の実行から始まります。Foo.java
をコンパイルするリクエストは次のようになります。
注: プロトコル バッファ仕様では「スネークケース」(request_id
)が使用されますが、JSON プロトコルでは「キャメルケース」(requestId
)が使用されます。このドキュメントでは、JSON の例ではキャメルケースを使用しますが、プロトコルに関係なくフィールドについて説明する場合はスネークケースを使用します。
{
"arguments": [ "-g", "-source", "1.5", "Foo.java" ]
"inputs": [
{ "path": "symlinkfarm/input1", "digest": "d49a..." },
{ "path": "symlinkfarm/input2", "digest": "093d..." },
],
}
ワーカーは、stdin
で改行区切りの JSON 形式でこれを受け取ります(requires-worker-protocol
が JSON に設定されているため)。ワーカーはアクションを実行し、JSON 形式の WorkResponse
を stdout で Bazel に送信します。次に Bazel
このレスポンスを解析し、手動で WorkResponse
proto に変換します。宛先
関連するワーカーと通信するには、代わりにバイナリエンコードされた protobuf を使用します。
JSON の場合、requires-worker-protocol
は次のように proto
に設定されます。
execution_requirements = {
"supports-workers" : "1" ,
"requires-worker-protocol" : "proto"
}
実行要件に requires-worker-protocol
を含めない場合は、次のようになります。
Bazel では、デフォルトで protobuf を使用するようにワーカー通信を行います。
Bazel は、メモニカと共有フラグから WorkerKey
を導出します。この構成で max_mem
パラメータを変更できる場合、使用される値ごとに個別のワーカーが生成されます。そのため、次の場合にメモリが過剰に消費されることがあります。
あまりに多くのバリエーションを
使用することはありません
現在のところ、各ワーカーは一度に 1 つのリクエストしか処理できません。試験運用版 Multiplex Worker 機能によって、複数の 基盤となるツールがマルチスレッドであり、ラッパーが 理解してください。
イン こちらの GitHub リポジトリ Java と Python で記述されたワーカー ラッパーの例を確認できます。もし 動作している場合、 @bazel/worker パッケージ および Nodejs ワーカーの例 役立つかもしれません。
ワーカーはサンドボックスにどのように影響しますか?
デフォルトでは worker
戦略を使用すると、アクションは実行されません。
サンドボックス。local
戦略と同様です。--worker_sandboxing
フラグを設定して、すべてのワーカーをサンドボックス内で実行し、ツールの各実行で、本来存在するはずの入力ファイルのみを参照するようにすることができます。ツール
引き続き内部的にリクエスト間で情報が漏洩することがあります。たとえば、
作成します。dynamic
戦略を使用
ワーカーをサンドボックス化する必要がある。
ワーカーでコンパイラ キャッシュを正しく使用できるように、ダイジェストが 必要があります。したがって、コンパイラまたはラッパーは、ファイルを読み取ることなく入力がまだ有効かどうかを確認できます。
不要なキャッシュを防ぐために入力ダイジェストを使用する場合でも、 サンドボックスは純粋なサンドボックスよりも厳格ではありません。ツールがサンドボックス化されてしまうため、 以前のリクエストの影響を受けた他の内部状態を保持する。
マルチプレックス ワーカーをサンドボックス化できるのは、ワーカーの実装がサンドボックス化をサポートしている場合のみです。このサンドボックス化は、--experimental_worker_multiplex_sandboxing
フラグで個別に有効にする必要があります。詳しくは、設計ドキュメントをご覧ください)。
関連情報
永続ワーカーの詳細については、以下をご覧ください。