newspaint

Documenting Problems That Were Difficult To Find The Answer To

Monitoring Statistics for a Single Process in Linux

Some useful tools exist in Linux for monitoring a system. Both top and htop provide a quick view as to processor utilisation, memory utilisation.

But what if you need to know some more details about an individual process, such as user CPU vs system CPU usage?

The following Perl script reads from the /proc filesystem to get the stat file for the particular process and, when run with a delay, calculates the rate over time for particular parameters.

#!/usr/bin/perl -w

use Time::HiRes;

use strict;

my $pid = shift;
my $interval = ( shift || 0 );

if ( ! $pid ) {
  die( "Must provide process ID to monitor" );
}

# from "man proc" under "/proc/[pid]/stat"
my @vars = qw(
  pid comm state ppid pgrp session tty_nr tpgid flags minflt cminflt majflt
  cmajflt utime stime cutime cstime priority nice num_threads itrealvalue
  starttime vsize rss rlim startcode endcode startstack kstkesp kstkeip
  signal blocked sigignore sigcatch wchan nswap cnswap exit_signal
  processor rt_priority policy delayacct_blkio_ticks
);

my %prevdata = ();
my $last = Time::HiRes::time();
my $first = 1;
while ( 1 ) {
  my $now = ( $interval == 0 ) ? $last + 1 : Time::HiRes::time();
  if ( ! open( FIN, "</proc/$pid/stat" ) ) {
    die( "Cannot open stat for PID $pid: $!" );
  }
  my $line = <FIN>;
  close( FIN );

  my $period = $now - $last;
  $last = $now;
 
  my @values = split( /\s+/, $line );
  my %data = ();<span style="font-family:monospace;">
  for ( my $i = 0; $i < keys( @vars ); $i++ ) {
    $data{$vars[$i]} = $values[$i];
  }

  my %rates = ();
  foreach ( keys %data ) {
    next if ( $data{$_} !~ m{^(\d+(?:\.\d+)?)$} );
    $rates{$_} = ( $data{$_} - ($prevdata{$_} || 0) ) / $period;
  }

  if ( ( ! $first ) || ( $interval == 0 ) ) {
    printf( "user=%3d kernel=%3d RSS=%8d thds=%d\n", 
      int( $rates{utime} ),
      int( $rates{stime} ),
      $data{rss},
      $data{num_threads},
    );
  } else {
    $first = 0;
  }

  last if ( $interval == 0 );
  select( undef, undef, undef, $interval );
  %prevdata = %data;
}

The script can be used as follows:

user@host:~$ perl -w procstat.pl 3663 3
user=  0 kernel=  0 RSS=  158818 thds=34
user=  7 kernel=  0 RSS=  159014 thds=34
user=  7 kernel=  0 RSS=  158750 thds=34
user=  0 kernel=  0 RSS=  158750 thds=34
user=  1 kernel=  0 RSS=  158870 thds=34
user=  0 kernel=  0 RSS=  158870 thds=34
user=  1 kernel=  0 RSS=  159200 thds=34
user=  0 kernel=  0 RSS=  159200 thds=34
user=  0 kernel=  0 RSS=  158804 thds=34
user= 28 kernel=  1 RSS=  159751 thds=35
user=  7 kernel=  0 RSS=  160081 thds=35

Usage is: perl procstat.pl PID interval

Where interval is seconds.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: