Date: November 25, 2002
Here's a quick and easy method for displaying a system's performance from a PC browser. The following chart illustrates CPU performance, but you can display any data collected by "sar" command: disk usage, run queues, paging, etc.
The procedure to set this up is as follows:
# On my system, it look like this
cp sarplot.cgi /usr/HTTPServer/cgi-bin
chmod a+x /usr/HTTPServer/cgi-bin/sarplot.cgi
# On my system, it looks like
cp sarplot.htm /usr/HTTPServer/htdocs
chmod a+r /usr/HTTPServer/htdocs/sarplot.htm
<html> <head><h2>Performance Measures:</h2></head> <body> <FORM ACTION="cgi-bin/sarplot.cgi" METHOD="POST"> <TABLE WIDTH=500 BORDER=0 CELLSPACING=0 CELLPADDING=5 BGCOLOR="#BBBBBB"> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="u" CHECKED> </TD> <TD> cpu usage </TD> </TR> <TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="d" CHECKED> </TD> <TD> disk usage </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="b"> </TD> <TD> buffer activity </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="y"> </TD> <TD> TTY device activity </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="c"> </TD> <TD> system calls </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="w"> </TD> <TD> swapping and switching </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="a"> </TD> <TD> file access statistics </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="q"> </TD> <TD> run queue statistics </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="v"> </TD> <TD> process, inode and file tables </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="m"> </TD> <TD> message and semaphore activity </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="p"> </TD> <TD> paging (-p) </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="g"> </TD> <TD> paging (-g) </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="r"> </TD> <TD> unused memory pages and disk blocks </TD> </TR> <TR> <TD ALIGN=CENTER> <INPUT TYPE="RADIO" NAME="opt" VALUE="k"> </TD> <TD> kernel memory allocation </TD> </TR> <TR> <TD> <INPUT TYPE="SUBMIT" VALUE="GRAPH IT!"> </TD> <TD> After making your selection, click the button </TD> </TR> </TABLE> </body>
#!/usr/bin/perl
# sarplot.cgi, shs 11/14/02, plot sar data
# modified by Bruce Sepncer, 11/25/02
# added section for disk usage
# changed tif to gif
# added yrange 0 to 100 for CPU, Disk and run queues
####################### Your Customizations go here #############
# Location of the gnuplot command
my $gnuplot = "/usr/local/bin/gnuplot";
####################### End of Your Customizations ##############
# ---------------------------------------------------------- modules
use IPC::Open3;
use CGI qw(:standard);
# ------------------------------------------------------- parameters
$opt=param('opt');
if ( ! $opt =~ /\w/ ) { # replace if not single letter
$opt="u";
}
# Set YRange on plot
# Found that gnuplot didn't do it properly
if ( $opt =~ /u|d|q/ ) {
$YRANGE = "[ 0 to 100 ]";
} else {
$YRANGE = "[ 0 to 1000 ]";
}
$dt=`date`; # save date for title
chomp($dt);
@sarstats=`sar -$opt`; # capture data from sar
$data="/tmp/stats$$"; # identify temp file
# ----------------------------------------------- process sar output
open DATA, ">$data" or die "Cannot open $data for writing";
foreach $line (@sarstats) {
if ( $line =~ /Average/ ) {
last;
} elsif ( $line =~ /^$/ ) {
next; # skip blank lines
} elsif ( $opt eq "d" ) {
if ( $line=~/^\d+:\d+:\d+.+hdisk/ ) { # first line in reading
@cols=split(/\s+/, $line);
$disk_line= $cols[0] . " " . $cols[3];
}
elsif ( $line =~ /hdisk/ ) {
@cols=split(/\s+/, $line);
$disk_line .= " " . $cols[2];
}
elsif ( $line =~ /cd/ ) {
print DATA ("$disk_line \n");
}
} elsif ( $line=~/\d+:\d+:\d+.+[a-z]/ ) { # capture column headings
@hdgs=split ' ',$line; # store in array for later use
} else {
print DATA "$line";
}
}
close DATA;
# Because the "sar -d" provides multi lines, must read headings differently
#
if ( $opt eq "d" ) {
@hdgs="";
foreach $line (@sarstats) {
if ( $line =~ /cd/ ) { last; }
if ( $line =~ /hdisk\d+/ ) {
@hdgs= (@hdgs, $&);
}
} # end for each
} # end if
$sz=$#hdgs; # number of data columns
# ------------------------------------------------------ run gnuplot
$| = 1; # disable buffering
my $pid = open3(\*GNUPLOT, \*GRAPHDATA, \*ERROR, $gnuplot);
# send commands to gnuplot
print GNUPLOT << "END";
set term gif color
set title "$dt (sar -$opt)";
set timefmt "%H:%M"
set xdata time
set format x "%H:%M"
set xtics border rotate
set xrange ["00:00" to "23:59"]
set yrange $YRANGE
END
# send command line for each data column
print GNUPLOT "plot ";
for ($x=2; $x<=$sz; $x++) {
$h=$x-1;
print GNUPLOT "'$data' using 1:$x t '$hdgs[$h]' with line,";
}
# last line is separate because is has no continuation character
print GNUPLOT "'$data' using 1:$x t '$hdgs[$x-1]' with line";
close(GNUPLOT);
# identify data type
print header("image/gif");
# send the image back to the browser
while ($length = sysread(GRAPHDATA,$content,1024)) {
syswrite(STDOUT,$content,$length);
}
close(GRAPHDATA);
`/usr/bin/rm $data`;
Bruce Spencer,
baspence@us.ibm.com