Tracing verwenden, um Informationen zur Systemleistung zu erhalten

Mit Tracing können Sie Ereignisse und Zähler im System aufzeichnen und auf einer Zeitachse visualisieren. Das Standard-Tracing-Tool in Android ist Perfetto. Weitere Informationen finden Sie unter Tracing 101.

Code instrumentieren

Damit Ereignisse aus der App erfasst werden können, muss sie instrumentiert werden. Dazu müssen dem Code Tracepoints hinzugefügt werden. Abschnitte, die nicht instrumentiert sind, werden in Traces nicht angezeigt.

Das SDV-Tracing-Beispiel ist eine Demo der Tracing-Integration mit einer Anleitung und einem Beispiel für die Tracing-Konfiguration. Sie befindet sich in system/software_defined_vehicle/core_services/samples/tracing/.

Rost

Für Rust wird empfohlen, das tracing-Crate zu verwenden, um ATrace-Ereignisse auszugeben. Perfetto unterstützt ATrace als Datenquelle. Wir planen, zum Perfetto SDK zu wechseln, sobald Rust-Bindungen verfügbar sind, und je nachdem, wie sich die Anwendungsfälle entwickeln.

Fügen Sie die Standardeinstellungen für das Tracing in Android.bp ein:

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

Initialisieren Sie den Subscriber. Dies ist nur einmal pro Prozess möglich:

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()
    ...
}

Sie können den Initialisierungsaufruf weglassen. Dadurch bleibt das Tracing nicht initialisiert und Perfetto erfasst keine Instrumentierungsereignisse aus der App.

Tracepoints hinzufügen Weitere Beispiele finden Sie unter 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++

Für das C++-Tracing wird das Perfetto SDK verwendet, um Ereignisse zu erfassen. Fügen Sie die Standardeinstellungen für das Tracing zu Android.bp hinzu:

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

Definieren Sie die Kategorien. Wenn Sie die Kategorien in mehreren Modulen verwenden, verschieben Sie sie in eine gemeinsame Bibliothek. Beispiel: system/software_defined_vehicle/core_services/samples/tracing/cpp_service/tracing_categories.h

Im Header:

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

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

Platzieren Sie das Makro für die statische Speicherung in einer .cpp-Quelldatei, nicht in einer Methode. Wenn Sie die Kategorien für mehrere Komponenten freigeben, verwenden Sie die Quelldatei, die dem Header mit Kategorien entspricht.

PERFETTO_TRACK_EVENT_STATIC_STORAGE();

int main() {
    ...
}

Um Perfetto zu initialisieren, initialisieren Sie das System-Backend und registrieren Sie die Track-Ereignisse:


#include <sdv/tracing_init.h>

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

Instrumentierung hinzufügen Weitere Beispiele finden Sie unter 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;
}

Wie im Rust-Beispiel werden mit diesem Code zwei verschachtelte Slices und eine Markierung für das Instant-Ereignis in der Benutzeroberfläche erstellt. Die Werte der Debug-Argumente werden angezeigt, wenn ein Ereignis ausgewählt ist.

Trace erfassen

Verwenden Sie das record\_android\_trace-Befehlszeilenscript, um einen Trace aufzuzeichnen, und die Perfetto-Web-UI, um ihn anzusehen.

Erfassung konfigurieren

Sie müssen eine Konfiguration für record_android_trace im Textproto-Format angeben. Weitere Informationen finden Sie in der Perfetto-Dokumentation.

Das SDV-Repository enthält eine Beispielkonfiguration (system/software_defined_vehicle/core_services/samples/tracing/config/trace_cfg.pbtx). Diese Datei enthält mehrere Datenquellen und kann angepasst oder unverändert verwendet werden.

Konfiguration mit der Perfetto-Benutzeroberfläche generieren

Sie können eine benutzerdefinierte Konfiguration erstellen und verfügbare Optionen erkunden, indem Sie in der Perfetto-Benutzeroberfläche zu Record new trace (Neuen Trace aufzeichnen) gehen und die Aufzeichnungseinstellungen und Probes anpassen. Anschließend können Sie die Ansicht „Aufzeichnungsbefehl“ öffnen, um den generierten Befehl und die Konfigurationsinhalte aufzurufen.

Sichtbarkeit der In-App-Instrumentierung konfigurieren

Bei der Rust-Instrumentierung wird ATrace verwendet. Sie wird im Abschnitt ftrace_config des Dokuments konfiguriert. SDV-Komponenten haben das Tag ATRACE_TAG_APP und können pro App aktiviert werden. In der Beispielkonfiguration sind alle Apps aktiviert.

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: "*"
        }
    }
}

Wir verwenden Track-Ereignisse im C++ Perfetto SDK. Das ist eine track_event-Datenquelle (Dokumentation).

Sie können Kategorien und Tags im Feld track_event_config aktivieren oder deaktivieren. Jedes Kategorie-Ende-Tag ist standardmäßig aktiviert, mit Ausnahme der speziellen slow- und debug-Tags. Wenn Sie nur bestimmte Kategorien aktivieren möchten, müssen Sie alle anderen deaktivieren, z. B. mit disabled_categories: "*" wie hier:

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

Trace aufzeichnen

Öffnen Sie ein Terminal im Stammverzeichnis des Android-Repositorys. Sie müssen envsetup nicht ausführen. Das Aufzeichnungsskript befindet sich in external/perfetto/tools/record_android_trace.

Führen Sie das Skript mit der Beispielkonfiguration aus:

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

Wenn Sie die Aufzeichnung vorzeitig beenden möchten, drücken Sie Strg + C.

Dadurch wird adb shell perfetto ausgelöst, um einen Trace aufzuzeichnen und dann zum Host zu übertragen, normalerweise in ~/traces. Wenn der Trace erfasst wurde, öffnet das Tool ein Browserfenster, um ihn anzuzeigen.

Hilfreiche Argumente:

  • -s SERIAL, um das Gerät mit einer bestimmten Seriennummer zu verwenden. Beispiel: -s 0.0.0.0:6520

  • --no-open-browser würde eine URL erstellen, um den Trace bereitzustellen, aber den Browser nicht öffnen. Das ist nützlich für Remotesitzungen, wenn Sie die Portweiterleitung eingerichtet haben (in der Regel 9001).

  • -n, --no-open öffnet den Browser nicht und ruft die URL zum Bereitstellen des Traces nach der Tracing-Sitzung nicht auf. Sie können Dateien weiterhin in der Perfetto-Benutzeroberfläche öffnen, indem Sie auf „Open trace file“ (Trace-Datei öffnen) klicken und die Datei auswählen.

  • -o <path>, um den Ausgabepfad festzulegen.

Nutzungsdetails

In diesem Abschnitt finden Sie Details, die bei der Verwendung des Tracing-Systems hilfreich sein können.

Trace-Instrumentierung in SDV-Komponenten

In Agents mit Tracing-Instrumentierung ist Tracing standardmäßig für debugfähige Builds (-eng, -userdebug) verfügbar, sofern nicht anders angegeben. Wenn Sie einen Trace erfassen, sollten Sie die Ereignisse für die Prozesse ohne zusätzliche Konfiguration sehen.

Bibliotheken initialisieren das Tracing in der Regel nicht automatisch. In Rust muss das Binärprogramm, das die Bibliothek verwendet, das Tracing für den Prozess mit sdv_tracing::init_tracing() initialisieren. Weitere Informationen finden Sie unter Code instrumentieren.

Middleware

Publishing/Subscribing Library: libsdv_middleware_dt

Ereignisse:

  • Publisher: Themen veröffentlichen und registrieren
  • Abonnent: Abonnieren und Umfragen

Aktivieren: Rufen Sie sdv_tracing::init_tracing() oder sdv_tracing::try_init_tracing() im Binärprogramm auf.

gRPC-Bibliothek: libsdvmiddleware_rpc_grpc_transport

Ereignisse:

  • RPC-Client: Starten, Verbindung zum Server herstellen und RPC-Methoden aufrufen.
  • RPC-Server: Starten, Registrieren bei Service Discovery, Hinzufügen und Aufrufen von RPC-Methoden.

Aktivieren: Rufen Sie sdv_tracing::init_tracing() oder sdv_tracing::try_init_tracing() im Binärformat auf.

SOME/IP
  • Vorgang: sdv_someip_broker_agent. \
  • Ereignisse: Nachrichtenverarbeitung und ‑übersetzung, Ereignisabo.
Lifecycle Manager
  • Vorgang: sdv_lifecycle_agent. \
  • Ereignisse: Dienstvorgänge – Starten, Beenden, Registrieren, Aufheben der Registrierung.
Stromversorgungsmodus des Fahrzeugs
  • Vorgang: sdv_vpm_agent. \
  • Ereignisse: Änderungen des Energiestatus und Abos.
Datentunnel

Wir planen, die Integration von Tracing in Zukunft zu unterstützen.

Leistungsaufwand für die Ablaufverfolgung

Die Overhead-Messungen sind mit dem üblichen Vorbehalt verbunden, dass die Leistung je nach System und insbesondere zwischen dem Emulator und der echten Hardware variieren kann.

Rost

Rohdaten für Benchmarks sind in AOSP verfügbar. Die Daten wurden auf einer Cuttlefish-VM erhoben.

  • Einzelner Bereich: tracing::info_span!(), #[tracing::instrument] und ähnlich:
    • Tracing nicht initialisiert: 1 ns.
    • Tracing initialisiert und deaktiviert (keine Aufzeichnung): 30 ns.
    • Tracing aktiviert: 3 µs. Annotationen für Debugfelder können je nach Komplexität der Stringifizierung 1–2 µs hinzufügen.
  • Einzelnes Ereignis: tracing::info!() und ähnlich:
    • Tracing nicht initialisiert: 1 ns.
    • Tracing initialisiert und deaktiviert: 30 ns.
    • Tracing aktiviert: 1,5 µs. Das Debuggen von Feldannotationen kann je nach Komplexität von stringification 0,5 bis 1 µs dauern.
C++

Die Leistungszahlen stammen aus dem Leistungsabschnitt des Dokuments „Track events“ (Ereignisse erfassen) in Perfetto. Die Zeiten für das Pixel 3 in der Tabelle stimmen mit unseren Beobachtungen auf der Cuttlefish-VM überein.

Einzelner Slice: TRACE_EVENT() und ähnlich. Tracing:

  • Deaktiviert: 2 ns.
  • Aktiviert: 300 ns. Die Verwendung von Anmerkungen für Debugfelder kann 50–100 ns hinzufügen.