使用跟踪功能记录系统上的事件和计数器,并在时间轴上直观呈现每个事件和计数器。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 字段中启用或停用类别和标签。默认情况下,所有类别结束标记均处于启用状态,但特殊的 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会生成用于提供轨迹的网址,但不会打开浏览器。当您设置了端口转发(通常为 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 纳秒。