Striker has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am new to Perl. I am working on a web UI where I have to give CPU and memory monitoring data, so I am using top and gnuplot command. I am able to do it through my terminal. but when I am executing same commands with a perl script its not working. The problem I am having is that whenever I am executing top command in my terminal than I have to wait for few minutes and then I have to plot it using GNUPLOT but when I am doing the same work using system command in perl I am unable to give that delay.

Here is what I am doing

system "top -p 1758 -b -d5 | tee -a stats.log"; system "./top_stats.sh -f stats.log";

Here 1758 is the app ID whose top data I have to monitor and stats.log file is the one where I am saving logs and then using this stats.log file as input to top_stats.sh script I am plotting graphs. This top_stats.sh script takes the log file and uses gnuplot to plot data

Now the problem is whenever I am executing this first system command in terminal I have to wait for some time say 2 to 3 minutes to have ample number of data points and then I have to press Ctrl+C to come out of top command and then run the script. but here as soon as this first system command is encountered it is executed and then next command is executed without any delay so I am not getting any data points to plot the graph. Is there any way I can execute my first command and wait for 3 minutes without coming out of system command and then execute the next command.??

  • Comment on Running 'top' command (of linux) for few minutes and then come out of system command (of perl)
  • Download Code

Replies are listed 'Best First'.
Re: Running 'top' command (of linux) for few minutes and then come out of system command (of perl)
by kcott (Archbishop) on Mar 19, 2014 at 09:17 UTC

    G'day Striker,

    I have a different version of top (with different options) so I can't test this. However, looking at this top manpage (which appears to have the same options that you're using), I'd guess you can add a -n iterations to your top command; then put a sleep between the system statements.

    So, with a delay of 5 seconds, that would be 36 iterations in 3 minutes:

    system "top -p 1758 -b -d5 -n36 | tee -a stats.log"; sleep 180; system "./top_stats.sh -f stats.log";

    According to that manpage, top should stop running after the set number of iterations, so you won't need a Ctrl-C (or equivalent).

    -- Ken

      ++! Now that you mention it, I remember using -n for running top through 'n' iterations of page refresh. There's also the 'batch mode' for passing output from top to other programs. Here's what my copy of manpage has to say about this:
      -b : Batch mode operation
                  Starts  top  in 'Batch mode', which could be useful for sending output from top to other programs
                  or to a file.  In this mode, top will not accept input and runs until the iterations limit you've
                  set with the '-n' command-line option or until killed.
      
Re: Running 'top' command (of linux) for few minutes and then come out of system command (of perl)
by zentara (Cardinal) on Mar 19, 2014 at 11:13 UTC
    Here is the way I would do it, with IPC::Open3. If you add IO::Select into the mix, you can listen to multiple commands simultaneously ( shown in the second code block). Additionally, if you want a little graphic realtime, see linux memory leak monitor, where I do essentially what is shown below, but output it to a little Tk window in the bottom right corner of the screen.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; my $pid = $$; my $pid1 = open3(0, \*READ,0,"top -d 2 -b -p $pid "); #if \*ERROR is false, STDERR is sent to STDOUT while(1){ my @words = split(/\s+/,<READ>); $words[0] ||= 0; if($words[0] =~ /$pid/){print "$words[4] $words[9]\n"} #print "$words[0]\n"; } waitpid($pid, 1); # It is important to waitpid on your child process, # otherwise zombies could be created.
    And for multiple command reading, throw them into a select loop.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; use IO::Select; my $pid = $$; my $pid1 = open3(0, \*READ,\*ERROR,"top -d 1 -b -p $pid "); #if \*ERROR is false, STDERR is sent to STDOUT # add more commands here if you want, but make sure the # filehandles are different. It would be an improvement to use # IO::Handle for the filehandles my $sel = new IO::Select(); $sel->add(\*READ); $sel->add(\*ERROR); my($error,$answer)=('',''); while(1){ foreach my $h ($sel->can_read){ my $buf = ''; if ($h eq \*ERROR){ sysread(ERROR,$buf,4096); if($buf){print "ERROR-> $buf\n"} }else{ sysread(READ,$buf,4096); if($buf){print "$buf\n"} } } }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
Re: Running 'top' command (of linux) for few minutes and then come out of system command (of perl)
by robby_dobby (Hermit) on Mar 19, 2014 at 08:50 UTC
Re: Running 'top' command (of linux) for few minutes and then come out of system command (of perl)
by vinoth.ree (Monsignor) on Mar 19, 2014 at 09:05 UTC

    You can use IPC::Run's run method instead of system. and set a timeout.


    All is well