gpt4 book ai didi

c++ - 是什么导致无法在 DWARF perf 调用堆栈中展开?

转载 作者:行者123 更新时间:2023-12-04 11:56:36 27 4
gpt4 key购买 nike

perf record --call-graph dwarf 生成的回溯中由 perf script 打印,我一直在为大约 5% 的调用堆栈获取错误的地址,即展开失败。一个例子是

my_bin 770395 705462.825887:    3560360 cycles: 
7f0398b9b7e2 __vsnprintf_internal+0x12 (/usr/lib/x86_64-linux-gnu/libc-2.32.so)
7ffcdb6fbfdf [unknown] ([stack])

my_bin 770395 705462.827040: 3447195 cycles:
7f0398ba1624 __GI__IO_default_xsputn+0x104 (inlined)
7ffcdb6fb7af [unknown] ([stack])
它是从这个代码产生的(用 g++ -O3 -g -fno-omit-frame-pointer my_bin.cpp -o my_bin 编译):
#include <cstdio>
#include <iostream>

int __attribute__ ((noinline)) libc_string(int x) {
char buf[64] = {0};
// Some nonsense workload using libc
int res = 0;
for (int i = 0; i < x; ++i) {
res += snprintf(buf, 64, "%d %d %d Can I bring my friends to tea?", (i%10), (i%3)*10, i+2);
res = res % 128;
}
return res;
}

int main() {
int result = libc_string(20000000);
std::cout << result << "\n";
}
我很确定我的程序在堆栈中不应该有可执行代码,所以这些地址似乎是错误的。它不仅是一个程序,而且我分析过的大多数程序都有大约 5% 的错误调用堆栈。这些调用堆栈大多只有两个堆栈帧,最里面的一个有时在像 Eigen 这样的库中(即使它们通常具有正确的调用堆栈),有时在 C++ STL 或 libc 中。我已经看到平仓结束于 unknown , [stack] , [heap] , anon , //anon , libstdc++.so.6.0.28 , 或 <my_bin> .
我在 Ubuntu 18.04、20.04 和 20.10 上看到过这个。
这只发生在 DWARF 展开时。如何解决这个问题?

最佳答案

您测试了哪些其他类型的展开?
在示例中我 disabled kernel ASLR featuresetarch x86_64 -R更稳定的地址和更小的 perf.data 文件。perf record的用法选项 -e cycles:u命令可能会有所帮助,因为它不包含内核示例。
我为 __GI__IO_default_xsputn (inlined) 使用默认性能记录事件('-e 周期:u';使用了来自 libc6-prof package 的 libc-2.31)生成的文件重现了类似的矮人展开问题。功能:

env LD_LIBRARY_PATH=/lib/libc6-prof/x86_64-linux-gnu setarch `uname -m` -R perf record --call-graph dwarf -o perf.data.dwarf.u -e cycles:u ./my_bin
perf script -i perf.data.dwarf.u |less
错误样本:
my_bin 28100 760107.271010:     461418 cycles:u: 
7ffff7c74f06 __GI__IO_default_xsputn+0x106 (inlined)
7ffff7c59c6c __vfprintf_internal+0xf4c (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
正确样本:
my_bin 28100 760107.257283:     267268 cycles:u: 
7ffff7c74eff __GI__IO_default_xsputn+0xff (inlined)
7ffff7c59c6c __vfprintf_internal+0xf4c (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
7ffff7c6e9f6 __vsnprintf_internal+0xb6 (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
7ffff7d14a2c ___snprintf_chk+0x9c (inlined)
555555555314 libc_string+0xb4 (/home/user/so/my_bin)
555555555314 libc_string+0xb4 (/home/user/so/my_bin)
555555555111 main+0x11 (/home/user/so/my_bin)
7ffff7c040fa __libc_start_main+0x10a (/usr/lib/libc6-prof/x86_64-linux-gnu/libc-2.31.so)
55555555519d _start+0x2d (/home/user/so/my_bin)
为了正确展开,我在 __GI__IO_default_xsputn+ 中有许多不同的偏移量(+后的数字):
perf script -i perf.data.dwarf.u ||grep vsnprintf_internal -B3 |grep _GI__IO_default_xsputn|cut -d + -f 2|sort | uniq -c
...
208 0x0 (inlined)
45 0x101 (inlined)
2 0x105 (inlined)
91 0x10 (inlined)
294 0x110 (inlined)
2 0x117 (inlined)
2 0x11d (inlined)
326 0x121 (inlined)
但是我没有正确展开的 +0x106 地址。并且所有不正确的展开都有 +0x106 地址。让我们检查一下 gdb(禁用 ASLR 后更容易;+262 是 +0x106):
env LD_LIBRARY_PATH=/lib/libc6-prof/x86_64-linux-gnu setarch `uname -m` -R  gdb -q ./my_bin
(gdb) start
(gdb) x/i 0x7ffff7c74f06
0x7ffff7c74f06 <__GI__IO_default_xsputn+262>: retq
(gdb) disassemble __GI__IO_default_xsputn
Dump of assembler code for function __GI__IO_default_xsputn:
...
0x00007ffff7c74f05 <+261>: pop %rbp
0x00007ffff7c74f06 <+262>: retq
展开问题似乎与在 retq 处采样的内联(?)函数有关指令或之后 pop %rbp ?

关于c++ - 是什么导致无法在 DWARF perf 调用堆栈中展开?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68036746/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com