リモート実行のためのリモート キャッシュ ヒットのデバッグ

このページでは、キャッシュ ヒット率を確認する方法と、リモート実行のコンテキストで キャッシュ ミスを調査する方法について説明します。

このページでは、リモート実行を正常に 利用するビルドまたはテストがあり、リモート キャッシュを効果的に 利用していることを確認することを前提としています。

キャッシュ ヒット率を確認する

Bazel の実行の標準出力で、INFO 行を確認します。これは、Bazel アクションにほぼ対応しています。この行には、アクションが実行された場所が詳しく記載されています。 remote ラベルを探します。これは、リモートで実行されたアクションを示す 、ローカル サンドボックスで実行されたアクションを示す linux-sandbox、その他の実行戦略を示すその他の値です。結果がリモート キャッシュから取得されたアクションは、 remote cache hit と表示されます。

次に例を示します。

INFO: 11 processes: 6 remote cache hit, 3 internal, 2 remote.

この例では、リモート キャッシュ ヒットが 6 回あり、2 つのアクションは キャッシュ ヒットがなく、リモートで実行されました。3 つの内部パーツは無視できます。 通常、シンボリック リンクの作成などの小さな内部アクションです。この概要には、ローカル キャッシュ ヒットは含まれません。プロセスが 0 個 (または想定よりも少ない数)の場合は、bazel clean の後にビルド/テスト コマンドを実行します。

キャッシュ ヒットのトラブルシューティング

想定どおりのキャッシュ ヒット率が得られない場合は、次の操作を行います。

同じビルド/テストコマンドを再実行するとキャッシュ ヒットが発生することを確認する

  1. キャッシュにデータを入力するビルドまたはテストを実行します。特定のスタックで新しいビルドを 初めて実行する場合は、リモート キャッシュ ヒットは発生しません。リモート実行の一環として、アクションの結果は キャッシュに保存され、後続の実行で取得されます。

  2. bazel clean を実行します。このコマンドを実行すると、ローカル キャッシュが消去されます。これにより、 ローカル キャッシュ ヒットによって結果がマスクされることなく、 リモート キャッシュ ヒットを調査できます。

  3. 調査しているビルドとテストを(同じ マシンで)再度実行します。

  4. INFO 行でキャッシュ ヒット率を確認します。 remote cache hitinternal 以外のプロセスが表示されない場合は、キャッシュが正しく入力され、 アクセスされています。その場合は、次のセクションに進みます。

  5. 不一致の原因として考えられるのは、ビルド内の非ハーメチックな要素により 2 回の実行でアクションが異なるアクションキーを受け取ることです。これらのアクションを見つけるには、 次の操作を行います。

    a. 問題のビルドまたはテストを再実行して、実行ログを取得します。

      bazel clean
      bazel --optional-flags build //your:target --execution_log_compact_file=/tmp/exec1.log

    b. 2 回の実行の実行ログを比較します。2 つのログファイルでアクションが同一であることを確認します。 不一致は、 実行間で発生した変更の手がかりとなります。ビルドを更新して、これらの不一致を解消します。

    キャッシュの問題を解決でき、繰り返し実行すると すべてのキャッシュ ヒットが発生する場合は、次のセクションに進みます。

    アクション ID が同じでもキャッシュ ヒットがない場合は、構成内の何かが キャッシュを妨げています。このセクションに進んで、 一般的な問題を確認してください。

  6. 実行ログ内のすべてのアクションで cacheable が true に設定されていることを確認します。特定のアクションの実行ログに cacheableが表示されない場合は、対応するルールにno-cacheタグが 定義でBUILDファイルに含まれている可能性があります。実行ログの mnemonic フィールドと target_label フィールドを確認して、アクションの発生元を特定します。

  7. アクションが同一で cacheable でもキャッシュ ヒットがない場合は、コマンドラインに --noremote_accept_cached が含まれている可能性があります。この場合、ビルドのキャッシュ検索が無効になります。

    実際のコマンドラインを特定するのが難しい場合は、次のように Build Event Protocol の正規のコマンドラインを使用します。

    a. ログのテキスト バージョンを取得するには、--build_event_text_file=/tmp/bep.txt を Bazel コマンドに追加します。

    b. ログのテキスト バージョンを開き、 structured_command_line メッセージを検索します。command_line_label: "canonical". 展開後のすべてのオプションが一覧表示されます。

    c. remote_accept_cached を検索し、false に設定されているかどうかを確認します。

    d. remote_accept_cachedfalse の場合は、コマンドラインまたは bazelrc ファイルのどちらで false に設定されているかを確認します。

マシン間のキャッシュを確認する

同じマシンで想定どおりにキャッシュ ヒットが発生したら、別のマシンで 同じビルドまたはテストを実行します。マシン間でキャッシュが発生していないと思われる場合は、次の操作を行います。

  1. 既存のキャッシュにヒットしないように、ビルドを少し変更します。

  2. 最初のマシンでビルドを実行します。

     bazel clean
     bazel ... build ... --execution_log_compact_file=/tmp/exec1.log
  3. 2 台目のマシンでビルドを実行し、ステップ 1 の変更が含まれていることを確認します。

     bazel clean
     bazel ... build ... --execution_log_compact_file=/tmp/exec2.log
  4. 2 回の実行の実行ログを比較します 。ログが同一でない場合は、ビルド構成 の不一致と、ホスト環境のプロパティがどちらかのビルドに漏洩しているかどうかを調べます。

実行ログを比較する

実行ログには、ビルド中に実行されたアクションのレコードが含まれています。 各レコードには、アクションの入力(ファイルだけでなく、コマンドライン 引数、環境変数など)と出力の両方が記述されています。したがって、 ログを調べることで、アクションが再実行された理由を明らかにできます。

実行ログは、コンパクト(--execution_log_compact_file)、バイナリ(--execution_log_binary_file)、JSON(--execution_log_json_file)の 3 つの形式のいずれかで生成できます。コンパクト形式は、ランタイムのオーバーヘッドが非常に少なく、はるかに小さいファイルを生成するため、おすすめです。次の手順は、どの形式でも使用できます。 ツールを使用して、形式を変換することもできます。//src/tools/execlog:converter

想定どおりにキャッシュ ヒットを共有していない 2 つのビルドのログを比較するには、 次の操作を行います。

  1. 各ビルドから実行ログを取得し、/tmp/exec1.log/tmp/exec2.log として保存します。

  2. Bazel のソースコードをダウンロードし、//src/tools/execlog:parser ツールをビルドします。

    git clone https://github.com/bazelbuild/bazel.git cd bazel bazel build //src/tools/execlog:parser

  3. //src/tools/execlog:parser ツールを使用して、ログを 人間が読めるテキスト形式に変換します。この形式では、2 番目のログのアクションが 最初のログの順序と一致するように並べ替えられるため、比較が容易になります。

    bazel-bin/src/tools/execlog/parser \
      --log_path=/tmp/exec1.log \
      --log_path=/tmp/exec2.log \
      --output_path=/tmp/exec1.log.txt \
      --output_path=/tmp/exec2.log.txt
    
  4. 任意のテキスト差分ツールを使用して、/tmp/exec1.log.txt/tmp/exec2.log.txt の差分を確認します。