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