ros2_tracing 源码详细分析
工作区路径:/home/cp/work2/ros2Learn/ros2_humble/src/ros2/ros2_tracing
版本:4.1.2(Humble),子包 8 个,许可证 Apache 2.0,tracetools 质量等级 QL1。
ros2_tracing 是 ROS 2 的 LTTng 追踪框架:在 rcl / rclcpp / rmw 等核心栈插入 tracepoint,提供会话配置工具(CLI / launch),并支持用 Babeltrace 读取 CTF 轨迹做测试与分析。
平台限制:当前 仅支持 Linux + LTTng(LTTng-UST 用户态追踪;可选内核追踪需
lttng-modules-dkms)。
分析/visualization 在独立仓库tracetools_analysis。
1. 总体认识
1.1 核心职责
| 能力 | 实现包 | 说明 |
|---|---|---|
| Instrumentation API | tracetools |
TRACEPOINT() 宏 + LTTng TRACEPOINT_EVENT 定义 |
| 会话配置 | tracetools_trace |
Python 封装 LTTng session/channel/event |
| CLI 入口 | ros2trace |
ros2 trace 子命令 |
| Launch 集成 | tracetools_launch |
Trace action + LD_PRELOAD 辅助库 |
| 轨迹读取 | tracetools_read |
Babeltrace → Python dict |
| 测试框架 | tracetools_test |
TraceTestCase 自动化 trace 验证 |
| 自测 | test_tracetools / test_tracetools_launch |
覆盖各 tracepoint 与 launch action |
1.2 在 ROS 2 栈中的位置
关键设计:插桩代码 始终链接 tracetools;是否产生轨迹取决于 运行时 是否启动 LTTng session 并 enable 对应 event。未配置 session 时 tracepoint 开销极低(LTTng-UST fast path 几乎无系统调用)。
1.3 数据流概览
1 | 编译期: |
2. 仓库结构
1 | ros2_tracing/ |
| 包 | 构建类型 | 源码规模(约) | 职责 |
|---|---|---|---|
tracetools |
ament_cmake | ~1595 行 C/C++ | 宏、LTTng event 定义、符号解析 |
tracetools_trace |
ament_python | ~1190 行 Python | lttng_impl.setup/start/stop |
tracetools_launch |
ament_python | ~654 行 Python | Trace + LdPreload |
tracetools_read |
ament_python | ~189 行 Python | CTF → DictEvent |
tracetools_test |
ament_python | case/utils | 测试 harness |
ros2trace |
ament_python | ~126 行 Python | CLI 薄包装 |
test_tracetools |
ament_cmake + pytest | ~966 行 | 系统测试 |
test_tracetools_launch |
ament_python | 小 | launch 测试 |
3. 包 tracetools:插桩核心
3.1 构建与开关
CMakeLists.txt 关键选项:
| CMake 选项 | 效果 |
|---|---|
(默认)检测到 lttng-ust |
TRACETOOLS_LTTNG_ENABLED=ON,编译 tp_call.c,链接 LTTng |
TRACETOOLS_DISABLED=ON |
宏变为空操作;libtracetools 变为 INTERFACE 库(仅头文件) |
TRACETOOLS_NO_RDYNAMIC |
不导出 -rdynamic(影响回调符号解析) |
TRACETOOLS_STATUS_CHECKING_TOOL |
构建 ros2 run tracetools status 工具 |
Windows 上默认 TRACETOOLS_DISABLED=ON。
检测逻辑:
1 | pkg_check_modules(LTTNG lttng-ust) |
运行时检查:
1 | ros2 run tracetools status |
3.2 三层头文件
| 头文件 | 职责 |
|---|---|
tracetools.h |
对外 TRACEPOINT() / DECLARE_TRACEPOINT() 宏;全部 event 函数声明 |
tp_call.h |
LTTng TRACEPOINT_EVENT 定义(provider ros2);CTF 字段布局 |
utils.hpp |
tracetools::get_symbol() — 从 std::function/lambda 解析 demangled 符号 |
3.3 TRACEPOINT 宏机制
启用 LTTng 时,调用链为:
1 | TRACEPOINT(rcl_publish, publisher_handle, message); |
禁用时:
1 |
tracetools.c 在 TRACETOOLS_LTTNG_ENABLED 下 #include "tracetools/tp_call.h",用 CONDITIONAL_TP 包装每个函数。
3.4 LTTng Event 命名
Python 侧 tracepoints.py 与 LTTng 注册名一致:
1 | ros2:rcl_init |
共 28 个 ROS tracepoint(Humble),覆盖 init / pub-sub / service / timer / lifecycle / executor / callback。
3.5 Tracepoint 分层与关联字段
设计目标(见 doc/design_ros_2.md)是用 指针 handle 在层间关联对象,用 message 指针 跟踪消息在 rclcpp→rcl→rmw 的传播。
| 层级 | 初始化类 tracepoint | 运行时类 tracepoint |
|---|---|---|
| rmw | rmw_publisher_init(含 GID), rmw_subscription_init |
rmw_publish, rmw_take(含 source_timestamp, taken) |
| rcl | rcl_init, rcl_node_init, rcl_publisher_init, rcl_subscription_init, rcl_service_init, rcl_client_init, rcl_timer_init, lifecycle |
rcl_publish, rcl_take |
| rclcpp | rclcpp_subscription_init, *_callback_added, rclcpp_timer_link_node, rclcpp_callback_register |
rclcpp_publish/take, callback_start/end, executor 三件套 |
Executor 相关:
rclcpp_executor_get_next_ready— 开始取 ready executablerclcpp_executor_wait_for_work—wait阶段(带 timeout ns)rclcpp_executor_execute— 执行某rclhandle(timer/subscription)
Callback 相关:
rclcpp_callback_register— 注册 demangled 符号(需-rdynamic)callback_start/callback_end— 回调边界;is_intra_process标记 intra-process
3.6 符号解析(-rdynamic)
utils.cpp 通过 dladdr + abi::__cxa_demangle 解析回调函数名,供 rclcpp_callback_register 写入 trace。
CMake 在 LTTng 启用时默认:
1 | target_link_libraries(tracetools "-rdynamic") |
若链接时去掉 -rdynamic,符号可能变为 UNKNOWN。
3.7 下游插桩位置(核心栈,非本仓库)
插桩散布在 ROS 2 核心包,例如:
| 包 | 典型文件 | tracepoint |
|---|---|---|
rclcpp |
subscription.hpp, timer.hpp, executor.cpp |
callback_*, executor, publish/take |
rcl |
rcl/publisher.c, rcl/subscription.c |
rcl_publish, rcl_take, init |
rmw_fastrtps 等 |
rmw_publish.cpp, rmw_take.cpp |
rmw_publish, rmw_take, init |
所有上述包 package.xml 中 exec_depend/build_depend tracetools。
4. 包 tracetools_trace:LTTng 会话管理
4.1 模块结构
1 | tracetools_trace/ |
4.2 lttng_impl.setup() 流程
- 若无
lttng-sessiond→lttng-sessiond --daemonize - 若启用 kernel events →
lttng list -k检查内核追踪器 lttng.create(session_name, full_path)— 输出 CTF 目录- 创建 UST domain(
BUFFER_PER_UID)+ channelros2 - 可选 KERNEL domain + channel
kchan _enable_events— 每个 event 类型EVENT_TRACEPOINT_add_context— pid/tid/procname 等
Channel 调优(偏实时友好,见 README):
| 参数 | UST | Kernel |
|---|---|---|
| overwrite | 0(discard) | 0 |
| subbuf_size | 8×4096 | 32×4096 |
| num_subbuf | 2 | 2 |
| read_timer_interval | 200 ms | 200 ms |
| switch_timer | 0(禁用) | 0 |
4.3 默认启用事件
names.DEFAULT_EVENTS_ROS = tracepoints.py 中全部 28 个 ROS event。
DEFAULT_EVENTS_KERNEL(ros2 trace -k 时可追加)示例:
sched_switch,kmem_mm_page_*,power_cpu_frequency
4.4 轨迹目录
优先级(README 与 path.get_tracing_directory()):
$ROS_TRACE_DIR(非空)$ROS_HOME/tracing(ROS_HOME默认~/.ros)
Session 名默认 session-YYYYMMDDHHMMSS(path.append_timestamp)。
5. 包 ros2trace:ros2 trace CLI
1 | # ros2trace/command/trace.py |
CLI 参数(args.py):
| 选项 | 含义 |
|---|---|
-s/--session-name |
session 名 |
-p/--path |
基目录 |
-u/--ust EVENT... |
UST events(无参数 = 禁用全部 UST) |
-k/--kernel EVENT... |
内核 events |
-c/--context CONTEXT... |
context 字段 |
-l/--list |
打印 enabled 列表 |
典型用法:
1 | ros2 trace # 默认全部 ROS tracepoint |
trace.py 的 init() 在开始前 input('press enter to start...'),fini() 在 input('press enter to stop...') 后 destroy session — 交互式 录制。
6. 包 tracetools_launch:Launch 集成
6.1 Trace Action
1 | # example.launch.py |
生命周期:
execute()→_setup()→lttng.lttng_init(...)+lttng.start- 注册
OnShutdown→_destroy()→lttng_fini - 返回
LdPreload子 action 列表(按需LD_PRELOADUST helper)
Launch 前端:@expose_action('trace'),支持 Python / XML / YAML(events-ust, events-kernel, context-fields 等)。
6.2 LdPreload 与 UST helper
当 UST event 列表匹配特定 pattern 时自动 preload:
| 库 | 典型 events |
|---|---|
liblttng-ust-libc-wrapper.so |
lttng_ust_libc:malloc 等 |
liblttng-ust-pthread-wrapper.so |
lttng_ust_pthread:* |
liblttng-ust-cyg-profile-fast.so |
函数 entry/exit(fast) |
liblttng-ust-dl.so |
lttng_ust_dl:* |
通过 whereis -b 查找 .so 路径,追加 LD_PRELOAD 环境变量。
6.3 与 ros2 trace 对比
| 维度 | ros2 trace |
Trace launch action |
|---|---|---|
| 启停 | 手动 Enter | 随 launch 自动 start/stop |
| 适用 | 任意已运行进程 | 与 launch 文件中的 Node 同步 |
| LD_PRELOAD | 无 | 按 events 自动配置 |
| 交互 | 有 | 无 |
7. 包 tracetools_read:读取 CTF
1 | from tracetools_read.trace import get_trace_events |
- 使用 Babeltrace 1.x Python API(
babeltrace.TraceCollection) add_traces_recursive(path, 'ctf')- 过滤 CTF 元数据字段(
packet_size,stream_id等)
辅助函数(tracetools_read/__init__.py):get_event_name, get_field, get_procname 等。
8. 包 tracetools_test:测试基础设施
8.1 TraceTestCase
自动化流程(case.py):
run_and_trace()— 创建 LTTng session → 启动指定 package 的 nodes → 停止get_trace_events()读 CTF- 断言:event 集合、时间戳、procname、handle 指针有效性、字段类型
tearDown()删除 trace 目录(除非TRACETOOLS_TEST_DEBUG非空)
8.2 test_tracetools 用法示例
1 | class TestPublisher(TraceTestCase): |
覆盖:publisher、subscription、service、timer、executor、lifecycle、intra-process 等场景。
9. 构建与部署
9.1 依赖安装(Ubuntu)
1 | sudo apt install lttng-tools liblttng-ust-dev python3-babeltrace python3-lttng |
9.2 从源码启用 tracing
若先装了 ROS 二进制再装 LTTng,需重编至少到 tracetools:
1 | colcon build --packages-up-to tracetools --cmake-force-configure |
9.3 完全禁用
1 | colcon build --cmake-args "-DTRACETOOLS_DISABLED=ON" |
核心栈仍包含 TRACEPOINT 调用,但编译为空操作,不链接 LTTng。
10. 与分析工具的关系
本仓库 不负责 统计/可视化;设计文档指向 tracetools_analysis:
- 读取 CTF / 构建 callback 时长、消息年龄、调度干扰等指标
- 可与 kernel events(
sched_switch等)联合分析
数据契约即 tp_call.h 中的 CTF 字段 + context 字段。
11. 实时性说明
LTTng-UST 面向生产环境低延迟追踪(README 引用的 RA-L 论文)。默认 channel 配置已采用:
- discard 模式(不阻塞业务线程写缓冲)
- read timer 而非 switch timer(减少
write()syscall) - 较小 sub-buffer 数量
进一步实时调优(手动 URCU 注册、sub-buffer 大小等)需直接使用 LTTng API;ros2 trace / Trace action 尚未 暴露全部 channel 参数(见 issue #129)。
12. 环境变量与配置
| 变量 | 作用 |
|---|---|
ROS_TRACE_DIR |
轨迹基目录(优先于 ~/.ros/tracing) |
ROS_HOME |
默认 ~/.ros,其下 tracing/ |
TRACETOOLS_TEST_DEBUG |
测试后保留 trace 目录 |
LD_PRELOAD |
launch 可能追加 LTTng UST helper |
13. 扩展插桩指南
在自定义包中添加 tracing(摘自 design doc):
package.xml添加depend tracetools#include "tracetools/tracetools.h"- 在合适位置调用已有
TRACEPOINT(...)或 - 在
tp_call.h+tracetools.h+tracetools.c增加新 event(需改tracetools包并 release) - 在
tracepoints.py/DEFAULT_EVENTS_ROS注册 LTTng 名 - 用
tracetools_test.TraceTestCase验证
用户态 generic tracepoint 可直接使用 LTTng lttng_ust_tracepoint API,不必经过 tracetools 宏。
14. 调试建议
- 确认编译启用:
ros2 run tracetools status - 确认 session 在跑:
lttng list - 无 event:检查 enable 的 event 名是否为
ros2:*;节点是否用带 tracing 的 overlay 构建 - 空 trace 目录:session 未 start、或进程 domain 与 session 不匹配
- 符号 UNKNOWN:检查
-rdynamic、回调是否为 lambda 且无target<> - 读 trace 失败:安装
python3-babeltrace,路径是否为 session 根目录 - 内核 event 失败:用户是否在
tracing组、是否加载lttng-modules
15. 推荐阅读顺序
- 仓库
README.md— 构建、CLI、launch 快速上手 doc/design_ros_2.md— tracepoint 语义与分层表tracetools/include/tracetools/tracetools.h— 全部 APItracetools/include/tracetools/tp_call.h— CTF 字段定义tracetools/src/tracetools.c— 宏到 LTTng 的桥接tracetools_trace/tools/lttng_impl.py— session 创建细节tracetools_launch/action.py— Launch 生命周期 + LD_PRELOADtracetools_test/case.py— 如何写 trace 单测test_tracetools/test/test_publisher.py— 字段断言示例- 核心栈插桩点 —
rclcpp/executor.cpp,rmw_fastrtps/rmw_publish.cpp等
16. 小结
ros2_tracing 将 ROS 2 运行时行为映射为 LTTng CTF 轨迹,形成「插桩 → 会话 → 存储 → 读取/分析」完整链路:
tracetools:稳定 C API + LTTng providerros2,被 rcl/rclcpp/rmw 硬依赖(可编译为空操作);tracetools_trace+ros2trace:交互式ros2 trace会话管理;tracetools_launch:与 launch 同生命周期自动 tracing,并智能LD_PRELOAD;tracetools_read/tracetools_test:CTF 消费与回归测试。
Humble 上若仅安装二进制 ROS 而未重编 tracetools,默认 Tracing disabled;性能分析、executor 调度可视化、回调延迟测量等场景,需安装 LTTng 并重编核心栈,再配合 tracetools_analysis 或自定义 Babeltrace 脚本处理 ~/.ros/tracing/session-* 下的 CTF 数据。
正在加载留言…