Opensplice DDS+Protobuf程序终止耗时5秒,求可定位问题的调试工具
可用分析工具及排查方案
初步排查工具
/usr/bin/time(注意不是shell内置的time命令):加-v参数执行程序,可输出总挂钟时长、用户态CPU耗时、内核态CPU耗时:
如果总挂钟时长远大于用户+内核CPU耗时,说明卡顿来自阻塞类操作(大概率是DDS线程join);如果CPU耗时占比极高,说明卡顿来自计算类操作(大概率是大量Protobuf对象析构),可先做初步分类。/usr/bin/time -v ./你的程序路径
函数级耗时/调用次数分析工具
1. perf(Linux原生首选)
不需要修改代码或重新编译,支持统计函数CPU占比、调用次数、挂钟阻塞时长,是最适合这类问题的工具:
- 全周期统计命令:
程序退出后执行perf record -g -e cpu-clock -e sched:sched_switch ./你的程序路径perf report即可看到所有函数的耗时占比、调用栈关系,还能筛选出退出阶段的函数:- 若看到Protobuf相关的
~Message()、Arena析构类函数占比极高,说明卡顿来自大量Protobuf对象的销毁 - 若看到
pthread_join、Opensplice内部的os_threadJoin类函数占比高,且伴随大量sched_switch阻塞事件,说明卡顿来自DDS后台线程的退出等待
- 若看到Protobuf相关的
2. ftrace(function_graph模式)
不需要修改程序,可完整追踪函数调用流程和每个函数的实际执行时长,包括内核态调用:
# 先安装trace-cmd工具 trace-cmd record -p function_graph -F ./你的程序路径 trace-cmd report
可以直接看到退出阶段从main返回后到进程终止的所有函数调用序列,以及每个调用的耗时,精准定位卡顿点。
3. GDB自带调试方案
如果不想用外部工具,可直接用GDB打时间戳断点排查:
- 在
main函数的return 0;行打第一个断点,命中后执行shell date +%s.%N记录起始时间 - 分别给Protobuf消息析构函数、Opensplice的线程join函数打断点,每命中一次就打印当前时间,即可算出每个步骤的耗时
- 也可以开启GDB的执行录制功能:命中断点后执行
record full,执行到进程退出后可反向回溯执行流程,统计每个函数的执行指令数占比。
针对性优化建议
- 如果确认是Opensplice线程join卡顿:检查你使用的Opensplice 6.7配置文件中的
ShutdownTimeout参数,旧版本默认值就是5秒,用于等待内部通信资源回收,可按需调小,或者在return 0之前手动调用DDS的delete_participant接口提前释放DDS核心资源,不要等全局析构阶段自动释放 - 如果确认是Protobuf析构卡顿:排查是否有大量未提前释放的Protobuf消息对象,尤其是用Arena分配的内存是否提前归还,可在return 0之前手动清空所有持有Protobuf对象的容器,提前触发析构。
内容的提问来源于stack exchange,提问作者Bobby Tables
相关产品推荐
相关产品推荐

