从 perf 获取用户空间堆栈信息

Posted

技术标签:

【中文标题】从 perf 获取用户空间堆栈信息【英文标题】:Getting user-space stack information from perf 【发布时间】:2013-11-01 02:30:44 【问题描述】:

我目前正在尝试在我正在测试的 PostgreSQL 构建中追踪一些幻像 I/O。它是一个多进程服务器,将磁盘 I/O 关联回特定的后端和查询并不简单。

我认为 Linux 的 perf 工具非常适合这种情况,但我正在努力捕获块 I/O 性能计数器指标并将它们与用户空间活动相关联。

很容易记录块 I/O 请求和完成,例如:

sudo perf record -g -T -u postgres -e 'block:block_rq_*'

并且记录了用户空间 pid,但是没有捕获内核或用户空间堆栈,也没有能力快照用户空间进程堆的位(例如,查询文本)等。所以当你有 pid 时,你不知道那个过程当时在做什么。只需perf script 输出如下:

postgres  7462 [002] 301125.113632: block:block_rq_issue: 8,0 W 0 () 208078848 + 1024 [postgres]

如果我将-g 标志添加到perf record,它将拍摄内核 堆栈的快照,但不会捕获内核中捕获的性能事件的用户空间状态。用户空间堆栈仅从用户空间上升到入口点,如LWLockReleaseLWLockAcquirememcpy(mmap'd IO)、__GI___libc_write 等。

所以。有小费吗?能够捕获 user-space 堆栈的快照以响应 kernel 事件将是理想的选择。

我使用的是 Fedora 19,3.11.3-201.fc19.x86_64,薛定谔的猫,性能版本为 3.10.9-200.fc19.x86_64。

【问题讨论】:

回到这一点,另一种可能性可能是使用 frace / systemtap / uprobes / ... 代替。在 linux.conf.au 2014 上的一次演讲表明,此时 systemtap 可能更容易做到这一点。 【参考方案1】:

好的,看起来有几个部分:

我在 x86_64 上,大多数发行版默认使用 -fomit-frame-pointer 构建,而 perf 在没有帧指针的情况下无法跟随堆栈;

.... 除非它是支持libunwind 构建的较新版本,在这种情况下它支持perf record -g dwarf

见:

the patch adding libunwind support to Perf Debian bug 725075。 linux perf: how to interpret and find hotspots

我在 Fedora 18 上,但 the same issue applies。因此,如果您正在分析您正在处理的代码(可能在 Stack Overflow 上),请使用 -fno-omit-frame-pointer-ggdb 重新构建。

我开始重建 perf,因为我希望能够与库存 RPM 进行比较:

sudo yum build-dep perf sudo yum install yum-utils rpmdevtools libunwind-devel yumdownloader --source perf 或下载相应的kernel-.....src.rpm srpm rpmdev-setuptree rpm -Uvh kernel-*.src.rpm cd $HOME/rpmbuild/SPECS rpmbuild -bp --target=$(uname -m) kernel.spec

此时,您可以根据需要构建一个新的perf

cd $HOME/rpmbuild/BUILD/kernel-*/linux-*/tools/perf make

...我做了并测试了更新的perf 如果使用可用的 libunwind 构建,实际上确实捕获了一个有用的堆栈。

您也可以构建一个新的 rpm:

编辑 kernel.spec,取消注释行 %define buildid ...,将 buildid 更改为 .perfunwind。注意是%define 而不是% define

在同一个spec文件中,找到:

%global perf_make \
make %?_smp_mflags -C tools/perf -s V=1 WERROR=0 NO_LIBUNWIND=1 HAVE_CPLUS_DEMANGLE=1 NO_GTK2=1 NO_LIBNUMA=1 NO_STRLCPY=1 prefix=%_prefix

并删除NO_LIBUNWIND=1

rpmbuild -bb --without up --without mp --without pae --without debug --without doc --without headers --without debuginfo --without bootwrapper --without with_vdso_install --with perf kernel.spec 在不构建整个内核的情况下生成新的perf RPM。或者,如果您愿意,可以省略 --without 以获得所需的内核风格,在这种情况下,您还需要构建标头、调试信息等。

sudo rpm -Uvh $HOME/rpmbuild/RPMS/x86_64/perf-*.fc19.x86_64.rpm

见the fedora project guide on building a custom kernel。

我已经向 Fedora 报告了这个问题;他们不应该使用NO_LIBUNWIND=1。见bug 1025603。

一旦你重建了perf,你就可以使用perf record -g dwarf来获得完整的堆栈。

【讨论】:

@ErwinBrandstetter 您可能会喜欢后续博客文章:blog.2ndquadrant.com/tracing-postgresql-perf

以上是关于从 perf 获取用户空间堆栈信息的主要内容,如果未能解决你的问题,请参考以下文章

perf 如何采样内核堆栈?

perf 是不是锁定配置文件用户空间互斥锁?

如果通过strcpy()获取用户输入,用户输入是否会在空间或空字符之外复制到堆栈上

Linux内核——用户堆栈和内核堆栈

内核空间和内核堆栈之间的关系是什么?

折叠堆栈面板时从网格中删除空间