为什么 "xargs sudo perf top" 没有按预期工作?

Why doesn't "xargs sudo perf top" work as expected?

我想分析一个进程,所以首先获取它的 pid,然后使用“perf top”来检查它:

$ pgrep program
14472
$ sudo perf top -p 14472

它按预期工作:

然后我想用管道连接这两个命令,所以我用xargs:

$ pgrep program | sudo xargs perf top -p

但是这次“perf top”似乎不能正常工作: 我比较了这两个操作的过程:
(1) 运行 pgrepperf 分别为:

$ ps -ef | grep perf
root      18468  16827  0 09:34 pts/3    00:00:00 sudo perf top -p 14472
root      18469  18468 91 09:34 pts/3    00:00:06 perf top -p 14472
nanxiao   18477  18295  0 09:34 pts/4    00:00:00 grep --color=auto perf

(2) 使用xargs连接pgrepperf:

$ ps -ef | grep perf
nanxiao   18250  16827  0 09:32 pts/3    00:00:00 xargs sudo perf top -p
root      18251  18250  0 09:32 pts/3    00:00:00 sudo perf top -p 14472
root      18252  18251 87 09:32 pts/3    00:01:47 perf top -p 14472
nanxiao   18442  18295  0 09:34 pts/4    00:00:00 grep --color=auto perf

恕我直言,好像一样。任何人都可以提供一些线索吗?提前致谢!

P.S.,我的OS是CentOS 7.

更好的方法是在 pgrep 的输出上直接 运行 top,而不是通过管道 xargs。我相信 top 默认情况下命令不会通过标准输入读取信息

sudo perf top -p "$(pgrep program)"

这样 $(..) returns pgrep 命令的输出和返回值作为位置参数值传递给 -p 标志。

再次检查manual后,我发现-o选项可以解决这个问题:

-o, --open-tty Reopen stdin as /dev/tty in the child process before executing the command. This is useful if you want xargs to run an interactive application.

命令是这样的:

$ pgrep program | sudo xargs -o perf top -p

但不幸的是,CentOS 7xargs有点老了,没有提供这个选项。

根本原因是:没有-o选项,perf程序的stdin/dev/null:

$ sudo lsof -p 1495
......
perf    1495 root    0r      CHR    1,3       0t0     2052 /dev/null
......

并且 perf SLang_getkey() 中被阻止:

    ......
    FD_ZERO(&read_set);
    FD_SET(0, &read_set);

    if (delay_secs) {
        timeout.tv_sec = delay_secs;
        timeout.tv_usec = 0;
    }

    err = select(1, &read_set, NULL, NULL, ptimeout);

    if (err == 0)
        return K_TIMER;

    if (err == -1) {
        if (errno == EINTR)
            return K_RESIZE;
        return K_ERROR;
    }

    key = SLang_getkey();
    if (key != K_ESC)
        return key;
    ......

读取 /dev/null 将 return EOF,然后 select() 将 return 1.

使用 -o 选项 perf 程序的 stdin/dev/tty:

$ sudo lsof -p 1394
......
perf    1394 root    0u      CHR 136,25       0t0       28 /dev/pts/25
......

在上面的代码中,select() 将 return 0,并且整个函数将相应地 return。