使用跟踪功能深入了解系统性能

使用跟踪功能记录系统上的事件和计数器,并在时间轴上直观呈现每个事件和计数器。Android 中的标准跟踪工具是 Perfetto。如需了解详情,请参阅跟踪 101

为代码插桩

如需从应用获取事件,需要通过在代码中添加跟踪点来对应用进行插桩。未插桩的部分不会显示在轨迹中。

SDV 跟踪示例演示了跟踪集成,并提供了跟踪配置的说明和示例。该示例位于 system/software_defined_vehicle/core_services/samples/tracing/ 中。

Rust

对于 Rust,建议使用 tracing crate 来发出 ATrace 事件。Perfetto 支持将 ATrace 作为数据源。我们计划在 Rust 绑定可用时切换到 Perfetto SDK,具体取决于使用情形的发展情况。

将跟踪默认值添加到 Android.bp

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

初始化订阅者。每个进程只能执行一次:

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 示例中一样,此代码会生成两个嵌套切片和一个用于界面中即时事件的标记。选择事件后,系统会显示调试实参值。

收集轨迹

使用 record\_android\_trace 命令行脚本记录轨迹,并使用 Perfetto 网页界面查看轨迹。

配置捕获

您需要以 textproto 格式为 record_android_trace 提供配置。如需了解详情,请参阅 Perfetto 文档

SDV 代码库包含一个示例配置 (system/software_defined_vehicle/core_services/samples/tracing/config/trace_cfg.pbtx)。此文件包含多个数据源,可以自定义或直接使用。

使用 Perfetto 界面生成配置

您可以在 Perfetto 界面中前往记录新轨迹,调整记录设置和探测,以配置自定义配置并探索可用选项。然后,您可以打开“录制命令”视图,查看生成的命令并从中获取配置内容。

配置应用内插桩测试的可见性

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 字段中启用或停用类别和标签。默认情况下,所有类别结束标记均处于启用状态,但特殊的 slowdebug 标记除外。 如果您只想启用特定类别,则需要停用所有其他类别,例如使用 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 会生成用于提供轨迹的网址,但不会打开浏览器。当您设置了端口转发(通常为 9001)时,此命令对于远程会话非常有用。

  • -n, --no-open 不会打开浏览器,也不会在跟踪会话结束后生成用于提供轨迹的网址。您仍然可以在 Perfetto 界面中打开文件,只需点击“Open trace file”,然后选择相应文件即可。

  • -o <path> 设置输出路径。

使用情况详情

本部分提供了一些在使用跟踪系统时可能很有用的详细信息。

SDV 组件中的轨迹插桩

在具有跟踪检测功能的代理中,除非另有指定,否则跟踪功能默认在可调试 build (-eng-userdebug) 上可用。收集轨迹时,您应该会看到进程的事件,而无需进行额外的配置。

库通常不会自动初始化跟踪。在 Rust 中,使用该库的二进制文件需要使用 sdv_tracing::init_tracing() 为进程初始化跟踪。如需了解详情,请参阅为代码插桩

中间件

发布/订阅库libsdv_middleware_dt

活动:

  • 发布商:发布和注册主题。
  • 订阅者:订阅和参与投票。

启用:在二进制文件中调用 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 虚拟机上收集的。

  • 单个跨度:tracing::info_span!()#[tracing::instrument] 和类似跨度:
    • 跟踪未初始化:1 纳秒。
    • 跟踪已初始化并已停用(未进行任何跟踪记录):30 纳秒。
    • 启用跟踪:3 微秒。调试字段注释可能会增加 1-2 微秒,具体取决于字符串化的复杂程度。
  • 单事件:tracing::info!() 及类似事件:
    • 跟踪未初始化:1 纳秒。
    • 跟踪已初始化并已停用:30 纳秒。
    • 启用跟踪:1.5 微秒。调试字段注释可能会增加 0.5-1 微秒,具体取决于 stringification 的复杂程度。
C++

性能数据来自 Perfetto 中“跟踪事件”文档的性能部分。表格中 Pixel 3 的时间与我们在 Cuttlefish 虚拟机上的观测结果一致。

单一切片:TRACE_EVENT() 及类似内容。跟踪:

  • 已停用:2 纳秒。
  • 已启用:300 纳秒。使用调试字段注释可能会增加 50-100 纳秒。