如何在 Docker 容器内的 linux perf 工具中使用调试符号?
How do you get debugging symbols working in linux perf tool inside Docker containers?
我正在使用基于 "ubuntu" 标签的 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
这没有符号,即使可执行文件有符号信息。
在容器外执行相同的一般步骤工作正常,并显示如下内容:
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
标志的容器和带有--symfs /host
标志的容器中的运行宁perf report
修复它:
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 不会尝试重新映射路径。
另一种选择是 运行 性能主机端,如 sudo perf record -a docker run -ti <container name>
。但是这里的集合必须是系统范围的(-a
标志),因为容器是由 docker 守护进程生成的,它不在 docker 客户端工具的进程层次结构中,我们 运行 这里。
另一种不需要更改 运行 容器方式的方法(因此您可以分析一个已经 运行ning 的进程)是使用 bindfs 在主机上挂载容器的根目录:
bindfs /proc/$(docker inspect --format {{.State.Pid}} $CONTAINER_ID)/root /foo
然后 运行 性能报告为 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
我正在使用基于 "ubuntu" 标签的 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
这没有符号,即使可执行文件有符号信息。
在容器外执行相同的一般步骤工作正常,并显示如下内容:
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
标志的容器和带有--symfs /host
标志的容器中的运行宁perf report
修复它:
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 不会尝试重新映射路径。
另一种选择是 运行 性能主机端,如 sudo perf record -a docker run -ti <container name>
。但是这里的集合必须是系统范围的(-a
标志),因为容器是由 docker 守护进程生成的,它不在 docker 客户端工具的进程层次结构中,我们 运行 这里。
另一种不需要更改 运行 容器方式的方法(因此您可以分析一个已经 运行ning 的进程)是使用 bindfs 在主机上挂载容器的根目录:
bindfs /proc/$(docker inspect --format {{.State.Pid}} $CONTAINER_ID)/root /foo
然后 运行 性能报告为 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