我有几个进程占用了大量的系统 CPU 时间(通过查看 vmstat 确定)。有没有简单的方法可以找出正在进行的系统调用类型?
我知道有 strace,但是有没有更快捷更简单的方法?有没有类似“top”的系统调用?
答案1
我认为使用该-c
标志的 strace 可能是我所知道的最接近的方法。如果您尚未使用该-c
标志,请尝试以下操作:
$ sudo strace -c -p 12345
其中 12345 是相关进程的进程 ID (PID)。请注意,跟踪进程确实会增加额外的开销,因此在跟踪进程时,进程的运行速度会变慢。
运行该程序后,无论要收集数据多长时间,按Ctrl-C
停止数据收集并输出结果。它将产生如下结果:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
31.88 0.001738 145 12 futex
16.79 0.000915 11 80 tgkill
12.36 0.000674 34 20 read
9.76 0.000532 266 2 statfs
8.42 0.000459 13 35 time
4.38 0.000239 6 40 gettimeofday
3.65 0.000199 4 48 sigprocmask
2.94 0.000160 18 9 open
2.88 0.000157 12 13 stat64
1.32 0.000072 9 8 munmap
0.90 0.000049 6 8 mmap2
0.88 0.000048 3 14 7 sigreturn
0.79 0.000043 5 9 close
0.77 0.000042 4 10 rt_sigprocmask
0.64 0.000035 3 12 setitimer
0.55 0.000030 5 6 6 rt_sigsuspend
0.53 0.000029 4 8 fstat64
0.29 0.000016 8 2 setresuid32
0.13 0.000007 4 2 _llseek
0.09 0.000005 3 2 prctl
0.04 0.000002 2 1 geteuid32
------ ----------- ----------- --------- --------- ----------------
100.00 0.005451 341 13 total
如您所见,这是应用程序进行的所有系统调用的细分,按总时间排序,包括每次调用的平均时间和每个系统调用的调用次数。如果您想以不同的方式对它们进行排序,请参阅 strace 的手册页,因为那里有几个选项。
答案2
我倾向于使用的 strace 开关类型是这种。
strace -ffttT -p pid -o /tmp/strace.out
例如,
19:35:57.485493 mprotect(0x7f35e7472000, 16384, PROT_READ) = 0 <0.000037>
19:35:57.485599 mprotect(0x7f35e7692000, 4096, PROT_READ) = 0 <0.000030>
19:35:57.485697 mprotect(0x7f35e78b7000, 4096, PROT_READ) = 0 <0.000030>
19:35:57.485782 munmap(0x7f35e7896000, 129588) = 0 <0.000037>
19:35:57.485875 set_tid_address(0x7f35e78949d0) = 10730 <0.000029>
19:35:57.485960 set_robust_list(0x7f35e78949e0, 0x18) = 0 <0.000024>
19:35:57.486048 futex(0x7fff8f58628c, FUTEX_WAKE_PRIVATE, 1) = 0 <0.000025>
19:35:57.486131 futex(0x7fff8f58628c, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, 7f35e7894700) = -1 EAGAIN (Resource temporarily unavailable) <0.000024>
您可以在系统调用的右侧看到时间差,显示从一个系统调用到另一个系统调用花费了多少时间。
它会捕捉系统调用之间的时间差。因此,当您看到一个系统调用与下一个系统调用之间有相当多的秒数间隔时,就会产生一些噪音。
另一种方法是使用 gcore 进行 coredump。不过,这需要一点 gdb 操作经验。
但是,如果线程是内核线程,则无法对其进行 strace 或 coredump。在这种情况下,我们必须使用更复杂的东西。在 RHEL5 内核中,我们使用 oprofile。在 RHEL6 中,我们使用 perf。我更喜欢 perf 而不是 oprofile。Perf 数据可以以图形格式收集,显示使用 CPU 百分比最大的系统调用。
通过测试,我看到了这一点。
38.06% swapper [kernel.kallsyms] [k] mwait_idle_with_hints ↑
29.45% swapper [kernel.kallsyms] [k] read_hpet
4.90% swapper [kernel.kallsyms] [k] acpi_os_read_port ▒
4.74% swapper [kernel.kallsyms] [k] hpet_next_event
它显示了内核函数占用了 38% 的 CPU 时间。现在,我们可以检查该函数,看看它正在做什么以及它应该做什么。
通过几个例子,这并不那么难。
答案3
也许可以尝试其中一个采样分析器,例如 oprofile,或者对于较新的内核,可以使用 perf。如果幸运的话,“perf top”可能会准确地告诉您想要的内容。请参阅这里有一些例子