2016-08-12 266 views
3

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

这是我正在做的事情来证明问题。

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

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

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

做同样的一般步骤外容器正常工作,并显示是这样的:通过成为根和做 96.96% a.out a.out [.] function 0.35% a.out libc-2.19.so [.] [email protected]@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

在主机系统我已经打开内核符号: echo 0 > /proc/sys/kernel/kptr_restrict

如何让集装箱版本正常工作并显示调试符号?

回答

5

-v /:/host标志运行容器和容器与--symfs /host标志运行perf report修复它:

Samples: 4K of event 'cycles', Event count (approx.): 3420992473 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守护进程不在我们在此处运行的docker客户端工具的进程层次结构中。

+0

谢谢,就是这样。 要添加到解决方案,为了获得内核符号,您还需要添加: '--kallsyms =/proc/kallsyms'。 –

+1

万一它帮助其他人:更简单的方法是用'-v/var/lib/docker /:/ var/lib/docker'调用'docker run',这样'perf'不需要任何正确解析符号的特殊参数。 –

+0

啊,这是一个很好的。 –

1

,不需要改变运营容器的另一种方式(这样你就可以分析一个已经运行的进程)是安装容器的根上使用主机bindfs:

bindfs /proc/$(docker inspect --format {{.State.Pid}} $CONTAINER_ID)/root /foo

然后运行PERF报告作为perf report --symfs /foo

你必须运行perf record全系统,但你可以将其限制为只收集特定的容器事件:

perf record -g -a -F 100 -e cpu-clock -G docker/$(docker inspect --format {{.Id}} $CONTAINER_ID) sleep 90

相关问题