ros2_tracing 源码详细分析

ros2_tracing 源码详细分析

工作区路径:/home/cp/work2/ros2Learn/ros2_humble/src/ros2/ros2_tracing
版本:4.1.2(Humble),子包 8 个,许可证 Apache 2.0tracetools 质量等级 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 栈中的位置

应用 / rclcpp 节点已插桩核心栈ros2_tracing 仓库LTTng 栈Node / Executor / Callbacksrclcpprclrmw_*tracetools\nlibtracetools.sotracetools_trace\nLTTng Python APIros2trace\nros2 tracetracetools_launch\nTrace actiontracetools_read\nbabeltraceLTTng-UST\n用户态 tracepointlttng-sessiondCTF 轨迹文件

关键设计:插桩代码 始终链接 tracetools;是否产生轨迹取决于 运行时 是否启动 LTTng session 并 enable 对应 event。未配置 session 时 tracepoint 开销极低(LTTng-UST fast path 几乎无系统调用)。

1.3 数据流概览

1
2
3
4
5
6
7
8
9
10
11
编译期:
rclcpp/rcl/rmw 源码 #include tracetools/tracetools.h
→ 链接 libtracetools.so
→ tp_call.h 生成 LTTng provider "ros2" 的 TRACEPOINT_EVENT

运行期:
ros2 trace / Trace launch action
→ lttng.create + enable events (ros2:rcl_publish 等)
→ lttng.start
→ 用户启动节点 → tracepoint 写入 UST buffer → CTF 文件
→ tracetools_read / tracetools_analysis 解析

2. 仓库结构

1
2
3
4
5
6
7
8
9
10
11
12
ros2_tracing/
├── README.md # 构建、ros2 trace、launch 示例、实时性说明
├── doc/design_ros_2.md # ★ 设计文档:tracepoint 语义、分层表
├── tracing.repos # 可选 vendoring
├── tracetools/ # ★ C/C++ 插桩库(QL1)
├── tracetools_trace/ # LTTng session 管理
├── tracetools_launch/ # Launch Trace action
├── tracetools_read/ # Babeltrace 读取
├── tracetools_test/ # TraceTestCase 测试基类
├── ros2trace/ # ros2cli 扩展
├── test_tracetools/ # ping/pong 等可执行 + Python 单测
└── test_tracetools_launch/ # launch 集成测试
构建类型 源码规模(约) 职责
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
2
3
4
5
pkg_check_modules(LTTNG lttng-ust)
if(LTTNG_FOUND)
set(TRACETOOLS_LTTNG_ENABLED TRUE)
endif()
configure_file(config.h.in → config.h) # TRACETOOLS_DISABLED / TRACETOOLS_LTTNG_ENABLED

运行时检查:

1
2
3
ros2 run tracetools status
# Tracing enabled ← TRACETOOLS_LTTNG_ENABLED 且未 DISABLED
# Tracing disabled

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
2
3
TRACEPOINT(rcl_publish, publisher_handle, message);
ros_trace_rcl_publish(...) // tracetools.c 中实现
tracepoint(ros2, rcl_publish, ...) // LTTng UST

禁用时:

1
#define TRACEPOINT(...) ((void)(0))

tracetools.cTRACETOOLS_LTTNG_ENABLED#include "tracetools/tp_call.h",用 CONDITIONAL_TP 包装每个函数。

3.4 LTTng Event 命名

Python 侧 tracepoints.py 与 LTTng 注册名一致:

1
2
3
4
5
6
ros2:rcl_init
ros2:rcl_node_init
ros2:rmw_publisher_init
...
ros2:callback_start
ros2:rclcpp_executor_execute

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 executable
  • rclcpp_executor_wait_for_workwait 阶段(带 timeout ns)
  • rclcpp_executor_execute — 执行某 rcl handle(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
2
target_link_libraries(tracetools "-rdynamic")
ament_export_link_flags("-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.xmlexec_depend/build_depend tracetools


4. 包 tracetools_trace:LTTng 会话管理

4.1 模块结构

1
2
3
4
5
6
7
8
9
10
11
tracetools_trace/
├── trace.py # init/fini 入口(交互式 press enter)
└── tools/
├── lttng.py # 门面:is_lttng_installed, lttng_init/fini
├── lttng_impl.py # ★ setup/start/stop/destroy
├── lttng_stub.py # 无 lttng 模块时的 stub
├── names.py # DEFAULT_EVENTS_ROS/KERNEL, DEFAULT_CONTEXT
├── tracepoints.py # ros2:* 字符串常量
├── args.py # CLI 参数解析
├── path.py # ROS_TRACE_DIR / ~/.ros/tracing
└── signals.py # SIGINT 时 fini session

4.2 lttng_impl.setup() 流程

  1. 若无 lttng-sessiondlttng-sessiond --daemonize
  2. 若启用 kernel events → lttng list -k 检查内核追踪器
  3. lttng.create(session_name, full_path) — 输出 CTF 目录
  4. 创建 UST domainBUFFER_PER_UID)+ channel ros2
  5. 可选 KERNEL domain + channel kchan
  6. _enable_events — 每个 event 类型 EVENT_TRACEPOINT
  7. _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_KERNELros2 trace -k 时可追加)示例:

  • sched_switch, kmem_mm_page_*, power_cpu_frequency

4.4 轨迹目录

优先级(README 与 path.get_tracing_directory()):

  1. $ROS_TRACE_DIR(非空)
  2. $ROS_HOME/tracingROS_HOME 默认 ~/.ros

Session 名默认 session-YYYYMMDDHHMMSSpath.append_timestamp)。


5. 包 ros2traceros2 trace CLI

1
2
3
4
5
# ros2trace/command/trace.py
class TraceCommand(CommandExtension):
def main(...):
init(session_name=..., ros_events=..., kernel_events=..., ...)
fini(session_name=...)

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
2
3
4
ros2 trace                    # 默认全部 ROS tracepoint
ros2 trace -k sched_switch # 附加内核 event
ros2 trace -u # 仅内核/无 ROS(若再配合 -k)
# 另一终端运行节点,回到 trace 终端按 Enter 停止

trace.pyinit() 在开始前 input('press enter to start...')fini()input('press enter to stop...') 后 destroy session — 交互式 录制。


6. 包 tracetools_launch:Launch 集成

6.1 Trace Action

1
2
3
# example.launch.py
Trace(session_name='my-tracing-session'),
Node(package='test_tracetools', executable='test_ping', ...),

生命周期

  1. execute()_setup()lttng.lttng_init(...) + lttng.start
  2. 注册 OnShutdown_destroy()lttng_fini
  3. 返回 LdPreload 子 action 列表(按需 LD_PRELOAD UST 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
2
3
4
from tracetools_read.trace import get_trace_events

events = get_trace_events('/path/to/session-xxx')
# List[DictEvent]: {'_name', '_timestamp', ...fields}
  • 使用 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):

  1. run_and_trace() — 创建 LTTng session → 启动指定 package 的 nodes → 停止
  2. get_trace_events() 读 CTF
  3. 断言:event 集合、时间戳、procname、handle 指针有效性、字段类型
  4. tearDown() 删除 trace 目录(除非 TRACETOOLS_TEST_DEBUG 非空)

8.2 test_tracetools 用法示例

1
2
3
4
5
6
7
8
9
class TestPublisher(TraceTestCase):
def __init__(self, *args):
super().__init__(
*args,
session_name_prefix='session-test-publisher',
events_ros=[tp.rcl_publisher_init, tp.rmw_publish, ...],
package='test_tracetools',
nodes=['test_publisher'],
)

覆盖:publisher、subscription、service、timer、executor、lifecycle、intra-process 等场景。


9. 构建与部署

9.1 依赖安装(Ubuntu)

1
2
3
4
sudo apt install lttng-tools liblttng-ust-dev python3-babeltrace python3-lttng
# 可选内核追踪:
sudo apt install lttng-modules-dkms
sudo groupadd -r tracing && sudo usermod -aG tracing $USER

9.2 从源码启用 tracing

若先装了 ROS 二进制再装 LTTng,需重编至少到 tracetools

1
2
3
colcon build --packages-up-to tracetools --cmake-force-configure
source install/setup.bash
ros2 run tracetools status

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):

  1. package.xml 添加 depend tracetools
  2. #include "tracetools/tracetools.h"
  3. 在合适位置调用已有 TRACEPOINT(...)
  4. tp_call.h + tracetools.h + tracetools.c 增加新 event(需改 tracetools 包并 release)
  5. tracepoints.py / DEFAULT_EVENTS_ROS 注册 LTTng 名
  6. tracetools_test.TraceTestCase 验证

用户态 generic tracepoint 可直接使用 LTTng lttng_ust_tracepoint API,不必经过 tracetools 宏。


14. 调试建议

  1. 确认编译启用ros2 run tracetools status
  2. 确认 session 在跑lttng list
  3. 无 event:检查 enable 的 event 名是否为 ros2:*;节点是否用带 tracing 的 overlay 构建
  4. 空 trace 目录:session 未 start、或进程 domain 与 session 不匹配
  5. 符号 UNKNOWN:检查 -rdynamic、回调是否为 lambda 且无 target<>
  6. 读 trace 失败:安装 python3-babeltrace,路径是否为 session 根目录
  7. 内核 event 失败:用户是否在 tracing 组、是否加载 lttng-modules

15. 推荐阅读顺序

  1. 仓库 README.md — 构建、CLI、launch 快速上手
  2. doc/design_ros_2.md — tracepoint 语义与分层表
  3. tracetools/include/tracetools/tracetools.h — 全部 API
  4. tracetools/include/tracetools/tp_call.h — CTF 字段定义
  5. tracetools/src/tracetools.c — 宏到 LTTng 的桥接
  6. tracetools_trace/tools/lttng_impl.py — session 创建细节
  7. tracetools_launch/action.py — Launch 生命周期 + LD_PRELOAD
  8. tracetools_test/case.py — 如何写 trace 单测
  9. test_tracetools/test/test_publisher.py — 字段断言示例
  10. 核心栈插桩点rclcpp/executor.cpp, rmw_fastrtps/rmw_publish.cpp

16. 小结

ros2_tracing 将 ROS 2 运行时行为映射为 LTTng CTF 轨迹,形成「插桩 → 会话 → 存储 → 读取/分析」完整链路:

  • tracetools:稳定 C API + LTTng provider ros2,被 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 数据。

文章互动

阅读 --

留言

0 条留言

正在加载留言…