skip to Main Content

I want to profile a process, so first get its pid, then use "perf top" to check it:

$ pgrep program
14472
$ sudo perf top -p 14472

It works as expected:

enter image description here

Then I want to use pipe to connect these two commands, so I use xargs:

$ pgrep program | sudo xargs perf top -p

But this time "perf top" seems not work normally:
enter image description here
I compared processes of these two operations:
(1) Run pgrep and perf separately:

$ 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) Use xargs to connect pgrep and perf:

$ 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

IMHO, it seems same. Anyone can give some clues? Thanks in advance!

P.S., my OS is CentOS 7.

2

Answers


  1. Chosen as BEST ANSWER

    After checking manual again, I find -o option can fix this issue:

    -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.

    The command is like this:

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

    But unfortunately, CentOS 7's xargs is a little old, and doesn't provide this option.

    The root cause is: without -o option, the stdin of perf program is /dev/null:

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

    And the perf is blocked in 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;
        ......
    

    Read of /dev/null will return EOF, then select() will return 1.

    With -o option the stdin of perf program is /dev/tty:

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

    In above code, the select() will return 0, and the whole function will return accordingly.


  2. A better approach would be to directly run the top on the output of pgrep instead of piping over xargs. I believe top command by default does not read information over standard input

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

    This way the $(..) returns the output of the pgrep command and the returned value is passed as a positional argument value to the -p flag.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search