Utiliser le traçage pour obtenir des insights sur les performances du système

Utilisez le traçage pour enregistrer les événements et les compteurs sur le système, et pour visualiser chacun d'eux sur une chronologie. L'outil de traçage standard dans Android est Perfetto. Pour en savoir plus, consultez Mes premiers pas avec le traçage.

Instrumenter votre code

Pour obtenir des événements à partir de l'application, celle-ci doit être instrumentée en ajoutant des points de trace dans le code. Les sections qui ne sont pas instrumentées n'apparaissent pas dans les traces.

L'exemple de traçage SDV est une démonstration de l'intégration du traçage, avec des instructions et un exemple de configuration de traçage. Il se trouve dans system/software_defined_vehicle/core_services/samples/tracing/.

Rust

Pour Rust, l'approche recommandée consiste à utiliser la crate tracing pour émettre des événements ATrace. Perfetto est compatible avec ATrace en tant que source de données. Nous prévoyons de passer au SDK Perfetto lorsque les liaisons Rust seront disponibles et en fonction de l'évolution des cas d'utilisation.

Ajoutez les valeurs par défaut de traçage à Android.bp :

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

Initialisez l'abonné. Cette opération n'est possible qu'une seule fois par processus :

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

Vous pouvez omettre l'appel d'initialisation. Dans ce cas, le traçage n'est pas initialisé et Perfetto ne collecte pas les événements d'instrumentation de l'application.

Ajoutez des points de trace. Vous trouverez d'autres exemples dans 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++

Le traçage C++ utilise le SDK Perfetto pour suivre les événements. Ajoutez les valeurs par défaut du traçage à Android.bp :

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

Définissez les catégories. Si vous utilisez les catégories dans plusieurs modules, déplacez-les dans une bibliothèque commune. Par exemple, system/software_defined_vehicle/core_services/samples/tracing/cpp_service/tracing_categories.h.

Dans l'en-tête :

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

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

Placez la macro de stockage statique dans un fichier source .cpp, et non dans une méthode. Si vous partagez les catégories entre les composants, utilisez le fichier source qui correspond à l'en-tête avec les catégories.

PERFETTO_TRACK_EVENT_STATIC_STORAGE();

int main() {
    ...
}

Pour initialiser Perfetto, initialisez le backend du système et enregistrez les événements de suivi :


#include <sdv/tracing_init.h>

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

Ajoutez une instrumentation. Pour voir d'autres exemples, consultez 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;
}

Comme dans l'exemple Rust, ce code produit deux tranches imbriquées et un repère pour l'événement instantané dans l'UI. Les valeurs des arguments de débogage sont affichées lorsqu'un événement est sélectionné.

Collecter une trace

Utilisez le script de ligne de commande record\_android\_trace pour enregistrer une trace et l'UI Web Perfetto pour l'afficher.

Configurer la capture

Vous devez fournir une configuration pour record_android_trace au format textproto. Pour en savoir plus, consultez la documentation Perfetto.

Le dépôt SDV contient un exemple de configuration (system/software_defined_vehicle/core_services/samples/tracing/config/trace_cfg.pbtx). Ce fichier inclut plusieurs sources de données et peut être personnalisé ou utilisé tel quel.

Utiliser l'interface utilisateur Perfetto pour générer une configuration

Vous pouvez configurer une configuration personnalisée et explorer les options disponibles en accédant à Enregistrer une nouvelle trace dans l'UI Perfetto, puis en ajustant les paramètres d'enregistrement et les sondes. Vous pouvez ensuite ouvrir la vue "Recording command" (Commande d'enregistrement) pour afficher la commande générée et obtenir le contenu de la configuration.

Configurer la visibilité de l'instrumentation dans l'application

L'instrumentation Rust utilise ATrace. Il est configuré dans la section ftrace_config du document. Les composants SDV sont associés à la balise ATRACE_TAG_APP et peuvent être activés application par application. L'exemple de configuration active toutes les applications.

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

Nous utilisons des événements de suivi dans le SDK Perfetto C++. Il s'agit d'une source de données track_event (documentation).

Vous pouvez activer ou désactiver les catégories et les tags dans le champ track_event_config. La balise de fin de chaque catégorie est activée par défaut, à l'exception des balises spéciales slow et debug. Si vous ne souhaitez activer que certaines catégories, vous devez désactiver toutes les autres, par exemple avec disabled_categories: "*" comme ici :

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

Enregistrer une trace

Ouvrez un terminal à la racine du dépôt Android. Vous n'avez pas besoin de envsetup. Le script d'enregistrement se trouve dans external/perfetto/tools/record_android_trace.

Exécutez le script avec l'exemple de configuration :

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

Pour arrêter l'enregistrement plus tôt, sélectionnez Ctrl+C.

Cette opération déclenche adb shell perfetto pour enregistrer une trace, puis l'extraire vers l'hôte, généralement dans ~/traces. Une fois la trace collectée, l'outil ouvre une fenêtre de navigateur pour l'afficher.

Arguments utiles :

  • -s SERIAL pour utiliser l'appareil avec un numéro de série donné. Par exemple, -s 0.0.0.0:6520

  • --no-open-browser créerait une URL pour diffuser la trace, mais n'ouvrirait pas le navigateur. Il est utile pour les sessions à distance lorsque vous avez configuré le transfert de port (généralement 9001).

  • -n, --no-open n'ouvrira pas le navigateur ni ne créera l'URL pour diffuser la trace après la session de traçage. Vous pouvez toujours ouvrir des fichiers dans l'interface utilisateur de Perfetto en cliquant sur "Ouvrir le fichier de suivi" et en sélectionnant le fichier.

  • -o <path> pour définir le chemin de sortie.

Infos d'utilisation

Cette section fournit des informations qui peuvent être utiles lorsque vous utilisez le système de traçage.

Instrumentation du traçage dans les composants SDV

Dans les agents avec instrumentation de traçage, le traçage est disponible par défaut sur les versions débogables (-eng, -userdebug), sauf indication contraire. Lorsque vous collectez une trace, vous devriez voir les événements pour les processus sans configuration supplémentaire.

En règle générale, les bibliothèques n'initialisent pas automatiquement le traçage. En Rust, le binaire qui utilise la bibliothèque doit initialiser le traçage pour le processus à l'aide de sdv_tracing::init_tracing(). Pour en savoir plus, consultez Instrumenter votre code.

Middleware

Bibliothèque de publication/d'abonnement : libsdv_middleware_dt

Événements :

  • Éditeur : publication et enregistrement de thèmes.
  • Abonné : s'abonner et participer à des sondages

Activation : appelez sdv_tracing::init_tracing() ou sdv_tracing::try_init_tracing() dans le binaire.

Bibliothèque gRPC : libsdvmiddleware_rpc_grpc_transport

Événements :

  • Client RPC : démarrage, connexion au serveur et appels de méthodes RPC.
  • Serveur RPC : démarrage, enregistrement auprès de la découverte de services, ajout et appel de méthodes RPC.

Activation : appelez sdv_tracing::init_tracing() ou sdv_tracing::try_init_tracing() en binaire.

SOME/IP
  • Processus : sdv_someip_broker_agent. \
  • Événements : traitement et traduction des messages, abonnement aux événements.
Gestionnaire du cycle de vie
  • Processus : sdv_lifecycle_agent. \
  • Événements : opérations de service (lancement, arrêt, enregistrement, désenregistrement).
Mode d'alimentation du véhicule
  • Processus : sdv_vpm_agent. \
  • Événements : changements d'état de l'alimentation et abonnements.
Tunnel de données

Nous prévoyons de prendre en charge l'intégration du traçage ultérieurement.

Impact sur les performances du traçage

Les mesures de surcharge sont accompagnées de la mise en garde habituelle selon laquelle les performances peuvent varier d'un système à l'autre, et en particulier entre l'émulateur et le matériel réel.

Rust

Les données brutes de référence sont disponibles dans AOSP. Les données ont été collectées sur une VM Cuttlefish.

  • Portée unique : tracing::info_span!(), #[tracing::instrument] et similaires :
    • Traçage non initialisé : 1 ns.
    • La trace est initialisée et désactivée (aucun enregistrement de trace n'a lieu) : 30 ns.
    • Traçage activé : 3 µs. Les annotations de champ de débogage peuvent ajouter 1 à 2 µs, selon la complexité de la sérialisation.
  • Événement unique : tracing::info!() et similaires :
    • Traçage non initialisé : 1 ns.
    • Traçage initialisé et désactivé : 30 ns.
    • Traçage activé : 1,5 µs. Les annotations de champ de débogage peuvent ajouter 0,5 à 1 µs, selon la complexité de stringification.
C++

Les chiffres de performances proviennent de la section "Performances" du document sur le suivi des événements dans Perfetto. Les temps pour Pixel 3 dans le tableau sont cohérents avec nos observations sur la VM Cuttlefish.

Une seule tranche : TRACE_EVENT() et autres. Traçage :

  • Désactivé : 2 s.
  • Activé : 300 ns. L'utilisation d'annotations de champ de débogage peut ajouter 50 à 100 ns.