Friday, January 25, 2008

Linux Perl Script To Graph Out Paging, Memory and CPU

Hey there,

Yesterday's post has finally arrived. I've converted as much as I could from our previous posts into this one comprehensive script for RedHat Linux. I'm not going to overstuff this post with pictures, since the results you'll get here will look exactly like the ones in our previous posts for CPU, Paging and Memory graphing, except our Perl script today will create all 3 at once!

You may notice that the disk buffer reads and writes Graph has not been included here. This is on purpose and due to the fact that I couldn't find much more than opinion about what constituted the equivalent of Solaris cache reads/writes on Linux. The native sar didn't produce the exact same type of statistics, so I didn't want to throw out some garbage just for the sake of filling the page. As we look into this further, it seems that an entire post on how to determine and track Linux's buffer cache would be helpful, informative and quite lengthy all on it's own. I look forward to scripting that out in the near future :)

Today's script was put through its paces on a machine running RedHat AS2.1 (Pensacola) with sar from the sysstat RPM version 5.0.5-12.21as. I mention these specifics because its been my experience, in the past (when RedHat was free) that the column order would occasionally change when the sysstat RPM was updated. With that in mind, I've commented this script with the header notation for the column that I'm grabbing at each point in the script. This way, if it changes for you, all you'll need to do is change the array number to the one matching the data column we're graphing to keep this script pertinent.

These column notation comments (and all the other lines that varied enough from the Solaris script to necessitate changing) are noted in the script with:

# <-----

Again, this script can be run at any time, simply by calling it, since it interprets the sar data and creates the GIF Graphs when you run it, like so:

./linuxcpupagememgraph.pl <--- Worst script name ever? ;)

Over the weekend, we'll post on using these sorts of scripts in CGI and the security implications that go along with automating processes through the web browser (convenient, but sometimes dangerous!).

I hope you find this script helpful and flexible enough to use across however many different versions or flavors of Linux you run at your site.

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# linuxcpupagememgraph.pl
# Graph CPU, Paging and Memory
# statistics at will!
# Written specifically for Linux
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

&graphsarB; # sar -g on Solaris # <-----
&graphsarr;
&graphsaru;

sub graphsarB { # <-----
use GIFgraph::bars;
open(SARG, "/usr/bin/sar -B|"); # <-----
@sarg = <SARG>;
close(SARG);
$my_graph = new GIFgraph::bars(800,600);
$my_graph->set(
x_label => 'Time',
y1_label => 'Number',
y2_label => 'Number',
title => 'Paging Activity by Server - host',
two_axes => 1,
y_min_value => 0,
y1_max_value => 20,
y2_max_value => 20,
y_tick_number => 5,
long_ticks => 1,
x_ticks => 0,
legend_marker_width => 24,
line_width => 10,
bar_spacing => 0,
gifx => 800,
gify => 600,
transparent => 1,
dclrs => [ qw( red green blue black) ],
);
$my_graph->set_legend( qw( Pages_Paged_Out Minor_Page_Faults-Buffer_Access Major_Page_Faults ) ); # <-----
$a = $b = $c = $d = 0;
foreach $line (@sarg) {
next if ( ($line !~ /:/) || ($line =~ /\//));
@line=split(" ", $line);
if ( ( $a % 12 ) != 0 ) {
$pandata0[$a] = undef;
} else {
$line[0] =~ s/:00$//;
$pandata0[$a] = "$line[0] $line[1]"; # <-----
}
if ( $line[3] == 0 ) { # <-----
$pandata1[$b] = 0;
} else {
$pandata1[$b] = $line[3]; # <----- pgpgout/s
}
if ( $line[3] == 0 ) { # <-----
$pandata2[$c] = 0;
} else {
$pandata2[$c] = $line[4]; # <----- fault/s
}
if ( $line[3] == 0 ) { # <-----
$pandata3[$d] = 0;
} else {
$pandata3[$d] = $line[5]; # <----- majflt/s
}
$a++;
$b++;
$c++;
$d++;
}
if ( ! $c ) {
@pandata0[0] = `date "+%H:%M"`;
@pandata1[0] = 0;
@pandata2[0] = 0;
@pandata3[0] = 0;
}
@data = (\@pandata0, \@pandata1, \@pandata2, \@pandata3);
$my_graph->plot_to_gif( "/your/data/dir/lsarB.gif", \@data ); # <-----
}

sub graphsarr {
use GIFgraph::lines;
open(SARR, "/usr/bin/sar -r|"); # <-----
@sarr = <SARR>;
close(SARR);
$my_graph = new GIFgraph::lines(800,600);
$my_graph->set(
x_label => 'Time',
y1_label => 'MegaBytes',
y2_label => 'MegaBytes',
title => 'Free Memory By Server - host',
y_min_value => 0,
y_tick_number => 5,
long_ticks => 1,
x_ticks => 0,
legend_marker_width => 24,
line_width => 10,
bar_spacing => 0,
gifx => 800,
gify => 600,
transparent => 1,
dclrs => [ qw( red green blue ) ],
);
$my_graph->set_legend( qw( Real_Memory_Available Swap_Memory_Available ) ); # <-----
$a = $b = $c = 0;
foreach $line (@sarr) {
next if ( ($line !~ /:/) || ($line =~ /\//));
@line=split(" ", $line);
if ( ( $a % 12 ) != 0 ) {
$pandata0[$a] = undef;
} else {
$line[0] =~ s/:00$//;
$pandata0[$a] = "$line[0] $line[1]"; # <-----
}
$pandata1[$b] = ($line[2]*8)/1000; # <----- kbmemfree
$pandata2[$c] = ($line[7]/2)/1000; # <----- kbswpfree
$a++;
$b++;
$c++;
}
if ( ! $c ) {
@pandata0[0] = `date "+%H:%M"`;
@pandata1[1] = 0;
@pandata2[2] = 0;
}
@data = (\@pandata0, \@pandata1, \@pandata2);
$my_graph->plot_to_gif( "/your/data/dir/lsarr.gif", \@data ); # <-----
}

sub graphsaru {
use GIFgraph::lines;
open(SARU, "/usr/bin/sar -u|"); # <-----
@saru = <SARU>;
close(SARU);
$my_graph = new GIFgraph::lines(800,600);
$my_graph->set(
x_label => 'Time',
y1_label => 'Percentage',
y2_label => 'Percentage',
title => 'CPU Usage By Server - host',
y1_max_value => 100,
y2_max_value => 100,
y_min_value => 0,
y_tick_number => 5,
long_ticks => 1,
x_ticks => 0,
legend_marker_width => 24,
line_width => 10,
bar_spacing => 0,
gifx => 800,
gify => 600,
transparent => 1,
dclrs => [ qw( red green ) ],
);
$my_graph->set_legend( qw( CPU_Utilization ) );
$a = $b = 0;
foreach $line (@saru) {
next if ( ($line !~ /:/) || ($line =~ /\//));
@line=split(" ", $line);
if ( ( $a % 12 ) != 0 ) {
$pandata0[$a] = undef;
} else {
$line[0] =~ s/:00$//;
$pandata0[$a] = "$line[0] $line[1]"; # <-----
}
$pandata1[$b] = 100-$line[7]; # <----- %idle
$a++;
$b++;
}
if ( ! $c ) {
@pandata0[0] = `date "+%H:%M"`;
@pandata1[1] = 0;
}
@data = (\@pandata0, \@pandata1);
$my_graph->plot_to_gif( "/your/data/dir/lsaru.gif", \@data ); # <-----
}


, Mike