トレースを使用してシステム パフォーマンスに関する分析情報を取得する

トレースを使用して、システム上のイベントとカウンタを記録し、それぞれをタイムライン上に可視化します。Android の標準トレースツールは Perfetto です。詳しくは、トレース入門ガイドをご覧ください。

コードをインストルメント化する

アプリからイベントを取得するには、コードにトレースポイントを追加して計測する必要があります。計測されていないセクションはトレースに表示されません。

SDV トレース サンプルは、トレース統合のデモです。手順とトレース構成の例が示されています。system/software_defined_vehicle/core_services/samples/tracing/ にあります。

Rust

Rust の推奨アプローチは、tracing クレートを使用して ATrace イベントを発行することです。Perfetto は ATrace をデータソースとしてサポートしています。Rust バインディングが利用可能になり、ユースケースの進化に応じて、Perfetto SDK に切り替える予定です。

トレースのデフォルトを Android.bp に追加します。

rust_binary {
...
    defaults: [
        ...
        "sdv_tracing@rust_defaults",
    ],
...
}

サブスクライバーを初期化します。これはプロセスごとに 1 回だけ行うことができます。

fn main() {
    // Initialize the subscriber, panic if it fails.
    // sdv_tracing::try_init_tracing() is the version that returns a Result.
    sdv_tracing::init_tracing()
    ...
}

初期化呼び出しを省略できます。省略すると、トレースは初期化されず、Perfetto はアプリから計測イベントを収集しません。

トレースポイントを追加します。その他のサンプルについては、system/software_defined_vehicle/core_services/samples/tracing/rust_tracing_api_demo/tracing.rs をご覧ください。

use tracing::{instrument, info_span};

// #[tracing::instrument] wraps the method into a tracing span and records arguments.
// Use #[instrument(skip(num))] if you don't want to record the argument.
#[instrument]
fn mul_by_100(num: i32) -> i32 {
    // Create and enter a span with INFO verbosity, name, and a debug field annotation.
    // The span will exit when dropped.
    let _span = info_span!("This is a span", var=123).entered();
    let result = num * 100;
    // Emit an instant INFO event that records the result value.
    // We recommend to fully qualify the crate when using events to avoid confusion with log records.
    tracing::info!(result, "Completed");
    result
}

C++

C++ トレースでは、Perfetto SDK を使用してイベントを追跡します。Android.bp にトレースのデフォルトを追加します。

cc_binary {
...
    defaults: [
...
        "sdv_tracing@cc_defaults",
    ],
...
}

カテゴリを定義します。複数のモジュールでカテゴリを使用する場合は、共通ライブラリに移動します。例: system/software_defined_vehicle/core_services/samples/tracing/cpp_service/tracing_categories.h

ヘッダー内:

#include "perfetto/tracing/tracing.h"
#include "perfetto/tracing/track_event.h"

PERFETTO_DEFINE_CATEGORIES(
        perfetto::Category("sample")
                .SetTags("tag")
                .SetDescription("Sample events"));

静的ストレージ マクロは、メソッドではなく .cpp ソースファイルに配置します。カテゴリをコンポーネント間で共有する場合は、カテゴリを含むヘッダーに対応するソースファイルを使用します。

PERFETTO_TRACK_EVENT_STATIC_STORAGE();

int main() {
    ...
}

Perfetto を初期化するには、システム バックエンドを初期化して、トラック イベントを登録します。


#include <sdv/tracing_init.h>

int main() {
  ...
  android::sdv::InitPerfettoWithTrackEvents<perfetto::TrackEvent>();
  ...
}

計測手法を追加します。system/software_defined_vehicle/core_services/samples/tracing/cpp_service/client.cpp で他のサンプルをご覧ください。

int32_t mulBy100(int32_t num) {
    // Start a slice that will get closed at the end of the scope.
    TRACE_EVENT("client", "mulBy100", "num", num);

    TRACE_EVENT("client", "This is a slice", "var", 123);
    int32_t result = num * 100;

    // Instant events have zero duration. They are drawn as markers on the track.
    TRACE_EVENT_INSTANT("client", "Completed", "result", result);
    return result;
}

Rust の例と同様に、このコードは 2 つのネストされたスライスと、UI 内のインスタント イベントのマーカーを生成します。イベントを選択すると、デバッグ引数の値が表示されます。

トレースを収集する

record\_android\_trace コマンドライン スクリプトを使用してトレースを記録し、Perfetto ウェブ UI を使用して表示します。

キャプチャを構成する

record_android_trace の構成を textproto 形式で指定する必要があります。詳細については、Perfetto のドキュメントをご覧ください。

SDV リポジトリには、サンプル構成(system/software_defined_vehicle/core_services/samples/tracing/config/trace_cfg.pbtx)が含まれています。このファイルには複数のデータソースが含まれており、カスタマイズすることも、そのまま使用することもできます。

Perfetto UI を使用して構成を生成する

カスタム構成を設定し、使用可能なオプションを確認するには、Perfetto UI の [新しいトレースを記録] に移動し、記録設定とプローブを調整します。[Recording command] ビューを開いて、生成されたコマンドを確認し、そこから構成内容を取得できます。

アプリ内インストルメンテーションの可視性を構成する

Rust の計測では ATrace が使用されます。これはドキュメントの ftrace_config セクションで構成されます。SDV コンポーネントには ATRACE_TAG_APP タグがあり、アプリごとに有効にできます。サンプル設定では、すべてのアプリが有効になります。

data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            # Setting atrace_apps to "*" enable ATrace events for all apps.
            # You can set it to a pattern to match specific processes by name.
            # Use multiple atrace_apps entries to enable multiple processes.
            atrace_apps: "*"
        }
    }
}

C++ Perfetto SDK でトラック イベントを使用します。これは track_event データソース(ドキュメント)です。

カテゴリとタグは track_event_config フィールドで有効または無効にできます。特別な slow タグと debug タグを除き、すべてのカテゴリ終了タグはデフォルトで有効になっています。特定のカテゴリのみを有効にする場合は、他のすべてのカテゴリを無効にする必要があります。たとえば、次のように disabled_categories: "*" を使用します。

data_sources: {
    config {
        name: "track_event"
        track_event_config {
            enabled_categories: "the_best_category_in_the_world"
            disabled_categories: "*"
        }
    }
}

トレースを記録する

Android リポジトリのルートでターミナルを開きます。envsetup を行う必要はありません。録音スクリプトは external/perfetto/tools/record_android_trace にあります。

サンプル構成でスクリプトを実行します。

external/perfetto/tools/record_android_trace --config system/software_defined_vehicle/core_services/samples/tracing/config/trace_cfg.pbtx

録画を途中で停止するには、Ctrl+C キーを押します。

これにより、adb shell perfetto がトリガーされ、トレースが記録されてから、通常は ~/traces でホストにトレースがプルされます。トレースが収集されると、ツールによってブラウザ ウィンドウが開かれ、トレースが表示されます。

便利な引数:

  • -s SERIAL: 指定されたシリアル番号のデバイスを使用します。例: -s 0.0.0.0:6520

  • --no-open-browser はトレースを提供する URL を作成しますが、ブラウザは開きません。ポート転送(通常は 9001)が設定されているリモート セッションで役立ちます。

  • -n, --no-open は、ブラウザを開いたり、トレース セッション後にトレースを提供する URL を作成したりしません。[トレース ファイルを開く] をクリックしてファイルを選択すれば、Perfetto UI でファイルを開くことはできます。

  • -o <path> を使用して出力パスを設定します。

使用状況の詳細

このセクションでは、トレース システムを使用する際に役立つ詳細について説明します。

SDV コンポーネントのトレース計測

トレース計測機能を持つエージェントでは、特に指定がない限り、デバッグ可能なビルド(-eng-userdebug)でトレースがデフォルトで利用可能です。トレースを収集すると、追加の構成なしでプロセスのイベントが表示されます。

通常、ライブラリはトレースを自動的に初期化しません。Rust では、ライブラリを使用するバイナリは、sdv_tracing::init_tracing() を使用してプロセスのトレースを初期化する必要があります。詳しくは、コードを計測するをご覧ください。

ミドルウェア

パブリッシュ/サブスクライブ ライブラリ: libsdv_middleware_dt

イベント:

  • パブリッシャー: トピックのパブリッシュと登録。
  • Subscriber: サブスクライブとポーリング。

有効化: バイナリで sdv_tracing::init_tracing() または sdv_tracing::try_init_tracing() を呼び出します。

gRPC ライブラリ: libsdvmiddleware_rpc_grpc_transport

イベント:

  • RPC クライアント: 起動、サーバーへの接続、RPC メソッド呼び出し。
  • RPC サーバー: 開始、サービス ディスカバリへの登録、RPC メソッドの追加と呼び出し。

有効化: バイナリで sdv_tracing::init_tracing() または sdv_tracing::try_init_tracing() を呼び出します。

SOME/IP
  • プロセス: sdv_someip_broker_agent。\
  • イベント: メッセージ処理と変換、イベント サブスクリプション。
ライフサイクル マネージャー
  • プロセス: sdv_lifecycle_agent。\
  • イベント: サービス オペレーション - 起動、停止、登録、登録解除。
車両の電源モード
  • プロセス: sdv_vpm_agent。\
  • イベント: 電源状態の変更とサブスクリプション。
データ トンネル

トレース統合は、今後サポートする予定です。

トレースのパフォーマンス オーバーヘッド

オーバーヘッドの測定値には、パフォーマンスがシステムによって、特にエミュレータと実際のハードウェアで異なる可能性があるという通常の注意書きが付きます。

Rust

ベンチマークの元データは AOSP で入手可能です。データは Cuttlefish VM で収集されました。

  • 単一スパン: tracing::info_span!()#[tracing::instrument] など:
    • トレースの初期化: 1 ナノ秒。
    • トレースが初期化され、無効になっている(トレースの記録が行われていない)場合: 30 ns。
    • トレースが有効: 3 µs。デバッグ フィールド アノテーションは、文字列化の複雑さによって 1 ~ 2 マイクロ秒を追加する可能性があります。
  • 単一イベント: tracing::info!() など:
    • トレースの初期化: 1 ナノ秒。
    • トレースが初期化され、無効になっている場合: 30 ナノ秒。
    • トレースが有効: 1.5 µs。デバッグ フィールド アノテーションは、stringification の複雑さによって 0.5 ~ 1 µs を追加する可能性があります。
C++

パフォーマンスの数値は、Perfetto の「イベントの追跡」ドキュメントのパフォーマンス セクションから取得しています。表の Google Pixel 3 の時間は、Cuttlefish VM での測定結果と一致しています。

単一スライス: TRACE_EVENT() など。トレース:

  • 無効: 2ns。
  • 有効: 300 ns。デバッグ フィールド アノテーションを使用すると、50 ~ 100 ナノ秒が追加される可能性があります。