如何列出系统调用中繁忙的进程?有没有办法通过命令找到它top
?我在手册页中找不到任何合适的选项。
答案1
进程的状态表明它正在做什么。主要流程状态有:
- S:睡眠,即在系统调用中并阻塞等待某事。如果该进程有事情要做,它就可以被唤醒。
- D:忙,等待硬件——不间断睡眠。该进程无法唤醒,它必须等待特定事件的发生。 (有时可以取消,但并非总是如此。)
- R:运行,即执行代码。这通常是应用程序代码(因此在用户模式下运行),但内核内部执行的一些计算也会将进程状态保留在 R 上。
内核内部执行的计算可以处于状态 R 或 D。我认为这取决于这些计算是否使用资源(例如代码是否持有锁)。我认为没有一种可移植的直接方法来区分 R-in-user-mode 和 R-in-kernel 模式,但也许 Linux 中的/proc
某个地方有一种方法。
Linux procps 中的顶级版本列出了进程状态。它似乎没有只列出状态 D 的进程的选项,但您可以使用 键i
或-i
命令行选项来隐藏自上次屏幕更新以来保持空闲的所有进程,这通常会留下不到一屏的进程。
如果您只想列出 PID,您可以过滤 的输出ps
。
ps -o state=,pid= | sed -n 's/^D //p'
在不执行大量 I/O 的系统上,大多数情况下,这将列出零个进程。
答案2
这不是 100% 完美的答案,但它可以给你一种味道。如果您有某个进程始终处于“R”状态 - 您可以开始监视 procfs 中的两个字段:
$ awk '{print $14, $15}' /proc/$$/stat
你会看到类似:0 3915
第一个数字显示“此进程在用户模式下调度的时间量(以时钟滴答为单位)”,第二个数字显示“此进程在内核模式下调度的时间量(以时钟滴答为单位测量)”。 (请查看 man proc 了解详细信息)。
然而,关键是如果 3915 增长得很快而 0 没有增长,则意味着该进程现在正在内核模式下运行。 3915 增长得越快,我们就越能确定该进程正在 kerhel 模式下运行。
一个例子:
$ sudo dd if=/dev/nvme0n1p2 of=/dev/null bs=30M count=1000
$ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
16691 root 20 0 45352 32712 2112 R 50,5 0,2 0:06.00 dd
$ awk '{print $14, $15}' /proc/16691/stat
0 467
$ awk '{print $14, $15}' /proc/16691/stat
0 512
$ awk '{print $14, $15}' /proc/16691/stat
0 557
$ awk '{print $14, $15}' /proc/16691/stat
0 594
$ awk '{print $14, $15}' /proc/16691/stat
0 630
$ awk '{print $14, $15}' /proc/16691/stat
0 666
$ awk '{print $14, $15}' /proc/16691/stat
0 699
所以我们可以说 - 是的,该进程正在内核模式下运行。
至于“D”状态:
至于“D”状态(如果我错了,请纠正我)-这意味着进程处于“睡眠”状态。它是“不间断睡眠”状态,无论如何它是睡眠状态,这意味着进程(用户空间)的代码或通过系统调用调用的内核代码不会在CPU上调度,直到一些必要的数据\结构可用。所以我认为处于“D”状态的进程应该被排除在审查之外。为什么?因为它们根本不在CPU上执行。然而,有一个微妙的时刻。该进程可以在“D”和“R”状态之间快速切换,因此我们可以认为该进程处于“D”状态,但它有时会进入“R”状态。
让我详细解释一下: 人们经常说,如果一个进程处于“D”状态,则意味着它等待一些 I\O。事实并非如此。
C 中的简单程序。
$ cat 30.c
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = vfork();
if (pid == 0) {
sleep(180);
return 0;
}
printf("parent: I am exiting\n");
return(0);
}
编译。
$ gcc -o 30.exe 30.c
发射。
$ ./30.exe
它使用 vfork 创建子进程。父进程将被阻塞,直到子进程退出。父进程的状态也将为“D”。
$ ps aux | grep 30.exe
vasya 6495 0.0 0.0 10700 964 pts/66 D+ 03:30 0:00 ./30.exe
vasya 6496 0.0 0.0 10700 964 pts/66 S+ 03:30 0:00 ./30.exe
因此父进程不执行任何 i\o 操作,但具有“D”状态。
接下来 - 让我们看看带有“D”的进程是否使用 cpu。那么让我们检查一下它是否真的睡着了。
$ while true; do cat /proc/6495/stat | awk '{print $3, $14, $15}'; done
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
D 0 0
正如我们所看到的那样。
下一个。我们经常可以看到进程处于“D”状态,但“top”表明它消耗 CPU。这怎么可能?快速回答 - 该过程在“D”和“R”状态之间切换。它可能发生得很快。请记住“top”从 procfs 读取所有信息。默认情况下,“top”每 3 秒刷新一次所有数据,因此如果进程经常切换到“D”状态而不是经常切换到“R”状态,那么在我们看来,进程始终处于“D”状态。然而,这是错误的假设。
下一个要点是过程的状态是瞬时的属性。也就是说,当我们谈论进程处于“D”状态时,我们的意思是它在这个特定时间处于这种状态。然而,当我们谈论 CPU 消耗时,它与瞬时时间的属性无关。它是一段时间内的平均值。请看一下图片:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
13416 vasya 20 0 24024 5308 2132 D 62,9 0,0 0:05.02 dd
我们看到状态 = 'D' %CPU = 62,9
这意味着此时(现在)状态 = 'D' 这意味着现在进程不消耗 cpu 周期,但是在该进程之前一段时间不处于 'D' 状态并且正在消耗 cpu 周期。因此,为了简单起见,“top”计算最后三秒的平均值。它可以是这样的:
Now - 0%
1 sec ago - 62,9%
2 sec ago - 62,9%
3 sec ago - 62,9%
the average = (62,9%+62,9%+62,9%+0%)/(1+1+1) = 62,9%
这就是为什么“top”显示 62.9% 的 cpu 使用率,尽管进程的状态是“D”。
为了证明 'dd' 在 'D' 和 'R' 状态之间切换:
$ while true; do cat /proc/13416/stat | awk '{print $3, $14, $15}'; done
R 0 745
R 0 745
D 0 746
D 0 746
D 0 746
D 0 746
D 0 746
D 0 746
R 0 746
R 0 746
R 0 746
R 0 747
R 0 747
R 0 747
R 0 748
D 0 748
D 0 748
D 0 748
D 0 748
R 0 748
R 0 748
R 0 749
D 0 749
R 0 749
R 0 749
D 0 750
D 0 750
D 0 750
D 0 750
D 0 750
D 0 750
R 0 750
R 0 751
R 0 751
R 0 752
R 0 752
R 0 752
D 0 752
D 0 752
D 0 752
D 0 752
D 0 752
R 0 753
R 0 753
D 0 753
D 0 753
D 0 753
D 0 753
R 0 754
R 0 754
R 0 755
R 0 755
D 0 756
D 0 756
关于$14和%15字段的含义: 至于“man proc”:
$14 = 该进程在用户模式下调度的时间量,以时钟周期为单位(除以 sysconf(_SC_CLK_TCK))。
$15 = 该进程在内核模式下调度的时间量,以时钟周期为单位(除以 sysconf(_SC_CLK_TCK))。
正如您所看到的,“dd”在“R”和“D”状态之间切换。这就是为什么平均 CPU 消耗不是 0%。
您还可以看到,虽然进程确实处于“D”状态,但无论是用户模式还是内核模式,它都不会消耗 cpu 周期。
最后的建议:如果您有一个进程并想知道它现在是否在用户空间或内核空间中运行 --> 开始监视
$ cat /proc/13416/stat | awk '{print $3, $14, $15}';
如果 $14 正在变化 - 表示该进程位于用户空间,如果 %15 正在变化 - 表示该进程位于内核空间
希望能帮助到你
答案3
根据源代码,用 top 不可能做到这一点。
尽管如此,top 有一个-p
参数可以让你告诉它只监视某些 PID。不幸的是,这个参数也被限制为 20 个参数,并且内核很容易运行 20 个以上的进程。
我创建了一个两行脚本来测试:
kprocs=$(ls -l /proc/*/exe | grep -v " -> " | cut -d "/" -f 3)
top -c -p $(echo ${kprocs} | sed 's/ /,/g')
如果您徘徊,我将通过查看哪些链接未指向磁盘上的二进制文件来检测内核进程。