引
在某个服务收集性能数据的过程中,我们发现了一个不符合预期的火焰图生成情况,出现了不应该出现的调用栈,这是怎么回事呢?
错误的火焰图
在某个服务收集完火焰图之后,我们发现出现了不符合预期的调用栈,如图所示:
对于一个c++
程序,一般执行调用栈都是基于libc_start_main
启动的,但是右边这个却是直接就到了recursiveFunction
,这是为什么呢?
c++启动的时候并不是直接进入main函数,如需了解详情可自行了解。
问题复现
为了简化问题,我们编写了一个测试代码:
代码仓库:https://github.com/AshinZ/perf-workshop
通过如下的方式进行编译和数据收集:
调用栈深度
在遇到这样的火焰图以后,我们首先去查看了一下perf script
的原数据,发现原数据中的调用栈也没有从libc_start_main
开始,因此我们首先怀疑是不是perf script
解析数据的问题。通过perf script --help
查看帮助发现:
我们尝试用如下命令解析原数据:
发现解析出来的数据仍然是有不正常的调用栈,因此排除perf script
问题。那么就可能是perf record
收集数据的问题。
我们查看perf record --help
:
至此,我们尝试用新方式进行收集:
当使用--call-graph fp,32
这种方式收集的时候,在一些版本上会没有这个选项,因此我们可以基于帮助文档中fp
模式默认值是kernel.perf_event_max_stack
的信息,查看相关值并进行修改:
然后再使用fp
模式收集:
查看火焰图,就发现数据准确了:
总结
本文主要基于一个例子介绍了在用perf
收集数据时候针对调用栈过深的处理方案:
perf record
的时候通过--callgraph fp,256
或者--call-graph dwarf,256
选项手动提高栈深;perf record
的时候通过sysctl
设置kernel.perf_event_max_stack
提高栈深;perf script
时候通过-max-stack
提高解栈深度;
然而,perf
具体是如何通过参数控制这些的呢?我们下篇文章具体讲解。