我正在寻找学习哪个syscalls 或哪个子系统的方法,这些过程或线程花费时间等待,即被阻塞并且没有计划在CPU上运行。
特别是如果我有一些未知的过程,或者我们所知道的只是“很慢”的过程,我希望能够学习类似的东西:
sys_write()
上花费了80%的时间在/ some / file的fd 13上” 换句话说当我的程序不在CPU上运行时,它在做什么?
用perf
很难回答 ,因为它似乎无法记录从sys_enter到sys_exit的持续时间。否则,请跟踪事件的持续时间。大概是由于其采样性质。
我知道使用Brendan Gregg的off-cpu work进行的Linux 4.6及更高版本的eBPF的一些实验工作可能会有所帮助。但是在运行和支持4.6内核的悲惨世界中,这是一个难得的珍贵独角兽。
现实世界中有哪些选择?
ftrace,systemtap等在这里提供任何见解吗?
答案 0 :(得分:3)
您可以使用strace。首先,您可能需要对每种类型的系统调用的费用进行简要概述。您可以通过运行strace -c
获得此摘要。例如,可能的输出如下:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
90.07 0.000263 26 10 getdents
3.42 0.000010 0 1572 read
3.42 0.000010 0 762 1 stat
3.08 0.000009 0 1574 6 open
0.00 0.000000 0 11 write
0.00 0.000000 0 1569 close
0.00 0.000000 0 48 fstat
% time
值是相对于整个内核时间,而不是相对于整个执行时间(内核+用户)。此摘要告诉您最昂贵的系统调用是什么。但是,如果需要确定哪些特定的系统调用实例最昂贵,以及将哪些参数传递给它们,则可以运行strace -i -T
。 -i
选项显示执行系统调用的指令的指令地址,而-T
选项显示在系统调用中花费的时间。输出可能看起来像这样:
[00007f97f1b37367] open("myfile", O_RDONLY|O_CLOEXEC) = 3 <0.000020>
[00007f97f1b372f4] fstat(3, {st_mode=S_IFREG|0644, st_size=159776, ...}) = 0 <0.000018>
[00007f97f1b374ba] mmap(NULL, 159776, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f97f1d19000 <0.000019>
[00007f97f1b37467] close(3) = 0 <0.000018>
第一列显示指令地址,第二列显示带有参数的系统调用,第三列显示返回的值,最后一列显示在该系统调用中花费的时间。该列表是根据系统调用的动态发生而排序的。您可以使用grep
或-e
选项过滤此输出。指令地址可以帮助您找到这些系统调用在源代码中的位置。例如,如果一长串的系统调用具有相同的地址,则很有可能在包含系统调用的代码中的某个地方出现循环。如果可执行二进制文件不是PIE,则动态地址与objdump
所示的静态地址相同。但是即使使用PIE,动态地址的相对顺序也相同。我不知道是否有一种简单的方法可以将这些系统调用映射到源代码行。
如果要查找诸如“它花费了80%的时间在/ some / file的fd 13上的sys_write()中”的信息,则需要编写一个脚本,该脚本首先提取所有{{ 1}}调用和相应的文件名参数,然后总结open
参数等于某个值的所有sys_write
调用的时间。