专栏名称: Linux内核之旅
Linux内核之旅
目录
相关文章推荐
Linux内核之旅  ·  eBPF 治理 NFS 存储实践-4 ·  4 天前  
Linux内核之旅  ·  公平CFS调度类:SCHED_NORMAL、 ... ·  2 周前  
Linux内核之旅  ·  公平调度类的延伸:EEVDF ·  1 周前  
Linux内核之旅  ·  调用栈过深导致的火焰图错误该如何解决 ·  5 天前  
51好读  ›  专栏  ›  Linux内核之旅

调用栈过深导致的火焰图错误该如何解决

Linux内核之旅  · 公众号  · linux  · 2025-01-04 19:33

正文

在某个服务收集性能数据的过程中,我们发现了一个不符合预期的火焰图生成情况,出现了不应该出现的调用栈,这是怎么回事呢?

错误的火焰图

在某个服务收集完火焰图之后,我们发现出现了不符合预期的调用栈,如图所示:

对于一个c++程序,一般执行调用栈都是基于libc_start_main启动的,但是右边这个却是直接就到了recursiveFunction,这是为什么呢?

c++启动的时候并不是直接进入main函数,如需了解详情可自行了解。

问题复现

为了简化问题,我们编写了一个测试代码:

main.cpp

代码仓库:https://github.com/AshinZ/perf-workshop

通过如下的方式进行编译和数据收集:

编译与收集数据

调用栈深度

在遇到这样的火焰图以后,我们首先去查看了一下perf script的原数据,发现原数据中的调用栈也没有从libc_start_main开始,因此我们首先怀疑是不是perf script解析数据的问题。通过perf script --help查看帮助发现:

perf script --max-stack

我们尝试用如下命令解析原数据:

perf script --max-stack 256

发现解析出来的数据仍然是有不正常的调用栈,因此排除perf script问题。那么就可能是perf record收集数据的问题。

我们查看perf record --help

perf record --help

至此,我们尝试用新方式进行收集:

dwarf格式收集

当使用--call-graph fp,32这种方式收集的时候,在一些版本上会没有这个选项,因此我们可以基于帮助文档中fp模式默认值是kernel.perf_event_max_stack的信息,查看相关值并进行修改:

sysctl修改

然后再使用fp模式收集:

fp模式收集

查看火焰图,就发现数据准确了:

准确的火焰图

总结

本文主要基于一个例子介绍了在用perf收集数据时候针对调用栈过深的处理方案:

  • perf record的时候通过--callgraph fp,256或者--call-graph dwarf,256选项手动提高栈深;
  • perf record的时候通过sysctl设置kernel.perf_event_max_stack提高栈深;
  • perf script时候通过-max-stack提高解栈深度;

然而,perf具体是如何通过参数控制这些的呢?我们下篇文章具体讲解。