linux - 如何让调试符号在 Docker 容器内的 linux perf 工具中工作?

标签 linux docker linux-kernel perf

我正在使用基于“ubuntu”标签的 Docker 容器,无法获取 linux perf 工具来显示调试符号。

这是我为证明问题所做的工作。

首先我启动一个容器,这里有一个交互式外壳。

$ docker run -t -i ubuntu:14.04 /bin/bash

然后从容器提示中安装 linux perf 工具。

$ apt-get update
$ apt-get install -y linux-tools-common linux-tools-generic linux-tools-`uname -r`

我现在可以使用 perf 工具了。我的内核是 3.16.0-77-generic

现在我将安装 gcc,编译一个测试程序,并尝试在 perf record 下运行它。

$ apt-get install -y gcc

我把测试程序粘贴到test.c中:

#include <stdio.h>

int function(int i) {
    int j;
    for(j = 2; j <= i / 2; j++) {
        if (i % j == 0) {
            return 0;
        }
    }
    return 1;
}

int main() {
    int i;
    for(i = 2; i < 100000; i++) {
        if(function(i)) {
            printf("%d\n", i);
        }
    }
}

然后编译、运行、报告:

$ gcc -g -O0 test.c && perf record ./a.out && perf report

输出看起来像这样:

  72.38%  a.out  a.out              [.] 0x0000000000000544
   8.37%  a.out  a.out              [.] 0x000000000000055a
   8.30%  a.out  a.out              [.] 0x000000000000053d
   7.81%  a.out  a.out              [.] 0x0000000000000551
   0.40%  a.out  a.out              [.] 0x0000000000000540

这没有符号,即使可执行文件有符号信息。

在容器外执行相同的常规步骤可以正常工作,并显示如下内容:

96.96%  a.out  a.out             [.] function 
0.35%  a.out  libc-2.19.so       [.] _IO_file_xsputn@@GLIBC_2.2.5
0.14%  a.out  [kernel.kallsyms]  [k] update_curr
0.12%  a.out  [kernel.kallsyms]  [k] update_cfs_shares
0.11%  a.out  [kernel.kallsyms]  [k] _raw_spin_lock_irqsave                 

在主机系统中,我已经通过成为 root 并执行以下操作打开了内核符号:

$ echo 0 > /proc/sys/kernel/kptr_restrict 

如何让容器化版本正常工作并显示调试符号?

最佳答案

使用 -v /:/host 运行容器标记并运行perf report在带有 --symfs /host 的容器中标志修复它:

 96.59%  a.out  a.out              [.] function
  2.93%  a.out  [kernel.kallsyms]  [k] 0xffffffff8105144a
  0.13%  a.out  [nvidia]           [k] 0x00000000002eda57
  0.11%  a.out  libc-2.19.so       [.] vfprintf
  0.11%  a.out  libc-2.19.so       [.] 0x0000000000049980
  0.09%  a.out  a.out              [.] main
  0.02%  a.out  libc-2.19.so       [.] _IO_file_write
  0.02%  a.out  libc-2.19.so       [.] write

它不能按原样工作的部分原因是什么? perf script 的输出有点揭示了这一点:

...
           a.out    24 3374818.880960: cycles:  ffffffff81141140 __perf_event__output_id_sample ([kernel.kallsyms])
           a.out    24 3374818.881012: cycles:  ffffffff817319fd _raw_spin_lock_irqsave ([kernel.kallsyms])
           a.out    24 3374818.882217: cycles:  ffffffff8109aba3 ttwu_do_activate.constprop.75 ([kernel.kallsyms])
           a.out    24 3374818.884071: cycles:            40053d [unknown] (/var/lib/docker/aufs/diff/9bd2d4389cf7ad185405245b1f5c7d24d461bd565757880bfb4f970d3f4f7915/a.out)
           a.out    24 3374818.885329: cycles:            400544 [unknown] (/var/lib/docker/aufs/diff/9bd2d4389cf7ad185405245b1f5c7d24d461bd565757880bfb4f970d3f4f7915/a.out)
...

注意 /var/lib/docker/aufs小路。这是来自主机的,所以它不会存在于容器中,您需要帮助 perf report找到它。这可能是因为 mmap 事件由任何 cgroup 之外的 perf 跟踪,并且 perf 不会尝试重新映射路径。

另一种选择是在主机端运行 perf,例如 sudo perf record -a docker run -ti <container name> .但是这里的集合必须是系统范围的(-a 标志),因为容器是由 docker 守护进程生成的,它不在我们在此处运行的 docker 客户端工具的进程层次结构中。

关于linux - 如何让调试符号在 Docker 容器内的 linux perf 工具中工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38927895/

相关文章:

database - Postgres 不占用系统资源

linux - 如何设置虚拟磁盘的容量

Linux 音频录制和质量比较

php - 如何使PHP-FPM与FastCGI一起与Nginx-proxy一起使用?

docker - Traefik和Nginx在Docker上使用HTTPS/400错误请求

linux-kernel - pci_enable_device 和 pcim_enable_device 有什么区别?

linux - 软件陷阱与硬件陷阱

c - 如何在两个进程之间共享链表?

linux - 如何仅在 Docker 上下载 Git?

git - 只下载或克隆 git 中的一个分支,而不是整个树