[Orca-dev] [PATCH] r528/data_gatherers/aix/orca-aix-stat.pl.in
David Michaels
dragon at raytheon.com
Thu Apr 6 17:49:52 PDT 2006
This is more like a rewrite / replacement than a patch. There have been
enough changes that the patch is 50% longer than the original file.
I've retooled the script quite a bit, and have distributed it personally
to some users who've requested it on orca-users. I suspect most AIX
Orca users are using my version of this script. I think even Rajesh is
using it.
I've attached a copy of the script and, for completeness, a copy of the
patch.
Here's a summary of some of the changes I've made since Rajesh first
distributed the script to Orca two years ago. The big rewrite in 2005
was not logged.
Patched by: Dave "Dragon" Michaels <dragon at raytheon.com>
* r528/data_gatherers/aix/orca-aix-stat.pl.in
2006-04-06 - Added ^L page markers
2006-04-05 - Modified how physical memory cap is identified
Now uses prtconf instead of lslpp mumbo jumbo
- corrected memory calculation
- added check to verify memory cap identification
If it didn't work, use a (bogus) default
- added conditional for uptime parsing - N days (only)
- shifted where some warnings are printed
2006-01-31 - Added command-line options for TSM stuff:
o specify TSM ID/password
o disable TSM collection, even if present
- TSM id/password now specified as a global variable
- fixed warning messages to appear prior
to corresponding header/data variable reset
- updated version to 1.8
- injected patterns for gnu-configure integration
(only OUT_ROOT cared)
2004-08-19 - Not yet ready for ./configure integration
- Change: Redesign of some sections to run 24x7 using kernel
counters instead of script cycles to compute
needed values quickly every 5 minutes
- Change: Duration < 0 indicates infinite loop, consistent
with other orcallators
- Duration > 0 < 24 indicates run every 300 seconds
for Duration hours
- Duration = 0 or Duration >= 24 is undefined
-------------- next part --------------
#!/usr/bin/perl
#
# Version 1.20
# Description:
# Collect general perfromance statistics formatted for
# interpretaion by Orca.
# Usage:
# The following variables may be set:
#
# OUT_ROOT root directory for datafiles (eg /opt/log/performance)
# INTERVAL the number of seconds between checks (eg 300 = 5 min)
# DURATION numer of hours to run (eg 1 = 1 hr)
# < 0 means run indefinitely
# 0 is undefined
# 1-24 means run for N hours
#
# This script runs various standard system utilities to collect
# system performance statistics and writes them out to datafile named
# HOSTNAME/stats.YYYY-MM-DD-HHmm under the OUT_ROOT directory.
#
# It runs for the the numbers specified by DURATION collecting data
# every INTERVAL number of seconds. After DURATION, the script
# closes and compresses it's datafile via /usr/bin/compress and then
# exits. If DURATION=24 and INTERVAL=300 (recommended) then the
# following cron entry would collect continuos stats for a system:
#
# 0 0 * * * /<PATH_TO_SCRIPT>/orca-aix-stat.pl
#
# v1.20
# 2006-04-06 - DM - Added ^L page markers
# 2006-04-05 - DM - Modified how physical memory cap is identified
# Now uses prtconf instead of lslpp mumbo jumbo
# - corrected memory calculation
# - added check to verify memory cap identification
# If it didn't work, use a (bogus) default
# - added conditional for uptime parsing - N days (only)
# - shifted where some warnings are printed
# v1.8
# 2006-01-31 - DM - Added command-line options for TSM stuff:
# o specify TSM ID/password
# o disable TSM collection, even if present
# - TSM id/password now specified as a global variable
# - fixed warning messages to appear prior
# to corresponding header/data variable reset
# - updated version to 1.8
# - injected patterns for gnu-configure integration
# (only OUT_ROOT cared)
# 2004-08-19 - DM - Not yet ready for ./configure integration
# - Change: Redesign of some sections to run 24x7 using kernel
# counters instead of script cycles to compute
# needed values quickly every 5 minutes
# - Change: Duration < 0 indicates infinite loop, consistent
# with other orcallators
# - Duration > 0 < 24 indicates run every 300 seconds
# for Duration hours
# - Duration = 0 or Duration >= 24 is undefined
# DM = by Dave "Dragon" Michaels (dragon at raytheon.com)
# 2003-09-10 - RV - Modified for AIX 4.3/5.x.. by Rajesh Verma
# (rajeshverma at aixdude.com)
# v1.7 - RV - ignores /proc now
# 2001-04-16 - JDK - Genesis... by Jason D. Kelleher
# 2001-05-02 - JDK - Updates to make data aggregation easier.
# Added #open connections, pagestotl.
# 2001-07-06 - JDK - added command-line args & data checks
# 2001-07-09 - JDK - added signal handler, column checks, & umask
# 2001-07-10 - JDK - now autodetects interfaces via netstat -i
# v1.5
#
# $HeadURL: file:///var/www/svn/repositories-public/orcaware-public/orca/trunk/data_gatherers/aix/orca-aix-stat.pl.in $
# $LastChangedDate: 2006-04-06 17:36:41 -0700 (Thu, 06 Apr 2006) $
# $LastChangedBy: dragon at raytheon.com $
# $LastChangedRevision: 528 $
#
# Note: Execution speed is more important than cleanliness here.
# Explicitly set PATH to prevent odd problems if run manually.
$Usage_Message = '
Usage: orca-aix-stat.pl [-r out_root] [-i interval] [-d duration]
[-tid ID] [-tpw PASSWORD] [-notsm] [-h]
-r out_root - set root output directory, default: /opt/log/performance
-i interval - number of seconds between checks, default: 300
-d duration - number of hours to run, default: 24, -1: never terminate
-h - this message
-tid ID - the TSM user ID to use for dsmadmc commands
-tpw PASSWORD - the TSM password to use for dsmadmc commands
-notsm - do not gather TSM info
';
############################
# These are the packages you need to install
# 1. perl
# 2. openssh - if using ssh to the collector server
# 3. openssl
# 4. zlib
# 5. rsync - To copy file to the collector server
# 6. gzip - to zip the files
# 7. rpm.rte - to install rpm tools
#
# This the site you can file everything
# http://www-1.ibm.com/servers/aix/products/aixos/linux/download.html
# http://www.bullfreeware.com
#
#
# Good Luck, Rajesh Verma (rajeshverma at yahoo.com)
##############################
#
# Parse the command line arguments
while ( $#ARGV >= 0 ) {
if ( $ARGV[0] eq "-r" ) {
shift @ARGV;
$OUT_ROOT = shift @ARGV;
}
elsif ( $ARGV[0] eq "-notsm" ) {
shift @ARGV;
$DOTSM = "no";
}
elsif ( $ARGV[0] eq "-tid" ) {
shift @ARGV;
$TSMID = shift @ARGV;
}
elsif ( $ARGV[0] eq "-tpw" ) {
shift @ARGV;
$TSMPW = shift @ARGV;
}
elsif ( $ARGV[0] eq "-i" ) {
shift @ARGV;
$INTERVAL = shift @ARGV;
}
elsif ( $ARGV[0] eq "-d" ) {
shift @ARGV;
$DURATION = shift @ARGV;
}
elsif ( $ARGV[0] eq "-h" ) {
print $Usage_Message;
exit 0;
}
elsif ( $ARGV[0] =~ /^-/ ) {
die "Invalid flag: $ARGV[0]\n$Usage_Message";
}
else {
die "Invalid argument: $ARGV[0]\n$Usage_Message";
}
}
## BEGIN set defaults
#
$OUT_ROOT ||= '@VAR_DIR@/AIXorcallator'; # root directory for datafiles
$DOTSM ||= "yes";
$TSMID ||= 'orca';
$TSMPW ||= 'orca';
$INTERVAL ||= 300; # seconds between checks
$DURATION ||= 24; # number of hours to run
## END set defaults
## Derived variables.
$iterations = $DURATION * 60 * 60 / $INTERVAL; # Number of checks.
chomp( $HOST = `uname -n` );
$out_dir = "${OUT_ROOT}/${HOST}";
( $osec, $omin, $ohour, $omday, $omon, $oyear, $owday, $oyday, $oisdst ) =
localtime(time);
( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
localtime(time);
$stat_file =
sprintf( "%s/percol-%.2d-%.2d-%.2d-%02d%.2d%.2d", $out_dir, $year + 1900, $mon + 1,
$mday, $hour, $min, $sec );
$start_time = time();
$timestamp = $start_time;
#
# find the full paths of all commands,
# and deposit them into a variable $<name of cmd>_cmd
@pathdirs = reverse grep(m!^/!, split(/:/, $ENV{'PATH'}, 999));
$compressor = "@COMPRESSOR@";
if ( $compressor =~ "@" . "COMPRESSOR" . "@" ) {
# hmm, config must not have fixed it, so set it to a default
$compressor = "bzip2";
}
@cmds = (
$compressor,
"netstat",
"ls",
"ctxqsession",
"prtconf",
"uptime",
"ps",
"pstat",
"vmstat",
"df",
"iostat",
"svmon");
if ( "$DOTSM" == "yes" ) {
@cmds = ( @cmds, "dsmadmc" );
}
foreach $cmd ( @cmds ) {
$cmdvar = "";
if ( $cmd !~ m:^/: ) {
# don't have full path yet
foreach $dir ( @pathdirs ) {
if (-x "$dir/$cmd") {
$cmdvar = $cmd . "_cmd";
$$cmdvar="$dir/$cmd";
# for "ls", that evalutes to $ls_cmd, so in later
# code, $ls_cmd will expand to the full path, thus
# avoiding path traversal overhead
}
}
}
printf "%20s ", $cmd;
$$cmdvar ? print "=> $$cmdvar\n" : print "doesn't exist in PATH; Not collecting\n";
}
#
## Autodetect network interfaces
#open IN, "ifconfig -a|";
open IN, "$netstat_cmd -ni|";
while (<IN>) {
# if ( /^(\S+):/ ) {
if (/^(\w+).*link/) {
push @net_interfaces, $1;
}
}
close IN;
# Grab some base system info prior to collecting stats.
open IN, "$prtconf_cmd -m |";
while (<IN>) {
if (/^Memory Size: (\d+) MB/) {
$pagestotl = $1 * 1024 * 1024 / 4096; # Grab realmem in MB and convert to pages.
$mem_totl = $1 * 1024 * 1024; # Grab realmem in MB and convert to Bytes
# this gets used down in the vmstat section
} else {
print STDERR "ERROR: could not compute memorysize from $prtconf_cmd -m\n";
$pagestotl = 100;
$mem_totl = 100;
}
}
close IN;
## Make sure we can write output.
umask 0022; # make sure the file can be harvested
unless ( -d $out_dir ) {
system( "mkdir", "-p", "$out_dir" );
}
# Set signal handlers to close and compress the output
# file just in case.
$SIG{HUP} = \&exit_nicely;
$SIG{INT} = \&exit_nicely;
$SIG{QUIT} = \&exit_nicely;
$SIG{TERM} = \&exit_nicely;
# Set gloabals used for printing (or not) headers.
$need_header = 1; # our file starts empty, so we need a header by default
$prev_header_cnt = 0;
$prev_info_cnt = 0;
# Set globals used for tracking counts from interval to interval
# all counts start at zero
( $disk_t_prev,
$disk_rK_prev,
$disk_wK_prev,
$citrix_sessions,
$citrix_disconnect ) = ( 0, 0, 0, 0, 0 );
#
# set up a data structure to hold info about each
# interface, to carry from iteration to iteration,
# so we can calculate per-second data based on delta
# of totals between iterations
#
%netstat;
foreach $if (@net_interfaces) {
%netstat=(%netstat,
$if => {});
$netstat{$if}={"ipkt" => -1,
"ierr" => -1,
"opkt" => -1,
"oerr" => -1,
"coll" => -1};
}
$context_sw_prev=0;
# initialize all vmstat hash keys to -1, in a slick,
# if mystifying fashion, making it real easy to add
# more keys later, if need be
%vmstat;
# 1 2 3 4 5 6 7 8
# 9 10 11 12 13 14 15 16 17
@vmkeys=qw(r b avm fre re pi po fr
sr cy in sys cs us sy id wa);
@vmstat{@vmkeys} = (-1) x @vmkeys;
$vmstat{proc_s} = -1;
$vmstat{forks} = -1;
#
# Main while loop
while ( $DURATION < 0 || $iterations-- > 0 ) {
$timestamp = $timestamp ? time() : $start_time;
( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
localtime(time);
$locltime = sprintf( "%.2d:%.2d:%.2d", $hour, $min, $sec );
## Get runq data
$uptime = 0;
open IN, "$uptime_cmd |";
# Uptime is really really annoying. Here are the various and sundry formats
# you might run into over the course of a day:
# root at npdsa01 </var/tmp><137# uname -a
# AIX npdsa01 1 5 0025425A4C00
# root at npdsa01 </var/tmp><133# uptime
# 04:40PM up 13 days, 50 mins, 17 users, load average: 0.05, 0.12, 0.15
# dmichael at npdsa01 <orca/AIXorcallator><68> rsh npddev01 uptime
# 04:41PM up 2 days, 20 hrs, 33 users, load average: 0.58, 0.80, 1.06
# dmichael at npdsa01 <orca/AIXorcallator><70> rsh npddev01 uptime
# 04:45PM up 2 days, 20:04, 33 users, load average: 0.52, 0.68, 0.95
# dmichael at npdsa01 <~><2> uptime
# 03:48PM up 5:56, 9 users, load average: 0.00, 0.07, 0.16
# dmichael at npdsa01 <~><102> uptime
# 04:16PM up 1 day, 6:25, 8 users, load average: 0.00, 0.01, 0.01
# So, if you want the uptime, we have to parse all these circumstances.
while (<IN>) {
# first, get the easy part: load average
if (/load average:\s+(\S+),\s+(\S+),\s+(\S+)/) {
$load_info = join "\t", $1, $2, $3;
}
# now, get uptime, in various formats:
if (/up\s+(\d+)\s+day[s]?,\s+(\d+)\s+hrs,\s+(\d+)\s+user[s]?/) {
# up X days, Y hrs, U users
$up_day = $1;
$up_hrs = $2;
$up_min = 0;
$nusr = $3;
} elsif (/up\s+(\d+)\s+day[s]?,\s+(\d+):(\d+),\s+(\d+)\s+user[s]?/) {
# up X days, H:M, U users
$up_day = $1;
$up_hrs = $2;
$up_min = $3;
$nusr = $4;
} elsif (/up\s+(\d+)\s+day[s]?,\s+(\d+)\s+mins,\s+(\d+)\s+user[s]?/) {
# up X days, M mins, U users
$up_day = $1;
$up_hrs = 0;
$up_min = $2;
$nusr = $3;
} elsif (/up\s+(\d+)\s+mins,\s+(\d+)\s+user[s]?/) {
# up M mins, U users
$up_day = 0;
$up_hrs = 0;
$up_min = $1;
$nusr = $2;
} elsif (/up\s+(\d+):(\d+),\s+(\d+)\s+user[s]?/) {
# up H:M mins, U users
$up_day = 0;
$up_hrs = $1;
$up_min = $2;
$nusr = $3;
} elsif (/up\s+(\d+)\s+day[s]?,\s+(\d+)\s+user[s]?/) {
# up X days, U users
# this is pretty rare, as it only happens when
# orca is started on an exact day boundary (it just
# happened to me!).
$up_day = $1;
$up_hrs = 0;
$up_min = 0;
$nusr = $2;
}
#
# calculate uptime in seconds
$uptime = (( $up_day * 24 * 60 ) + ( $up_hrs * 60 ) + ( $up_min )) * 60;
}
close IN;
$load_header = "1runq\t5runq\t15runq";
$up_header = "uptime\tnusr";
$up_info = "$uptime\t$nusr";
if ( scalar( split ' ', $load_header ) != scalar( split ' ', $load_info ) )
{
$load_header = '';
$load_info = '';
$need_header = 1;
print STDERR "WARNING: load header does not match load info.\n";
}
if ( scalar( split ' ', $up_header ) != scalar( split ' ', $up_info ) )
{
$up_header = '';
$up_info = '';
$need_header = 1;
print STDERR "WARNING: UP header does not match load info.\n";
}
#
## Get number of system processes
$num_proc = -1; # Don't count the header.
open IN, "$ps_cmd -ek |";
while (<IN>) {
$num_proc++;
}
close IN;
$proc_info = "$num_proc";
$proc_header = '#proc';
if ( scalar( split ' ', $proc_header ) != scalar( split ' ', $proc_info ) )
{
$proc_header = '';
$proc_info = '';
$need_header = 1;
print STDERR "WARNING: #proc header does not match #proc info.\n";
}
#
## Get pstat data for pages
$sw_used = 0;
$sw_free = 0;
open IN, "$pstat_cmd -s |tail -3 |";
while (<IN>) {
@swp = split(/ +/,);
if (/\d/) {
$sw_used = $swp[1];
$sw_free = $swp[2];
$swap_used = $sw_used * 4096;
$swap_free = $sw_free * 4096;
}
}
close IN;
$swap_info = "$swap_used\t$swap_free";
$swap_header = "\tswap_used\tswap_free";
if ( scalar( split ' ', $swap_header ) !=
scalar( split ' ', $swap_info ) )
{
$swap_header = '';
$swap_info = '';
$need_header = 1;
print STDERR "WARNING: pstat header does not match pstat info.\n";
}
#
## Set up vmstat stuff
my $inter = $INTERVAL + ( time() - $timestamp );
my $interfact = ( $uptime - $inter ) * ( $uptime > $inter );
my %vm_sum_prev = %vmstat;
my $vm_sum_curr = {};
#
## Get numprocs/sec
open IN, "$vmstat_cmd -f |";
while (<IN>) {
chomp;
if (/^\s+(\d+) forks/) {
$vm_sum_curr{forks} = $1;
if ( $vm_sum_prev{forks} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{proc_s} = ( $vm_sum_curr{forks} - $vm_sum_prev{forks} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{proc_s} = ( $vm_sum_curr{forks} ) / $uptime;
}
$vm_sum_prev{forks} = $vm_sum_curr{forks};
}
}
close IN;
#
## Get static/counter-type vm stats
$inter = $INTERVAL + ( time() - $timestamp );
$interfact = ( $uptime - $inter ) * ( $uptime > $inter );
open IN, "$vmstat_cmd -s |";
while (<IN>) {
chomp;
if (/^\s+(\d+) total address trans. faults/) {
# total address trans. faults
# Incremented for each occurrence of an address translation
# page fault. I/O may or may not be required to resolve the
# page fault. Storage protection page faults (lock misses) are
# not included in this count.
} elsif (/^\s+(\d+) page ins/) {
# page ins
# Incremented for each page read in by the virtual memory
# manager. The count is incremented for page ins from page
# space and file space. Along with the page out statistic,
# this represents the total amount of real I/O initiated by
# the virtual memory manager.
} elsif (/^\s+(\d+) page outs/) {
# page outs
# Incremented for each page written out by the virtual memory
# manager. The count is incremented for page outs to page
# space and for page outs to file space. Along with the page
# in statistic, this represents the total amount of real I/O
# initiated by the virtual memory manager.
} elsif (/^\s+(\d+) paging space page ins/) {
# paging space page ins
# Incremented for VMM initiated page ins from paging space only.
$vm_sum_curr{pi} = $1;
if ( $vm_sum_prev{pi} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{pi} = ( $vm_sum_curr{pi} - $vm_sum_prev{pi} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{pi} = ( $vm_sum_curr{pi} ) / $uptime;
}
$vm_sum_prev{pi} = $vm_sum_curr{pi};
} elsif (/^\s+(\d+) paging space page outs/) {
# paging space outs
# Incremented for VMM initiated page outs to paging space only.
$vm_sum_curr{po} = $1;
if ( $vm_sum_prev{po} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{po} = ( $vm_sum_curr{po} - $vm_sum_prev{po} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{po} = ( $vm_sum_curr{po} ) / $uptime;
}
$vm_sum_prev{po} = $vm_sum_curr{po};
} elsif (/^\s+(\d+) total reclaims/) {
# reclaims
# Incremented when an address translation fault can be
# satisfied without initiating a new I/O request. This can
# occur if the page has been previously requested by VMM, but
# the I/O has not yet completed; or if the page was
# pre-fetched by VMM's read-ahead algorithm, but was hidden
# from the faulting segment; or if the page has been put on
# the free list and has not yet been reused.
} elsif (/^\s+(\d+) zero filled pages faults/) {
# zero filled pages faults
# Incremented if the page fault is to working storage and can
# be satisfied by assigning a frame and zero-filling it.
} elsif (/^\s+(\d+) executable filled pages faults/) {
# executable-filled page faults
# Incremented for each instruction page fault.
} elsif (/^\s+(\d+) pages examined by clock/) {
# pages examined by the clock
# VMM uses a clock-algorithm to implement a pseudo least
# recently used (lru) page replacement scheme. Pages are aged
# by being examined by the clock. This count is incremented
# for each page examined by the clock.
} elsif (/^\s+(\d+) revolutions of the clock hand/) {
# revolutions of the clock hand
# Incremented for each VMM clock revolution (that is, after
# each complete scan of memory).
$vm_sum_curr{cy} = $1;
if ( $vm_sum_prev{cy} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{cy} = ( $vm_sum_curr{cy} - $vm_sum_prev{cy} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{cy} = ( $vm_sum_curr{cy} ) / $uptime;
}
$vm_sum_prev{cy} = $vm_sum_prev{cy};
} elsif (/^\s+(\d+) pages freed by the clock/) {
# pages freed by the clock
# Incremented for each page the clock algorithm selects to
# free from real memory.
$vm_sum_curr{fr} = $1;
if ( $vm_sum_prev{fr} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{fr} = ( $vm_sum_curr{fr} - $vm_sum_prev{fr} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{fr} = ( $vm_sum_curr{fr} ) / $uptime;
}
$vm_sum_prev{fr} = $vm_sum_prev{fr};
} elsif (/^\s+(\d+) backtracks/) {
# backtracks
# Incremented for each page fault that occurs while resolving
# a previous page fault. (The new page fault must be resolved
# first and then initial page faults can be backtracked.)
} elsif (/^\s+(\d+) lock misses/) {
# lock misses
# VMM enforces locks for concurrency by removing
# addressability to a page. A page fault can occur due to a
# lock miss, and this count is incremented for each such
# occurrence.
} elsif (/^\s+(\d+) free frame waits/) {
# free frame waits
# Incremented each time a process is waited by VMM while free
# frames are gathered.
} elsif (/^\s+(\d+) extend XPT waits/) {
# extend XPT waits
# Incremented each time a process is waited by VMM due to a
# commit in progress for the segment being accessed.
} elsif (/^\s+(\d+) pending I\/O waits/) {
# pending I/O waits
# Incremented each time a process is waited by VMM for a
# page-in I/O to complete.
} elsif (/^\s+(\d+) start I\/Os/) {
# start I/Os
# Incremented for each read or write I/O request initiated by
# VMM. This count should equal the sum of page-ins and
# page-outs.
} elsif (/^\s+(\d+) iodones/) {
# iodones
# Incremented at the completion of each VMM I/O request.
} elsif (/^\s+(\d+) cpu context switches/) {
# CPU context switches
# Incremented for each CPU context switch (dispatch of a new
# process).
$vm_sum_curr{cs} = $1;
if ( $vm_sum_prev{cs} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{cs} = ( $vm_sum_curr{cs} - $vm_sum_prev{cs} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{cs} = ( $vm_sum_curr{cs} ) / $uptime;
}
} elsif (/^\s+(\d+) device interrupts/) {
# device interrupts
# Incremented on each hardware interrupt.
$vm_sum_curr{in} = $1;
if ( $vm_sum_prev{in} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{in} = ( $vm_sum_curr{in} - $vm_sum_prev{in} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{in} = ( $vm_sum_curr{in} ) / $uptime;
}
$vm_sum_prev{in} = $vm_sum_prev{in};
} elsif (/^\s+(\d+) software interrupts/) {
# software interrupts
# Incremented on each software interrupt. A software interrupt
# is a machine instruction similar to a hardware interrupt
# that saves some state and branches to a service
# routine. System calls are implemented with software
# interrupt instructions that branch to the system call
# handler routine.
} elsif (/^\s+(\d+) traps/) {
# traps
# Not maintained by the operating system.
} elsif (/^\s+(\d+) syscalls/) {
# syscalls
# Incremented for each system call.
$vm_sum_curr{sys} = $1;
if ( $vm_sum_prev{sys} > 0 ) {
# there already exists a valid "prev", so proceed as normal
$vm_sum_curr{sys} = ( $vm_sum_curr{sys} - $vm_sum_prev{sys} ) / $inter;
} else {
# set up first value as the average-to-date
$vm_sum_curr{sys} = ( $vm_sum_curr{sys} ) / $uptime;
}
$vm_sum_prev{sys} = $vm_sum_prev{sys};
}
}
close IN;
#
## Get live vmstat data
open IN, "$vmstat_cmd 5 2 |";
my $inter = $INTERVAL + ( time() - $timestamp );
# convert a given 'count' to 'estimated count before previous
# interval', with the condition that if we haven't been up for at least
# an interval, set this value to zero this is used to seed the initial
# values with something more useful than 0
while (<IN>) {
chomp;
# r b avm fre re pi po fr sr cy inf sysf csf us sy id wa
# 1 r Number of kernel threads placed in run queue.
# 2 b Number of kernel threads placed in wait queue (awaiting
# resource, awaiting input/output).
#
# Memory: information about the usage of virtual and real
# memory. Virtual pages are considered active if they have been
# accessed. A page is 4096 bytes.
#
# 3 avm Active virtual pages.
# 4 fre Size of the free list.
# Note: A large portion of real memory is utilized as a cache
# for file system data. It is not unusual for the size of the
# free list to remain small.
#
# Page: information about page faults and paging activity. These
# are averaged over the interval and given in units per second.
#
# 5 re Pages input/output list.
# 6 pi Pages paged in from paging space.
# 7 po Pages paged out to paging space.
# 8 fr Pages freed (page replacement).
# 9 sr Pages scanned by page-replacement algorithm.
# 10 cy Clock cycles by page-replacement algorithm.
#
# Faults: trap and interrupt rate averages per second over the
# sampling interval.
#
# 11 in Device interrupts.
# 12 sy System calls.
# 13 cs Kernel thread context switches.
#
# Cpu: breakdown of percentage usage of CPU time.
#
# 14 us User time.
# 15 sy System time.
# 16 id CPU idle time.
# 17 wa CPU idle time during which the system had outstanding disk/NFS I/O
# request(s). See detailed description above.
#
if (/^[\s\d]+$/) {
# overwrite first line on 2nd pass
my $vm_curr = {};
my $info = "";
# assign %curr{field} values. @vmkeys is
# an array of field identifiers that should align
# with the output of the vmstat command
@vm_curr{@vmkeys} = split;
foreach $_ ( @vmkeys , proc_s ) {
# if we already got the data from the summary
# output (more reliable / accurate), then
# use that, otherwise, use the values from the
# vmstat interval run
$vmstat{$_}=(
($vm_sum_curr{$_} > 0 )
* ( $vm_sum_curr{$_} )
||
$vm_curr{$_} );
$info = $info . $vmstat{$_} . "\t";
}
$vmstat{forks}=$vm_sum_curr{forks};
# tack on other things not in @vmkeys
$info = $info . "\t" . $pagestotl;
$vmstat_info = $info;
}
}
close IN;
$vmstat_header =
"runque\twaiting\tpagesactive\tfreememK\tPagesIO/s\tPagesI/s\tPagesO/s\tPagesF/s\tscanrate\tcy_cycles\tdevinter\tsyscalls\tcs\tusr%\tsys%\tidle%\twio%\t#proc/s\tpagestotl";
if ( scalar( split ' ', $vmstat_header ) !=
scalar( split ' ', $vmstat_info ) )
{
print STDERR "WARNING: vmstat header does not match vmstat info.\n";
print STDERR "header is: $vmstat_header\n";
print STDERR "header #fields: ", scalar(split ' ', $vmstat_header ), "\n";
print STDERR "info is : $vmstat_info\n";
print STDERR "info #fields : ", scalar(split ' ', $vmstat_info), "\n";
$vmstat_header = '';
$vmstat_info = '';
$need_header = 1;
print STDERR "vmkeys is : ", $#vmkeys, "\n";
}
#
## Get filesystem data
$fs_header = '';
$fs_info = '';
open IN, "$df_cmd -k -v |";
while (<IN>) {
chomp;
if (m%^/dev%) {
( $mnt_dev, $blocks, $used, $free, $pct_used, $iused, $ifree,
$ipct_used, $mnt ) = split;
# Recalculate percents because df rounds.
$fs_info .= "\t"
. sprintf( "%s\t%s\t%s\t%.5f\t%d\t%s\t%s\t%.5f", $blocks, $used,
$free, ( $used / $blocks ) * 100, ( $iused + $ifree ), $iused,
$ifree, ( $iused / ( $iused + $ifree ) ) * 100 );
$fs_header .= "\t" . join "\t", "mntC_$mnt", "mntU_$mnt",
"mntA_$mnt", "mntP_$mnt", "mntc_$mnt", "mntu_$mnt", "mnta_$mnt",
"mntp_$mnt";
}
}
close IN;
if ( scalar( split ' ', $fs_header ) != scalar( split ' ', $fs_info ) ) {
$fs_header = '';
$fs_info = '';
$need_header = 1;
print STDERR
"WARNING: filesystem header does not match filesystem info.\n";
}
#
## Get iostat data
$disk_t = 0;
$disk_rK = 0;
$disk_wK = 0;
undef %disks;
# open IN, "iostat -d 1 2|";
# iostat totals are useful; running counts are good for
# interactive observations, but a 1s interval observation
# isn't representative for 'snapshots'; only total counts are.
open IN, "$iostat_cmd -s -d|";
# for accuracy's sake, add on number of seconds
# since this run started
my $inter = $INTERVAL + ( time() - $timestamp );
while (<IN>) {
# if (/^(\S+)\s+\S+\s+\S+\s+(\S+)\s+(\d+)\s+(\d+)/) {
if (/^\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)/) {
my $kBs = $1;
my $tps = $2;
my $rK = $3;
my $wK = $4;
if ( $disk_rK_prev == 0 ) {
# there is no previous data, so seed with average rates
# spread over time-since-boot minus specified interval.
# If uptime < INTERVAL, then we haven't been up long enough
# to have a (valid) previous interval, so
# the previous count really is zero.
$disk_rK_prev = ( $rK / $uptime ) * ( $uptime - $inter ) * ($uptime > $INTERVAL);
$disk_wK_prev = ( $wK / $uptime ) * ( $uptime - $inter ) * ($uptime > $INTERVAL);
# iostat on AIX only reports transactions per second,
# to 3 significant figures, not total transactions.
# So this value is useless; maybe some other AIX utility
# can grab this, but for now, just keep reporting the
# running average.
$disk_t_prev = $tps;
}
# calculate reads/writes per second from totals reported by iostat
$disk_rK = ( $rK - $disk_rK_prev ) / $inter;
$disk_wK = ( $wK - $disk_wK_prev ) / $inter;
$disk_t = $tps;
$disk_rK_prev = $rK;
$disk_wK_prev = $wK;
$disk_t_prev = $tps;
}
}
close IN;
$iostat_header = "disk_t/s\tdisk_rK/s\tdisk_wK/s";
$iostat_info = "${disk_t}\t${disk_rK}\t${disk_wK}";
if ( scalar( split ' ', $iostat_header ) !=
scalar( split ' ', $iostat_info ) )
{
$iostat_header = '';
$iostat_info = '';
$need_header = 1;
print STDERR "WARNING: iostat header does not match iostat info.\n";
}
#
## Get packet data
$packet_header = '';
$packet_info = '';
foreach $interface (@net_interfaces) {
$packet_header .=
"\t${interface}Ipkt/s\t${interface}IErr/s\t${interface}Opkt/s\t${interface}OErr/s\t${interface}Coll/s\t";
open IN, "$netstat_cmd -n -I $interface 1 |";
# format looks like
# input (en0) output input (Total) output
# packets errs packets errs colls packets errs packets errs colls
# 492126804 0 255536091 0 0 553459817 0 316872224 0 0
# for accuracy's sake, add on number of seconds
# since this run started
my $interv = $INTERVAL + ( time() - $timestamp );
# make %prev point to %netstat{$interface}, just for readability
my $prev = %netstat->{$interface};
while (<IN>) {
if (/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+/) {
my $ipkt = $1;
my $ierr = $2;
my $opkt = $3;
my $oerr = $4;
my $coll = $5;
if ( $prev->{"ipkt"} == -1 ) {
# haven't populated data yet - extrapolate
my $extrapolate = sub { ( @_[0] / $uptime ) *
( $uptime - $interv ) * ( $uptime > $interv ); };
# use this funky notation, so that packet_info
# syntax doesn't depend on instance status
# of prev (copy or pointer)
$prev=\%{{ "ipkt" => &$extrapolate($ipkt),
"ierr" => &$extrapolate($ierr),
"opkt" => &$extrapolate($opkt),
"oerr" => &$extrapolate($oerr),
"coll" => &$extrapolate($coll) }};
}
# build packet info line with appropriate rates
$packet_info .= "\t" . join "\t",
( ( $ipkt - $prev->{"ipkt"} ) / $interv ),
( ( $ierr - $prev->{"ierr"} ) / $interv ),
( ( $opkt - $prev->{"opkt"} ) / $interv ),
( ( $oerr - $prev->{"oerr"} ) / $interv ),
( ( $coll - $prev->{"coll"} ) / $interv );
# remember current counts for next iteration calculations
$netstat{$interface} = { "ipkt" => $ipkt,
"ierr" => $ierr,
"opkt" => $opkt,
"oerr" => $oerr,
"coll" => $coll};
# don't care about rest of input, just terminate read loop
last;
}
}
close IN;
}
# print "packet header is $packet_header\n";
# print "packet info is $packet_info\n";
if ( scalar( split ' ', $packet_header ) !=
scalar( split ' ', $packet_info ) )
{
$packet_header = '';
$packet_info = '';
$need_header = 1;
print STDERR "WARNING: packet header does not match packet info.\n";
print STDERR "packet header is: ", $packet_header, "\n";
print STDERR "packet info is: ", $packet_info, "\n";
}
#
## Get TCP Connection data
$tcp_estb = 0;
open IN, "$netstat_cmd -an |";
while (<IN>) {
if (/^tcp.+ESTABLISHED$/) {
$tcp_estb++;
}
}
close IN;
$tcp_info = $tcp_estb;
$tcp_header = 'tcp_estb';
if ( scalar( split ' ', $tcp_estb_header ) !=
scalar( split ' ', $tcp_estb_info ) )
{
$tcp_estb_header = '';
$tcp_estb_info = '';
$need_header = 1;
print STDERR "WARNING: tcp_estb header does not match tcp_estb info.\n";
}
#
## Get TSM Database space usage
$tsmdb = 0;
if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query db' |tail -r -n 5 |";
while (<IN>) {
@fld = split(/ +/,);
if (/\d/) {
$tsmdb = $fld[8];
}
}
close IN;
}
$tsm_info = $tsmdb;
$tsm_header = "tsmdb\t";
if ( scalar( split ' ', $tsm_header ) !=
scalar( split ' ', $tsm_info ) )
{
$tsm_header = '';
$tsm_info = '';
$need_header = 1;
print STDERR "WARNING: tsmdb header does not match tsmdb info.\n";
}
#
## Get Memory Usage breakup using SVMON
$mem_work = 0;
$mem_pres = 0;
$mem_clnt = 0;
open IN, "$svmon_cmd -G |tail -2 |";
while (<IN>) {
@memp = split(/ +/,);
if (/use\s+(\d+) /) {
$m_work = $memp[2];
$m_pres = $memp[3];
$m_clnt = $memp[4];
$mem_work = $m_work * 4096;
$mem_pres = $m_pres * 4096;
$mem_clnt = $m_clnt * 4096;
}
}
close IN;
$mem_info = "$mem_work\t$mem_pres\t$mem_clnt\t$mem_totl";
$mem_header = "mem_work\tmem_pres\tmem_clnt\tmem_totl";
if ( scalar( split ' ', $mem_header ) !=
scalar( split ' ', $mem_info ) )
{
$mem_header = '';
$mem_info = '';
$need_header = 1;
print STDERR "WARNING: memory header does not match memory info.\n";
}
#
## Get TSM Tape Drive usage
$rmt = 0;
$rmt5 = 5;
if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query mount' |grep matches |";
while (<IN>) {
@fld = split(/ +/,);
if (/\d/) {
$rmt = $fld[1];
}
}
close IN;
}
$tsm_rmt_header = "rmt5\trmt\t";
$tsm_rmt_info = "$rmt5\t$rmt";
if ( scalar( split ' ', $tsm_rmt_header ) !=
scalar( split ' ', $tsm_rmt_info ) )
{
print STDERR "WARNING: TSM RMT header does not match TSM RMT info.\n";
$tsm_rmt_header = '';
$tsm_rmt_info = '';
$need_header = 1;
}
#
## Get TSM Recovery Log space usage
$tsmlog = 0;
if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query log' |tail -r -n 4 |";
while (<IN>) {
@fld = split(/ +/,);
if (/\d/) {
$tsmlog = $fld[8];
}
}
close IN;
}
$tsm_log_info = $tsmlog;
$tsm_log_header = 'tsmlog';
if ( scalar( split ' ', $tsm_log_header ) !=
scalar( split ' ', $tsm_log_info ) )
{
print STDERR "WARNING: TSM Log header ($tsm_log_header) does not match TSM Log info ($tsm_log_info).\n";
$tsm_log_header = '';
$tsm_log_info = '';
$need_header = 1;
}
#
## Get TSM Tape usage
$tsmpvt = 0;
$tsmscr = 0;
$tsmvlt = 0;
if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query libvol' | grep 'Private' | wc -l |";
while (<IN>) {
chomp;
@fld = split(/ +/,);
if (/\d/) {
$tsmpvt = $fld[1];
}
}
close IN;
open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query libvol' | grep 'Scratch' | wc -l |";
while (<IN>) {
chomp;
@fld = split(/ +/,);
if (/\d/) {
$tsmscr = $fld[1];
}
}
close IN;
open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query drmedia' | grep 'Vault' | wc -l |";
while (<IN>) {
chomp;
@fld = split(/ +/,);
if (/\d/) {
$tsmvlt = $fld[1];
}
}
}
$tsm_tape_info = join "\t", $tsmpvt, $tsmscr, $tsmvlt;
$tsm_tape_header = join "\t", tsmpvt, tsmscr, tsmvlt;
if ( scalar( split ' ', $tsm_tape_header ) !=
scalar( split ' ', $tsm_tape_info ) )
{
print STDERR "WARNING: TSM Tape header does not match TSM Tape info.\n";
$tsm_tape_header = '';
$tsm_tape_info = '';
$need_header = 1;
}
#
## Get TSM Disk Storage Pool usage
$tsmphcy = 0;
$tsmphcn = 0;
if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query stgpool' |";
while (<IN>) {
@fld = split(/ +/,);
if (/\d/) {
if ( $fld[0] eq "PHCYDISKPO-" ) {
$tsmphcy = $fld[3];
}
elsif ( $fld[0] eq "PHCNDISKPO-" ) {
$tsmphcn = $fld[3];
}
}
}
close IN;
}
$tsm_stg_info = join "\t", $tsmphcy, $tsmphcn;
$tsm_stg_header = join "\t", tsmphcy, tsmphcn;
if ( scalar( split ' ', $tsm_stg_header ) !=
scalar( split ' ', $tsm_stg_info ) )
{
print STDERR "WARNING: TSM Storage Pool header does not match TSM Storage Pool info.\n";
$tsm_stg_header = '';
$tsm_stg_info = '';
$need_header = 1;
}
#
## Get runq data
if ( $ctxqsession_cmd == "" ) {
$ctxqsession_cmd="/usr/lpp/CTXSmf/bin/ctxqsession";
}
$citrix_sessions=0;
$citrix_disconnect=0;
if ( -e $ctxqsession_cmd && -x $ctxqsession_cmd ) {
open IN, "$ctxqsession_cmd |";
while (<IN>) {
if ( /tcp\#/ ) {
$citrix_sessions++;
}
if ( /\sdisc\s/ ) {
$citrix_disconnect++;
}
}
close IN;
}
$citrix_info = join "\t", $citrix_sessions, $citrix_disconnect;
$citrix_header = join "\t", ctx_sess, ctx_disc;
#
## construct our header
$out_header = join "\t", "timestamp", "locltime", $load_header, $up_header,
$proc_header, $vmstat_header, $fs_header, $iostat_header, $packet_header,
$tcp_header, $tsm_header, $swap_header, $mem_header, $tsm_rmt_header,
$tsm_log_header, $tsm_tape_header, $tsm_stg_header, $citrix_header;
$out_header =~ tr/ \t/\t/s; # translate whitespace to single tabs
## construct a line of data
$out_info = join "\t", $timestamp, $locltime, $load_info, $up_info, $proc_info,
$vmstat_info, $fs_info, $iostat_info, $packet_info, $tcp_info, $tsm_info,
$swap_info, $mem_info, $tsm_rmt_info, $tsm_log_info, $tsm_tape_info,
$tsm_stg_info, $citrix_info;
$out_info =~ tr/ \t/\t/s; # translate whitespace to single tabs
# count the fields in header and info lines--make sure the counts match.
$header_cnt = split ' ', $out_header;
$info_cnt = split ' ', $out_info;
if ( $header_cnt != $info_cnt ) {
# oh, dear! How did this happen? Bad code! No biscuit!
# somehow we collected more (or less) data than we have columns for.
# That's bad, Ray.
print STDERR
"ERROR: header columns do not equal data columns. Exiting.\n";
&exit_nicely;
}
#
if ( $need_header == 1 ) {
# If we did things right,
# The only way we get here is if it's the first line of the output file,
# or if we already know of a header change, such as if TSM spewed,
# or new filesystems were mounted, or dismounted, or .....
# In any of these cases, we'll be creating a new output file anyway,
# so just let things happen.
} elsif ( $prev_header != $out_header ) {
# the header changed. Time for a new file.
$need_header = 1;
} elsif ( $header_cnt != $prev_header_cnt or $info_cnt != $prev_info_cnt ) {
# crazy -- the previous count and the current count don't match,
# so we must have different headers, which should have been caught
# in the header comparison above, but apparently not.
$need_header = 1;
}
$prev_header = $out_header;
$prev_header_cnt = $header_cnt;
$prev_info_cnt = $info_cnt;
#
## Check to see if we've crossed days,
## or if we need a new header.
## In either case, we need a new file.
#
( $nsec, $nmin, $nhour, $nmday, $nmon, $nyear, $nwday, $nyday, $nisdst ) =
localtime(time);
if ( ($nyear*1000 + $nyday) > ($oyear*1000 + $oyday) ) {
# hey, we crossed days. Be nice--open a new file, to keep the
# existing file from getting stupid-big. Note that
# creating a new output file automatically sets need_header to 1.
&new_output_file;
} elsif ( $need_header ) {
# We didn't switch days yet, but we still need a new header for various
# possible reasons. So make a new output file (always need a new
# output file whenever we need a new header--even the first time!)
&new_output_file;
}
# Can't imagine how we'd get here without creating an output file.
# But, here's the code for creating it, just in case.
# if (! select OUT) {
# open OUT, ">$stat_file" or die "ERROR: Could not open $stat_file: $!";
# my $oldfh = select OUT;
# $| = 1;
# select $oldfh;
# }
## Write output
if ($need_header) {
print OUT $out_header, "\n";
$need_header = 0;
}
print OUT $out_info, "\n";
# use this for testing, to speed things along.
#sleep 5;
sleep $INTERVAL - ( time() - $timestamp );
}
&exit_nicely;
######################################################################
#
# subroutines
#
#
##################################################
# exit_nicely ()
# This subroutine is called by the signal handler, or at the end
# of the while loop, if ever reached.
#
# It takes no arguments, and does not return - it simply exits
# the fork it's running under.
sub exit_nicely {
if ( <OUT> ) {
close OUT;
@args = split(' ',$compressor);
push @args, "$stat_file";
print @args, "\n";
system(@args);
}
exit 0;
}
#
##################################################
# new_output_file ()
#
# Whenever a new header is needed, or if we change
# days, then do the following:
# o close previous output file
# o fork a process to compress it
# o create a new output file
#
sub new_output_file {
if ( <OUT> ) {
close OUT;
}
( $osec, $omin, $ohour, $omday, $omon,
$oyear, $owday, $oyday, $oisdst ) = localtime(time);
# close & compress file in background process
# create new file & continue in current process
if ( $pid = fork ) {
# parent process resumes here
$stat_file =
sprintf( "%s/percol-%.2d-%.2d-%.2d-%.2d%.2d%.2d",
$out_dir, $oyear + 1900, $omon + 1,
$omday, $ohour, $omin, $osec );
open OUT, ">$stat_file" or die "ERROR: Could not open $stat_file: $!";
my $oldfh = select OUT;
$| = 1;
select $oldfh;
$need_header = 1;
} elsif (defined $pid) {
# child process resumes here
&exit_nicely;
}
}
-------------- next part --------------
*** orca-aix-stat.pl.in Thu Apr 6 18:02:06 2006
--- orca-aix-stat.old.pl.in Thu Sep 8 21:51:41 2005
***************
*** 1,62 ****
! #!/usr/bin/perl
#
! # Version 1.20
!
! # Description:
! # Collect general perfromance statistics formatted for
! # interpretaion by Orca.
!
! # Usage:
# The following variables may be set:
! #
! # OUT_ROOT root directory for datafiles (eg /opt/log/performance)
# INTERVAL the number of seconds between checks (eg 300 = 5 min)
! # DURATION numer of hours to run (eg 1 = 1 hr)
! # < 0 means run indefinitely
! # 0 is undefined
! # 1-24 means run for N hours
! #
# This script runs various standard system utilities to collect
# system performance statistics and writes them out to datafile named
# HOSTNAME/stats.YYYY-MM-DD-HHmm under the OUT_ROOT directory.
! #
! # It runs for the the numbers specified by DURATION collecting data
! # every INTERVAL number of seconds. After DURATION, the script
! # closes and compresses it's datafile via /usr/bin/compress and then
! # exits. If DURATION=24 and INTERVAL=300 (recommended) then the
! # following cron entry would collect continuos stats for a system:
! #
# 0 0 * * * /<PATH_TO_SCRIPT>/orca-aix-stat.pl
! #
! # v1.20
! # 2006-04-06 - DM - Added ^L page markers
! # 2006-04-05 - DM - Modified how physical memory cap is identified
! # Now uses prtconf instead of lslpp mumbo jumbo
! # - corrected memory calculation
! # - added check to verify memory cap identification
! # If it didn't work, use a (bogus) default
! # - added conditional for uptime parsing - N days (only)
! # - shifted where some warnings are printed
! # v1.8
! # 2006-01-31 - DM - Added command-line options for TSM stuff:
! # o specify TSM ID/password
! # o disable TSM collection, even if present
! # - TSM id/password now specified as a global variable
! # - fixed warning messages to appear prior
! # to corresponding header/data variable reset
! # - updated version to 1.8
! # - injected patterns for gnu-configure integration
! # (only OUT_ROOT cared)
! # 2004-08-19 - DM - Not yet ready for ./configure integration
! # - Change: Redesign of some sections to run 24x7 using kernel
! # counters instead of script cycles to compute
! # needed values quickly every 5 minutes
! # - Change: Duration < 0 indicates infinite loop, consistent
! # with other orcallators
! # - Duration > 0 < 24 indicates run every 300 seconds
! # for Duration hours
! # - Duration = 0 or Duration >= 24 is undefined
! # DM = by Dave "Dragon" Michaels (dragon at raytheon.com)
# 2003-09-10 - RV - Modified for AIX 4.3/5.x.. by Rajesh Verma
# (rajeshverma at aixdude.com)
# v1.7 - RV - ignores /proc now
--- 1,25 ----
! # Collect general AIX performance statistics formatted for
! # interpretation by Orca.
#
! # Usage:
# The following variables may be set:
! #
! # OUT_ROOT root directory for data files (eg /opt/log/performance)
# INTERVAL the number of seconds between checks (eg 300 = 5 min)
! # DURATION number of hours to run (eg 1 = 1 hr)
! #
# This script runs various standard system utilities to collect
# system performance statistics and writes them out to datafile named
# HOSTNAME/stats.YYYY-MM-DD-HHmm under the OUT_ROOT directory.
! #
! # It runs for the numbers specified by DURATION collecting data every
! # INTERVAL number of seconds. After DURATION, the script closes and
! # compresses it's datafile via /usr/bin/compress and then exits. If
! # DURATION=24 and INTERVAL=300 (recommended) then the following cron
! # entry would collect continuous stats for a system:
! #
# 0 0 * * * /<PATH_TO_SCRIPT>/orca-aix-stat.pl
! #
# 2003-09-10 - RV - Modified for AIX 4.3/5.x.. by Rajesh Verma
# (rajeshverma at aixdude.com)
# v1.7 - RV - ignores /proc now
***************
*** 65,95 ****
# Added #open connections, pagestotl.
# 2001-07-06 - JDK - added command-line args & data checks
# 2001-07-09 - JDK - added signal handler, column checks, & umask
! # 2001-07-10 - JDK - now autodetects interfaces via netstat -i
# v1.5
#
# $HeadURL: file:///var/www/svn/repositories-public/orcaware-public/orca/trunk/data_gatherers/aix/orca-aix-stat.pl.in $
! # $LastChangedDate: 2006-04-06 17:36:41 -0700 (Thu, 06 Apr 2006) $
! # $LastChangedBy: dragon at raytheon.com $
! # $LastChangedRevision: 528 $
! #
! # Note: Execution speed is more important than cleanliness here.
# Explicitly set PATH to prevent odd problems if run manually.
! $Usage_Message = '
! Usage: orca-aix-stat.pl [-r out_root] [-i interval] [-d duration]
! [-tid ID] [-tpw PASSWORD] [-notsm] [-h]
! -r out_root - set root output directory, default: /opt/log/performance
! -i interval - number of seconds between checks, default: 300
! -d duration - number of hours to run, default: 24, -1: never terminate
! -h - this message
! -tid ID - the TSM user ID to use for dsmadmc commands
! -tpw PASSWORD - the TSM password to use for dsmadmc commands
! -notsm - do not gather TSM info
- ';
############################
# These are the packages you need to install
# 1. perl
--- 28,55 ----
# Added #open connections, pagestotl.
# 2001-07-06 - JDK - added command-line args & data checks
# 2001-07-09 - JDK - added signal handler, column checks, & umask
! # 2001-07-10 - JDK - now auto detects interfaces via netstat -i
# v1.5
#
# $HeadURL: file:///var/www/svn/repositories-public/orcaware-public/orca/trunk/data_gatherers/aix/orca-aix-stat.pl.in $
! # $LastChangedDate: 2005-09-08 20:51:41 -0700 (Thu, 08 Sep 2005) $
! # $LastChangedBy: blair at orcaware.com $
! # $LastChangedRevision: 490 $
+ my $COMPRESS = '@COMPRESSOR@';
+
# Explicitly set PATH to prevent odd problems if run manually.
+ $ENV{PATH} = '/bin:/usr/bin:/etc:/usr/sbin:/usr/ucb:/sbin';
! my $Usage_Message = "
! usage: $0 [-r out_root] [-i interval] [-d duration] [-h]
! -r out_root set root output directory, default: /opt/log/performance
! -i interval number of seconds between checks, default: 300
! -d duration number of hours to run, default: 24
! -h this message
! ";
############################
# These are the packages you need to install
# 1. perl
***************
*** 104,158 ****
# http://www-1.ibm.com/servers/aix/products/aixos/linux/download.html
# http://www.bullfreeware.com
#
! #
! # Good Luck, Rajesh Verma (rajeshverma at yahoo.com)
##############################
- #
- # Parse the command line arguments
- while ( $#ARGV >= 0 ) {
! if ( $ARGV[0] eq "-r" ) {
! shift @ARGV;
! $OUT_ROOT = shift @ARGV;
! }
! elsif ( $ARGV[0] eq "-notsm" ) {
! shift @ARGV;
! $DOTSM = "no";
! }
! elsif ( $ARGV[0] eq "-tid" ) {
! shift @ARGV;
! $TSMID = shift @ARGV;
! }
! elsif ( $ARGV[0] eq "-tpw" ) {
! shift @ARGV;
! $TSMPW = shift @ARGV;
! }
! elsif ( $ARGV[0] eq "-i" ) {
! shift @ARGV;
! $INTERVAL = shift @ARGV;
! }
! elsif ( $ARGV[0] eq "-d" ) {
! shift @ARGV;
! $DURATION = shift @ARGV;
! }
! elsif ( $ARGV[0] eq "-h" ) {
! print $Usage_Message;
! exit 0;
! }
! elsif ( $ARGV[0] =~ /^-/ ) {
! die "Invalid flag: $ARGV[0]\n$Usage_Message";
! }
! else {
! die "Invalid argument: $ARGV[0]\n$Usage_Message";
! }
}
## BEGIN set defaults
! #
! $OUT_ROOT ||= '@VAR_DIR@/AIXorcallator'; # root directory for datafiles
! $DOTSM ||= "yes";
! $TSMID ||= 'orca';
! $TSMPW ||= 'orca';
$INTERVAL ||= 300; # seconds between checks
$DURATION ||= 24; # number of hours to run
--- 64,96 ----
# http://www-1.ibm.com/servers/aix/products/aixos/linux/download.html
# http://www.bullfreeware.com
#
! # Good Luck, Rajesh Verma (rajeshverma at yahoo.com)
##############################
! # Parse the command line arguments
! while ($#ARGV >= 0) {
! if ($ARGV[0] eq "-r") {
! shift @ARGV;
! $OUT_ROOT = shift @ARGV;
! } elsif ($ARGV[0] eq "-i") {
! shift @ARGV;
! $INTERVAL = shift @ARGV;
! } elsif ($ARGV[0] eq "-d") {
! shift @ARGV;
! $DURATION = shift @ARGV;
! } elsif ($ARGV[0] eq "-h") {
! print $Usage_Message;
! exit 0;
! } elsif ($ARGV[0] =~ /^-/) {
! die "Invalid flag: $ARGV[0]\n$Usage_Message";
! } else {
! die "Invalid argument: $ARGV[0]\n$Usage_Message";
! }
}
## BEGIN set defaults
!
! $OUT_ROOT ||= '/home/orca/orcallator'; # root directory for data files
$INTERVAL ||= 300; # seconds between checks
$DURATION ||= 24; # number of hours to run
***************
*** 160,256 ****
## Derived variables.
$iterations = $DURATION * 60 * 60 / $INTERVAL; # Number of checks.
! chomp( $HOST = `uname -n` );
$out_dir = "${OUT_ROOT}/${HOST}";
! ( $osec, $omin, $ohour, $omday, $omon, $oyear, $owday, $oyday, $oisdst ) =
localtime(time);
- ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
- localtime(time);
$stat_file =
! sprintf( "%s/percol-%.2d-%.2d-%.2d-%02d%.2d%.2d", $out_dir, $year + 1900, $mon + 1,
! $mday, $hour, $min, $sec );
$start_time = time();
! $timestamp = $start_time;
! #
! # find the full paths of all commands,
! # and deposit them into a variable $<name of cmd>_cmd
! @pathdirs = reverse grep(m!^/!, split(/:/, $ENV{'PATH'}, 999));
! $compressor = "@COMPRESSOR@";
! if ( $compressor =~ "@" . "COMPRESSOR" . "@" ) {
! # hmm, config must not have fixed it, so set it to a default
! $compressor = "bzip2";
! }
!
! @cmds = (
! $compressor,
! "netstat",
! "ls",
! "ctxqsession",
! "prtconf",
! "uptime",
! "ps",
! "pstat",
! "vmstat",
! "df",
! "iostat",
! "svmon");
! if ( "$DOTSM" == "yes" ) {
! @cmds = ( @cmds, "dsmadmc" );
! }
! foreach $cmd ( @cmds ) {
! $cmdvar = "";
! if ( $cmd !~ m:^/: ) {
! # don't have full path yet
! foreach $dir ( @pathdirs ) {
! if (-x "$dir/$cmd") {
! $cmdvar = $cmd . "_cmd";
! $$cmdvar="$dir/$cmd";
! # for "ls", that evalutes to $ls_cmd, so in later
! # code, $ls_cmd will expand to the full path, thus
! # avoiding path traversal overhead
! }
! }
! }
! printf "%20s ", $cmd;
! $$cmdvar ? print "=> $$cmdvar\n" : print "doesn't exist in PATH; Not collecting\n";
!
! }
! #
! ## Autodetect network interfaces
#open IN, "ifconfig -a|";
! open IN, "$netstat_cmd -ni|";
while (<IN>) {
!
! # if ( /^(\S+):/ ) {
! if (/^(\w+).*link/) {
! push @net_interfaces, $1;
! }
}
close IN;
# Grab some base system info prior to collecting stats.
! open IN, "$prtconf_cmd -m |";
while (<IN>) {
! if (/^Memory Size: (\d+) MB/) {
! $pagestotl = $1 * 1024 * 1024 / 4096; # Grab realmem in MB and convert to pages.
! $mem_totl = $1 * 1024 * 1024; # Grab realmem in MB and convert to Bytes
!
! # this gets used down in the vmstat section
! } else {
! print STDERR "ERROR: could not compute memorysize from $prtconf_cmd -m\n";
! $pagestotl = 100;
! $mem_totl = 100;
! }
}
close IN;
## Make sure we can write output.
umask 0022; # make sure the file can be harvested
! unless ( -d $out_dir ) {
! system( "mkdir", "-p", "$out_dir" );
}
# Set signal handlers to close and compress the output
# file just in case.
--- 98,152 ----
## Derived variables.
$iterations = $DURATION * 60 * 60 / $INTERVAL; # Number of checks.
! chomp($HOST = `uname -n`);
$out_dir = "${OUT_ROOT}/${HOST}";
! ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
localtime(time);
$stat_file =
! sprintf("%s/percol-%.2d-%.2d-%.2d-%1d%.2d",
! $out_dir,
! $year + 1900,
! $mon + 1,
! $mday,
! $hour,
! $min);
+ # Base all timestamps on start time.
$start_time = time();
! $timestamp = 0;
! # Auto detect network interfaces
#open IN, "ifconfig -a|";
! open IN, "netstat -ni|";
while (<IN>) {
! # if (/^(\S+):/) {
! if (/^(\w+).*link/) {
! push @net_interfaces, $1;
! }
}
close IN;
# Grab some base system info prior to collecting stats.
! open IN, "lsattr -El sys0 -a realmem |";
while (<IN>) {
! if (/^realmem (\d+) /) {
! $pagestotl = $1 * 1024 / 4096; # Grab realmem in KB and convert to pages.
! $mem_totl = $1 * 1024; # Grab realmem in KB and convert to Bytes.
! # this gets used down in the vmstat section
! }
}
close IN;
## Make sure we can write output.
umask 0022; # make sure the file can be harvested
! unless (-d $out_dir) {
! mkdir($out_dir, 0755)
! or die "$0: cannot mkdir '$out_dir': $!\n";
}
+ open OUT, ">$stat_file" or die "ERROR: Could not open $stat_file: $!";
+ my $oldfh = select OUT;
+ $| = 1;
+ select $oldfh;
# Set signal handlers to close and compress the output
# file just in case.
***************
*** 259,978 ****
$SIG{QUIT} = \&exit_nicely;
$SIG{TERM} = \&exit_nicely;
! # Set gloabals used for printing (or not) headers.
! $need_header = 1; # our file starts empty, so we need a header by default
$prev_header_cnt = 0;
$prev_info_cnt = 0;
! # Set globals used for tracking counts from interval to interval
! # all counts start at zero
! ( $disk_t_prev,
! $disk_rK_prev,
! $disk_wK_prev,
! $citrix_sessions,
! $citrix_disconnect ) = ( 0, 0, 0, 0, 0 );
! #
! # set up a data structure to hold info about each
! # interface, to carry from iteration to iteration,
! # so we can calculate per-second data based on delta
! # of totals between iterations
! #
! %netstat;
! foreach $if (@net_interfaces) {
! %netstat=(%netstat,
! $if => {});
! $netstat{$if}={"ipkt" => -1,
! "ierr" => -1,
! "opkt" => -1,
! "oerr" => -1,
! "coll" => -1};
! }
! $context_sw_prev=0;
! # initialize all vmstat hash keys to -1, in a slick,
! # if mystifying fashion, making it real easy to add
! # more keys later, if need be
! %vmstat;
! # 1 2 3 4 5 6 7 8
! # 9 10 11 12 13 14 15 16 17
! @vmkeys=qw(r b avm fre re pi po fr
! sr cy in sys cs us sy id wa);
! @vmstat{@vmkeys} = (-1) x @vmkeys;
! $vmstat{proc_s} = -1;
! $vmstat{forks} = -1;
! #
! # Main while loop
! while ( $DURATION < 0 || $iterations-- > 0 ) {
! $timestamp = $timestamp ? time() : $start_time;
! ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
! localtime(time);
! $locltime = sprintf( "%.2d:%.2d:%.2d", $hour, $min, $sec );
! ## Get runq data
! $uptime = 0;
! open IN, "$uptime_cmd |";
! # Uptime is really really annoying. Here are the various and sundry formats
! # you might run into over the course of a day:
! # root at npdsa01 </var/tmp><137# uname -a
! # AIX npdsa01 1 5 0025425A4C00
! # root at npdsa01 </var/tmp><133# uptime
! # 04:40PM up 13 days, 50 mins, 17 users, load average: 0.05, 0.12, 0.15
! # dmichael at npdsa01 <orca/AIXorcallator><68> rsh npddev01 uptime
! # 04:41PM up 2 days, 20 hrs, 33 users, load average: 0.58, 0.80, 1.06
! # dmichael at npdsa01 <orca/AIXorcallator><70> rsh npddev01 uptime
! # 04:45PM up 2 days, 20:04, 33 users, load average: 0.52, 0.68, 0.95
! # dmichael at npdsa01 <~><2> uptime
! # 03:48PM up 5:56, 9 users, load average: 0.00, 0.07, 0.16
! # dmichael at npdsa01 <~><102> uptime
! # 04:16PM up 1 day, 6:25, 8 users, load average: 0.00, 0.01, 0.01
! # So, if you want the uptime, we have to parse all these circumstances.
! while (<IN>) {
! # first, get the easy part: load average
! if (/load average:\s+(\S+),\s+(\S+),\s+(\S+)/) {
! $load_info = join "\t", $1, $2, $3;
! }
! # now, get uptime, in various formats:
! if (/up\s+(\d+)\s+day[s]?,\s+(\d+)\s+hrs,\s+(\d+)\s+user[s]?/) {
! # up X days, Y hrs, U users
! $up_day = $1;
! $up_hrs = $2;
! $up_min = 0;
! $nusr = $3;
! } elsif (/up\s+(\d+)\s+day[s]?,\s+(\d+):(\d+),\s+(\d+)\s+user[s]?/) {
! # up X days, H:M, U users
! $up_day = $1;
! $up_hrs = $2;
! $up_min = $3;
! $nusr = $4;
! } elsif (/up\s+(\d+)\s+day[s]?,\s+(\d+)\s+mins,\s+(\d+)\s+user[s]?/) {
! # up X days, M mins, U users
! $up_day = $1;
! $up_hrs = 0;
! $up_min = $2;
! $nusr = $3;
! } elsif (/up\s+(\d+)\s+mins,\s+(\d+)\s+user[s]?/) {
! # up M mins, U users
! $up_day = 0;
! $up_hrs = 0;
! $up_min = $1;
! $nusr = $2;
! } elsif (/up\s+(\d+):(\d+),\s+(\d+)\s+user[s]?/) {
! # up H:M mins, U users
! $up_day = 0;
! $up_hrs = $1;
! $up_min = $2;
! $nusr = $3;
! } elsif (/up\s+(\d+)\s+day[s]?,\s+(\d+)\s+user[s]?/) {
! # up X days, U users
! # this is pretty rare, as it only happens when
! # orca is started on an exact day boundary (it just
! # happened to me!).
! $up_day = $1;
! $up_hrs = 0;
! $up_min = 0;
! $nusr = $2;
! }
! #
! # calculate uptime in seconds
! $uptime = (( $up_day * 24 * 60 ) + ( $up_hrs * 60 ) + ( $up_min )) * 60;
! }
! close IN;
! $load_header = "1runq\t5runq\t15runq";
! $up_header = "uptime\tnusr";
! $up_info = "$uptime\t$nusr";
! if ( scalar( split ' ', $load_header ) != scalar( split ' ', $load_info ) )
! {
! $load_header = '';
! $load_info = '';
! $need_header = 1;
! print STDERR "WARNING: load header does not match load info.\n";
}
! if ( scalar( split ' ', $up_header ) != scalar( split ' ', $up_info ) )
! {
! $up_header = '';
! $up_info = '';
! $need_header = 1;
! print STDERR "WARNING: UP header does not match load info.\n";
! }
! #
! ## Get number of system processes
! $num_proc = -1; # Don't count the header.
! open IN, "$ps_cmd -ek |";
! while (<IN>) {
! $num_proc++;
! }
! close IN;
! $proc_info = "$num_proc";
! $proc_header = '#proc';
! if ( scalar( split ' ', $proc_header ) != scalar( split ' ', $proc_info ) )
! {
! $proc_header = '';
! $proc_info = '';
! $need_header = 1;
! print STDERR "WARNING: #proc header does not match #proc info.\n";
! }
! #
! ## Get pstat data for pages
! $sw_used = 0;
! $sw_free = 0;
! open IN, "$pstat_cmd -s |tail -3 |";
! while (<IN>) {
! @swp = split(/ +/,);
! if (/\d/) {
! $sw_used = $swp[1];
! $sw_free = $swp[2];
! $swap_used = $sw_used * 4096;
! $swap_free = $sw_free * 4096;
! }
! }
! close IN;
! $swap_info = "$swap_used\t$swap_free";
! $swap_header = "\tswap_used\tswap_free";
!
! if ( scalar( split ' ', $swap_header ) !=
! scalar( split ' ', $swap_info ) )
! {
! $swap_header = '';
! $swap_info = '';
! $need_header = 1;
! print STDERR "WARNING: pstat header does not match pstat info.\n";
}
! #
! ## Set up vmstat stuff
! my $inter = $INTERVAL + ( time() - $timestamp );
! my $interfact = ( $uptime - $inter ) * ( $uptime > $inter );
! my %vm_sum_prev = %vmstat;
! my $vm_sum_curr = {};
! #
! ## Get numprocs/sec
! open IN, "$vmstat_cmd -f |";
! while (<IN>) {
! chomp;
! if (/^\s+(\d+) forks/) {
! $vm_sum_curr{forks} = $1;
! if ( $vm_sum_prev{forks} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{proc_s} = ( $vm_sum_curr{forks} - $vm_sum_prev{forks} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{proc_s} = ( $vm_sum_curr{forks} ) / $uptime;
! }
! $vm_sum_prev{forks} = $vm_sum_curr{forks};
! }
! }
! close IN;
! #
! ## Get static/counter-type vm stats
! $inter = $INTERVAL + ( time() - $timestamp );
! $interfact = ( $uptime - $inter ) * ( $uptime > $inter );
! open IN, "$vmstat_cmd -s |";
! while (<IN>) {
! chomp;
! if (/^\s+(\d+) total address trans. faults/) {
! # total address trans. faults
! # Incremented for each occurrence of an address translation
! # page fault. I/O may or may not be required to resolve the
! # page fault. Storage protection page faults (lock misses) are
! # not included in this count.
! } elsif (/^\s+(\d+) page ins/) {
! # page ins
! # Incremented for each page read in by the virtual memory
! # manager. The count is incremented for page ins from page
! # space and file space. Along with the page out statistic,
! # this represents the total amount of real I/O initiated by
! # the virtual memory manager.
! } elsif (/^\s+(\d+) page outs/) {
! # page outs
! # Incremented for each page written out by the virtual memory
! # manager. The count is incremented for page outs to page
! # space and for page outs to file space. Along with the page
! # in statistic, this represents the total amount of real I/O
! # initiated by the virtual memory manager.
! } elsif (/^\s+(\d+) paging space page ins/) {
! # paging space page ins
! # Incremented for VMM initiated page ins from paging space only.
! $vm_sum_curr{pi} = $1;
! if ( $vm_sum_prev{pi} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{pi} = ( $vm_sum_curr{pi} - $vm_sum_prev{pi} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{pi} = ( $vm_sum_curr{pi} ) / $uptime;
! }
! $vm_sum_prev{pi} = $vm_sum_curr{pi};
! } elsif (/^\s+(\d+) paging space page outs/) {
! # paging space outs
! # Incremented for VMM initiated page outs to paging space only.
! $vm_sum_curr{po} = $1;
! if ( $vm_sum_prev{po} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{po} = ( $vm_sum_curr{po} - $vm_sum_prev{po} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{po} = ( $vm_sum_curr{po} ) / $uptime;
! }
! $vm_sum_prev{po} = $vm_sum_curr{po};
! } elsif (/^\s+(\d+) total reclaims/) {
! # reclaims
! # Incremented when an address translation fault can be
! # satisfied without initiating a new I/O request. This can
! # occur if the page has been previously requested by VMM, but
! # the I/O has not yet completed; or if the page was
! # pre-fetched by VMM's read-ahead algorithm, but was hidden
! # from the faulting segment; or if the page has been put on
! # the free list and has not yet been reused.
! } elsif (/^\s+(\d+) zero filled pages faults/) {
! # zero filled pages faults
! # Incremented if the page fault is to working storage and can
! # be satisfied by assigning a frame and zero-filling it.
! } elsif (/^\s+(\d+) executable filled pages faults/) {
! # executable-filled page faults
! # Incremented for each instruction page fault.
! } elsif (/^\s+(\d+) pages examined by clock/) {
! # pages examined by the clock
! # VMM uses a clock-algorithm to implement a pseudo least
! # recently used (lru) page replacement scheme. Pages are aged
! # by being examined by the clock. This count is incremented
! # for each page examined by the clock.
! } elsif (/^\s+(\d+) revolutions of the clock hand/) {
! # revolutions of the clock hand
! # Incremented for each VMM clock revolution (that is, after
! # each complete scan of memory).
! $vm_sum_curr{cy} = $1;
! if ( $vm_sum_prev{cy} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{cy} = ( $vm_sum_curr{cy} - $vm_sum_prev{cy} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{cy} = ( $vm_sum_curr{cy} ) / $uptime;
! }
! $vm_sum_prev{cy} = $vm_sum_prev{cy};
! } elsif (/^\s+(\d+) pages freed by the clock/) {
! # pages freed by the clock
! # Incremented for each page the clock algorithm selects to
! # free from real memory.
! $vm_sum_curr{fr} = $1;
! if ( $vm_sum_prev{fr} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{fr} = ( $vm_sum_curr{fr} - $vm_sum_prev{fr} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{fr} = ( $vm_sum_curr{fr} ) / $uptime;
! }
! $vm_sum_prev{fr} = $vm_sum_prev{fr};
! } elsif (/^\s+(\d+) backtracks/) {
! # backtracks
! # Incremented for each page fault that occurs while resolving
! # a previous page fault. (The new page fault must be resolved
! # first and then initial page faults can be backtracked.)
! } elsif (/^\s+(\d+) lock misses/) {
! # lock misses
! # VMM enforces locks for concurrency by removing
! # addressability to a page. A page fault can occur due to a
! # lock miss, and this count is incremented for each such
! # occurrence.
! } elsif (/^\s+(\d+) free frame waits/) {
! # free frame waits
! # Incremented each time a process is waited by VMM while free
! # frames are gathered.
! } elsif (/^\s+(\d+) extend XPT waits/) {
! # extend XPT waits
! # Incremented each time a process is waited by VMM due to a
! # commit in progress for the segment being accessed.
! } elsif (/^\s+(\d+) pending I\/O waits/) {
! # pending I/O waits
! # Incremented each time a process is waited by VMM for a
! # page-in I/O to complete.
! } elsif (/^\s+(\d+) start I\/Os/) {
! # start I/Os
! # Incremented for each read or write I/O request initiated by
! # VMM. This count should equal the sum of page-ins and
! # page-outs.
! } elsif (/^\s+(\d+) iodones/) {
! # iodones
! # Incremented at the completion of each VMM I/O request.
! } elsif (/^\s+(\d+) cpu context switches/) {
! # CPU context switches
! # Incremented for each CPU context switch (dispatch of a new
! # process).
! $vm_sum_curr{cs} = $1;
! if ( $vm_sum_prev{cs} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{cs} = ( $vm_sum_curr{cs} - $vm_sum_prev{cs} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{cs} = ( $vm_sum_curr{cs} ) / $uptime;
! }
! } elsif (/^\s+(\d+) device interrupts/) {
! # device interrupts
! # Incremented on each hardware interrupt.
! $vm_sum_curr{in} = $1;
! if ( $vm_sum_prev{in} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{in} = ( $vm_sum_curr{in} - $vm_sum_prev{in} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{in} = ( $vm_sum_curr{in} ) / $uptime;
! }
! $vm_sum_prev{in} = $vm_sum_prev{in};
! } elsif (/^\s+(\d+) software interrupts/) {
! # software interrupts
! # Incremented on each software interrupt. A software interrupt
! # is a machine instruction similar to a hardware interrupt
! # that saves some state and branches to a service
! # routine. System calls are implemented with software
! # interrupt instructions that branch to the system call
! # handler routine.
! } elsif (/^\s+(\d+) traps/) {
! # traps
! # Not maintained by the operating system.
! } elsif (/^\s+(\d+) syscalls/) {
! # syscalls
! # Incremented for each system call.
! $vm_sum_curr{sys} = $1;
! if ( $vm_sum_prev{sys} > 0 ) {
! # there already exists a valid "prev", so proceed as normal
! $vm_sum_curr{sys} = ( $vm_sum_curr{sys} - $vm_sum_prev{sys} ) / $inter;
! } else {
! # set up first value as the average-to-date
! $vm_sum_curr{sys} = ( $vm_sum_curr{sys} ) / $uptime;
! }
! $vm_sum_prev{sys} = $vm_sum_prev{sys};
! }
! }
! close IN;
!
! #
! ## Get live vmstat data
! open IN, "$vmstat_cmd 5 2 |";
! my $inter = $INTERVAL + ( time() - $timestamp );
! # convert a given 'count' to 'estimated count before previous
! # interval', with the condition that if we haven't been up for at least
! # an interval, set this value to zero this is used to seed the initial
! # values with something more useful than 0
! while (<IN>) {
! chomp;
! # r b avm fre re pi po fr sr cy inf sysf csf us sy id wa
! # 1 r Number of kernel threads placed in run queue.
! # 2 b Number of kernel threads placed in wait queue (awaiting
! # resource, awaiting input/output).
! #
! # Memory: information about the usage of virtual and real
! # memory. Virtual pages are considered active if they have been
! # accessed. A page is 4096 bytes.
! #
! # 3 avm Active virtual pages.
! # 4 fre Size of the free list.
! # Note: A large portion of real memory is utilized as a cache
! # for file system data. It is not unusual for the size of the
! # free list to remain small.
! #
! # Page: information about page faults and paging activity. These
! # are averaged over the interval and given in units per second.
! #
! # 5 re Pages input/output list.
! # 6 pi Pages paged in from paging space.
! # 7 po Pages paged out to paging space.
! # 8 fr Pages freed (page replacement).
! # 9 sr Pages scanned by page-replacement algorithm.
! # 10 cy Clock cycles by page-replacement algorithm.
! #
! # Faults: trap and interrupt rate averages per second over the
! # sampling interval.
! #
! # 11 in Device interrupts.
! # 12 sy System calls.
! # 13 cs Kernel thread context switches.
! #
! # Cpu: breakdown of percentage usage of CPU time.
! #
! # 14 us User time.
! # 15 sy System time.
! # 16 id CPU idle time.
! # 17 wa CPU idle time during which the system had outstanding disk/NFS I/O
! # request(s). See detailed description above.
! #
! if (/^[\s\d]+$/) {
! # overwrite first line on 2nd pass
! my $vm_curr = {};
! my $info = "";
! # assign %curr{field} values. @vmkeys is
! # an array of field identifiers that should align
! # with the output of the vmstat command
! @vm_curr{@vmkeys} = split;
! foreach $_ ( @vmkeys , proc_s ) {
! # if we already got the data from the summary
! # output (more reliable / accurate), then
! # use that, otherwise, use the values from the
! # vmstat interval run
! $vmstat{$_}=(
! ($vm_sum_curr{$_} > 0 )
! * ( $vm_sum_curr{$_} )
! ||
! $vm_curr{$_} );
! $info = $info . $vmstat{$_} . "\t";
! }
! $vmstat{forks}=$vm_sum_curr{forks};
! # tack on other things not in @vmkeys
! $info = $info . "\t" . $pagestotl;
! $vmstat_info = $info;
! }
}
! close IN;
! $vmstat_header =
! "runque\twaiting\tpagesactive\tfreememK\tPagesIO/s\tPagesI/s\tPagesO/s\tPagesF/s\tscanrate\tcy_cycles\tdevinter\tsyscalls\tcs\tusr%\tsys%\tidle%\twio%\t#proc/s\tpagestotl";
! if ( scalar( split ' ', $vmstat_header ) !=
! scalar( split ' ', $vmstat_info ) )
! {
! print STDERR "WARNING: vmstat header does not match vmstat info.\n";
! print STDERR "header is: $vmstat_header\n";
! print STDERR "header #fields: ", scalar(split ' ', $vmstat_header ), "\n";
! print STDERR "info is : $vmstat_info\n";
! print STDERR "info #fields : ", scalar(split ' ', $vmstat_info), "\n";
! $vmstat_header = '';
! $vmstat_info = '';
! $need_header = 1;
! print STDERR "vmkeys is : ", $#vmkeys, "\n";
! }
! #
! ## Get filesystem data
! $fs_header = '';
! $fs_info = '';
! open IN, "$df_cmd -k -v |";
! while (<IN>) {
! chomp;
!
! if (m%^/dev%) {
! ( $mnt_dev, $blocks, $used, $free, $pct_used, $iused, $ifree,
! $ipct_used, $mnt ) = split;
!
! # Recalculate percents because df rounds.
! $fs_info .= "\t"
! . sprintf( "%s\t%s\t%s\t%.5f\t%d\t%s\t%s\t%.5f", $blocks, $used,
! $free, ( $used / $blocks ) * 100, ( $iused + $ifree ), $iused,
! $ifree, ( $iused / ( $iused + $ifree ) ) * 100 );
! $fs_header .= "\t" . join "\t", "mntC_$mnt", "mntU_$mnt",
! "mntA_$mnt", "mntP_$mnt", "mntc_$mnt", "mntu_$mnt", "mnta_$mnt",
! "mntp_$mnt";
! }
}
! close IN;
! if ( scalar( split ' ', $fs_header ) != scalar( split ' ', $fs_info ) ) {
! $fs_header = '';
! $fs_info = '';
! $need_header = 1;
! print STDERR
! "WARNING: filesystem header does not match filesystem info.\n";
! }
! #
! ## Get iostat data
! $disk_t = 0;
! $disk_rK = 0;
! $disk_wK = 0;
! undef %disks;
! # open IN, "iostat -d 1 2|";
! # iostat totals are useful; running counts are good for
! # interactive observations, but a 1s interval observation
! # isn't representative for 'snapshots'; only total counts are.
! open IN, "$iostat_cmd -s -d|";
! # for accuracy's sake, add on number of seconds
! # since this run started
! my $inter = $INTERVAL + ( time() - $timestamp );
while (<IN>) {
! # if (/^(\S+)\s+\S+\s+\S+\s+(\S+)\s+(\d+)\s+(\d+)/) {
! if (/^\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)/) {
! my $kBs = $1;
! my $tps = $2;
! my $rK = $3;
! my $wK = $4;
! if ( $disk_rK_prev == 0 ) {
! # there is no previous data, so seed with average rates
! # spread over time-since-boot minus specified interval.
! # If uptime < INTERVAL, then we haven't been up long enough
! # to have a (valid) previous interval, so
! # the previous count really is zero.
! $disk_rK_prev = ( $rK / $uptime ) * ( $uptime - $inter ) * ($uptime > $INTERVAL);
! $disk_wK_prev = ( $wK / $uptime ) * ( $uptime - $inter ) * ($uptime > $INTERVAL);
!
! # iostat on AIX only reports transactions per second,
! # to 3 significant figures, not total transactions.
! # So this value is useless; maybe some other AIX utility
! # can grab this, but for now, just keep reporting the
! # running average.
! $disk_t_prev = $tps;
! }
! # calculate reads/writes per second from totals reported by iostat
! $disk_rK = ( $rK - $disk_rK_prev ) / $inter;
! $disk_wK = ( $wK - $disk_wK_prev ) / $inter;
! $disk_t = $tps;
! $disk_rK_prev = $rK;
! $disk_wK_prev = $wK;
! $disk_t_prev = $tps;
! }
}
close IN;
! $iostat_header = "disk_t/s\tdisk_rK/s\tdisk_wK/s";
! $iostat_info = "${disk_t}\t${disk_rK}\t${disk_wK}";
! if ( scalar( split ' ', $iostat_header ) !=
! scalar( split ' ', $iostat_info ) )
! {
! $iostat_header = '';
! $iostat_info = '';
! $need_header = 1;
! print STDERR "WARNING: iostat header does not match iostat info.\n";
! }
!
! #
! ## Get packet data
$packet_header = '';
$packet_info = '';
! foreach $interface (@net_interfaces) {
! $packet_header .=
! "\t${interface}Ipkt/s\t${interface}IErr/s\t${interface}Opkt/s\t${interface}OErr/s\t${interface}Coll/s\t";
! open IN, "$netstat_cmd -n -I $interface 1 |";
! # format looks like
! # input (en0) output input (Total) output
! # packets errs packets errs colls packets errs packets errs colls
! # 492126804 0 255536091 0 0 553459817 0 316872224 0 0
!
! # for accuracy's sake, add on number of seconds
! # since this run started
! my $interv = $INTERVAL + ( time() - $timestamp );
! # make %prev point to %netstat{$interface}, just for readability
! my $prev = %netstat->{$interface};
!
! while (<IN>) {
! if (/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+/) {
! my $ipkt = $1;
! my $ierr = $2;
! my $opkt = $3;
! my $oerr = $4;
! my $coll = $5;
! if ( $prev->{"ipkt"} == -1 ) {
! # haven't populated data yet - extrapolate
! my $extrapolate = sub { ( @_[0] / $uptime ) *
! ( $uptime - $interv ) * ( $uptime > $interv ); };
! # use this funky notation, so that packet_info
! # syntax doesn't depend on instance status
! # of prev (copy or pointer)
! $prev=\%{{ "ipkt" => &$extrapolate($ipkt),
! "ierr" => &$extrapolate($ierr),
! "opkt" => &$extrapolate($opkt),
! "oerr" => &$extrapolate($oerr),
! "coll" => &$extrapolate($coll) }};
! }
! # build packet info line with appropriate rates
! $packet_info .= "\t" . join "\t",
! ( ( $ipkt - $prev->{"ipkt"} ) / $interv ),
! ( ( $ierr - $prev->{"ierr"} ) / $interv ),
! ( ( $opkt - $prev->{"opkt"} ) / $interv ),
! ( ( $oerr - $prev->{"oerr"} ) / $interv ),
! ( ( $coll - $prev->{"coll"} ) / $interv );
! # remember current counts for next iteration calculations
! $netstat{$interface} = { "ipkt" => $ipkt,
! "ierr" => $ierr,
! "opkt" => $opkt,
! "oerr" => $oerr,
! "coll" => $coll};
! # don't care about rest of input, just terminate read loop
! last;
! }
! }
! close IN;
}
! # print "packet header is $packet_header\n";
! # print "packet info is $packet_info\n";
! if ( scalar( split ' ', $packet_header ) !=
! scalar( split ' ', $packet_info ) )
! {
! $packet_header = '';
! $packet_info = '';
! $need_header = 1;
! print STDERR "WARNING: packet header does not match packet info.\n";
! print STDERR "packet header is: ", $packet_header, "\n";
! print STDERR "packet info is: ", $packet_info, "\n";
! }
! #
! ## Get TCP Connection data
! $tcp_estb = 0;
! open IN, "$netstat_cmd -an |";
! while (<IN>) {
! if (/^tcp.+ESTABLISHED$/) {
! $tcp_estb++;
! }
! }
! close IN;
! $tcp_info = $tcp_estb;
! $tcp_header = 'tcp_estb';
! if ( scalar( split ' ', $tcp_estb_header ) !=
! scalar( split ' ', $tcp_estb_info ) )
! {
! $tcp_estb_header = '';
! $tcp_estb_info = '';
! $need_header = 1;
! print STDERR "WARNING: tcp_estb header does not match tcp_estb info.\n";
}
! #
! ## Get TSM Database space usage
! $tsmdb = 0;
! if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
! open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query db' |tail -r -n 5 |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmdb = $fld[8];
! }
! }
! close IN;
! }
! $tsm_info = $tsmdb;
! $tsm_header = "tsmdb\t";
!
! if ( scalar( split ' ', $tsm_header ) !=
! scalar( split ' ', $tsm_info ) )
! {
! $tsm_header = '';
! $tsm_info = '';
! $need_header = 1;
! print STDERR "WARNING: tsmdb header does not match tsmdb info.\n";
! }
!
! #
! ## Get Memory Usage breakup using SVMON
! $mem_work = 0;
! $mem_pres = 0;
! $mem_clnt = 0;
! open IN, "$svmon_cmd -G |tail -2 |";
! while (<IN>) {
! @memp = split(/ +/,);
! if (/use\s+(\d+) /) {
$m_work = $memp[2];
$m_pres = $memp[3];
$m_clnt = $memp[4];
--- 155,450 ----
$SIG{QUIT} = \&exit_nicely;
$SIG{TERM} = \&exit_nicely;
! # Set globals used for printing (or not) headers.
! $need_header = 1;
$prev_header_cnt = 0;
$prev_info_cnt = 0;
! while ($iterations-- > 0) {
! $timestamp = $timestamp ? time() : $start_time;
! ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
! localtime(time);
! $locltime = sprintf("%.2d:%.2d:%.2d", $hour, $min, $sec);
! ## Get runq data
! $uptime = 0;
! open IN, "uptime |";
! while (<IN>) {
! if (/load average:\s+(\S+),\s+(\S+),\s+(\S+)/) {
! $load_info = join "\t", $1, $2, $3;
! }
! @upt = split(/ +/,);
! $uptd = $upt[3];
! $up_day = $uptd * 24 * 60 * 60;
! $up_hrs = 0;
! $up_min = 0;
! if (/day(?:s?),\s+(\S+)\s+min(?:s?),/) {
! $nusr = $upt[7];
! $up_min = $1 * 60;
! } elsif (/day(?:s?),\s+(\S+)\s+hr(?:s?),/) {
! $nusr = $upt[7];
! $up_hrs = $1 * 60 * 60;
! } elsif (/day(?:s?),\s+(\S+):(\S+), /) {
! $nusr = $upt[6];
! $up_hrs = $1 * 60 * 60;
! $up_min = $2 * 60;
! } elsif ($_ !~ /day/) {
! $up_day = 0;
! if (/\s+(\S+):(\S+),/) {
! $nusr = $upt[4];
! $up_hrs = $1 * 60 * 60;
! $up_min = $2 * 60;
! } elsif (/\s+(\S+)\s+min(?:s?),/) {
! $nusr = $upt[5];
! $up_min = $1 * 60;
! } elsif (/\s+(\S+)\s+hr(?:s?),/) {
! $nusr = $upt[5];
! $up_hrs = $1 * 60 * 60;
! }
! } else {
! $nusr = $upt[5];
! }
! $uptime = $up_day + $up_hrs + $up_min;
! }
! close IN;
! $load_header = "1runq\t5runq\t15runq";
! $up_header = "uptime\tnusr";
! $up_info = "$uptime\t$nusr";
! unless (strings_have_same_number_words($load_header, $load_info)) {
! $load_header = '';
! $load_info = '';
! $need_header = 1;
! warn "$0: warning: load header does not match load info.\n";
! }
! unless (strings_have_same_number_words($up_header, $up_info)) {
! $up_header = '';
! $up_info = '';
! $need_header = 1;
! warn "$0: warning: UP header does not match load info.\n";
! }
+ ## Get number of system processes
+ $num_proc = -1; # Don't count the header.
+ open IN, "ps -ek |";
+ while (<IN>) {
+ $num_proc++;
+ }
+ close IN;
+ $proc_info = $num_proc;
+ $proc_header = '#proc';
! unless (strings_have_same_number_words($proc_header, $proc_info)) {
! $proc_header = '';
! $proc_info = '';
! $need_header = 1;
! warn "$0: warning: #proc header does not match #proc info.\n";
! }
! ## Get pstat data for pages
! $sw_used = 0;
! $sw_free = 0;
! open IN, "pstat -s |tail -3 |";
! while (<IN>) {
! @swp = split(/ +/,);
! if (/\d/) {
! $sw_used = $swp[1];
! $sw_free = $swp[2];
! $swap_used = $sw_used * 4096;
! $swap_free = $sw_free * 4096;
}
! }
! close IN;
! $swap_info = "$swap_used\t$swap_free";
! $swap_header = "\tswap_used\tswap_free";
! unless (strings_have_same_number_words($swap_header, $swap_info)) {
! warn "$0: warning: pstat header does not match pstat info.\n";
! $swap_header = '';
! $swap_info = '';
! $need_header = 1;
! }
! ## Get vmstat data
! open IN, "vmstat 1 2|";
! while (<IN>) {
! chomp;
! if (/^[\s\d]+$/) {
! # overwrite first line on 2nd pass
! my ($vmstat_r, $vmstat_b, $vmstat_avm, $vmstat_fre,
! $vmstat_re, $vmstat_pi, $vmstat_po, $vmstat_fr,
! $vmstat_sr, $vmstat_cy, $vmstat_inf, $vmstat_syf,
! $vmstat_csf, $vmstat_us, $vmstat_sy, $vmstat_id,
! $vmstat_wa)
! = split;
! $vmstat_info = join("\t",
! $vmstat_r, $vmstat_b, $vmstat_avm, $vmstat_fre,
! $pagestotl, $vmstat_pi, $vmstat_po, $vmstat_fr,
! $vmstat_sr, $vmstat_us, $vmstat_sy, $vmstat_wa,
! $vmstat_id);
}
+ }
+ close IN;
+ $vmstat_header = "runque\twaiting\tpagesactive\tpagesfree\tpagestotl\t" .
+ "PagesI/s\tPagesO/s\tPagesF/s\tscanrate\tusr%\tsys%\t" .
+ "wio%\tidle%";
! unless (strings_have_same_number_words($vmstat_header, $vmstat_info)) {
! warn "$0: warning: vmstat header does not match vmstat info.\n";
! $vmstat_header = '';
! $vmstat_info = '';
! $need_header = 1;
! }
! ## Get filesystem data
! $fs_header = '';
! $fs_info = '';
! open IN, "df -k -v |";
! while (<IN>) {
! chomp;
! if (m%^/dev%) {
! my ($mnt_dev, $blocks, $used, $free, $pct_used, $iused, $ifree,
! $ipct_used, $mnt) = split;
! # Recalculate percents because df rounds.
! $fs_info .= "\t"
! . sprintf("%s\t%s\t%s\t%.5f\t%d\t%s\t%s\t%.5f",
! $blocks,
! $used,
! $free,
! 100*($used/$blocks),
! ($iused + $ifree),
! $iused,
! $ifree,
! 100*$iused/($iused + $ifree));
! $fs_header .= "\t" . join("\t",
! "mntC_$mnt", "mntU_$mnt", "mntA_$mnt",
! "mntP_$mnt", "mntc_$mnt", "mntu_$mnt",
! "mnta_$mnt", "mntp_$mnt");
}
! }
! close IN;
! unless (strings_have_same_number_words($fs_header, $fs_info)) {
! warn "$0: warning: filesystem header does not match filesystem info.\n";
! $fs_header = '';
! $fs_info = '';
! $need_header = 1;
! }
! ## Get iostat data
! $disk_t = 0;
! $disk_rK = 0;
! $disk_wK = 0;
! undef %disks;
! open IN, "iostat -d 1 2|";
! while (<IN>) {
! if (/^(\S+)\s+\S+\s+\S+\s+(\S+)\s+(\d+)\s+(\d+)/) {
! my $disk = $1;
! my $tps = $2;
! my $rK = $3;
! my $wK = $4;
! if (not $disks{$disk}) {
! $disks{$disk}++; # Get rK & wK from first pass.
! $disk_rK += $rK;
! $disk_wK += $wK;
! } else {
! $disk_t += $tps; # Get trans per sec from second pass.
! }
}
! }
! close IN;
! $iostat_header = "disk_t/s\tdisk_rK/s\tdisk_wK/s\t";
! $iostat_info = "${disk_t}\t${disk_rK}\t${disk_wK}";
! unless (strings_have_same_number_words($iostat_header, $iostat_info)) {
! warn "$0: warning: iostat header does not match iostat info.\n";
! $iostat_header = '';
! $iostat_info = '';
! $need_header = 1;
! }
! ## Get packet data
! $packet_header = '';
! $packet_info = '';
! #foreach $interface (split(/\s+/, $NET_INTERFACES)) {
! foreach $interface (@net_interfaces) {
! $packet_header .= "\t${interface}Ipkt/s\t${interface}IErr/s\t" .
! "${interface}Opkt/s\t${interface}OErr/s\t" .
! "${interface}Coll/s\t";
+ open IN, "netstat -n -I $interface 1|";
while (<IN>) {
! if (/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+/) {
! $packet_info .= "\t" . join("\t", $1, $2, $3, $4, $5);
! last;
! }
}
close IN;
! }
! unless (strings_have_same_number_words($packet_header, $packet_info)) {
! warn "$0: warning: packet header does not match packet info.\n";
$packet_header = '';
$packet_info = '';
+ $need_header = 1;
+ }
! ## Get TCP Connection data
! $tcp_estb = 0;
! open IN, "netstat -an |";
! while (<IN>) {
! if (/^tcp.+ESTABLISHED$/) {
! $tcp_estb++;
}
+ }
+ close IN;
! $tcp_info = $tcp_estb;
! $tcp_header = 'tcp_estb';
! unless (strings_have_same_number_words($tcp_estb_header, $tcp_estb_info)) {
! warn "$0: warning: tcp_estb header does not match tcp_estb info.\n";
! $tcp_estb_header = '';
! $tcp_estb_info = '';
! $need_header = 1;
! }
! ## Get TSM Database space usage
! $tsmdb = 0;
! open IN, "dsmadmc -id=view -password=view 'query db' |tail -r -n 5 |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmdb = $fld[8];
}
+ }
+ close IN;
+ $tsm_info = $tsmdb;
+ $tsm_header = "tsmdb\t";
! unless (strings_have_same_number_words($tsm_header, $tsm_info)) {
! warn "$0: warning: tsmdb header does not match tsmdb info.\n";
! $tsm_header = '';
! $tsm_info = '';
! $need_header = 1;
! }
! ## Get Memory Usage breakup using SVMON
! $mem_work = 0;
! $mem_pres = 0;
! $mem_clnt = 0;
! open IN, "svmon -G |tail -2 |";
! while (<IN>) {
! @memp = split(/ +/,);
! if (/use\s+(\d+) /) {
$m_work = $memp[2];
$m_pres = $memp[3];
$m_clnt = $memp[4];
***************
*** 979,1302 ****
$mem_work = $m_work * 4096;
$mem_pres = $m_pres * 4096;
$mem_clnt = $m_clnt * 4096;
- }
}
! close IN;
! $mem_info = "$mem_work\t$mem_pres\t$mem_clnt\t$mem_totl";
! $mem_header = "mem_work\tmem_pres\tmem_clnt\tmem_totl";
! if ( scalar( split ' ', $mem_header ) !=
! scalar( split ' ', $mem_info ) )
! {
! $mem_header = '';
! $mem_info = '';
! $need_header = 1;
! print STDERR "WARNING: memory header does not match memory info.\n";
! }
! #
! ## Get TSM Tape Drive usage
! $rmt = 0;
! $rmt5 = 5;
! if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
! open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query mount' |grep matches |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! $rmt = $fld[1];
! }
! }
! close IN;
! }
! $tsm_rmt_header = "rmt5\trmt\t";
! $tsm_rmt_info = "$rmt5\t$rmt";
! if ( scalar( split ' ', $tsm_rmt_header ) !=
! scalar( split ' ', $tsm_rmt_info ) )
! {
! print STDERR "WARNING: TSM RMT header does not match TSM RMT info.\n";
! $tsm_rmt_header = '';
! $tsm_rmt_info = '';
! $need_header = 1;
}
! #
! ## Get TSM Recovery Log space usage
! $tsmlog = 0;
! if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
! open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query log' |tail -r -n 4 |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmlog = $fld[8];
! }
! }
! close IN;
! }
! $tsm_log_info = $tsmlog;
! $tsm_log_header = 'tsmlog';
! if ( scalar( split ' ', $tsm_log_header ) !=
! scalar( split ' ', $tsm_log_info ) )
! {
! print STDERR "WARNING: TSM Log header ($tsm_log_header) does not match TSM Log info ($tsm_log_info).\n";
! $tsm_log_header = '';
! $tsm_log_info = '';
! $need_header = 1;
}
! #
! ## Get TSM Tape usage
! $tsmpvt = 0;
! $tsmscr = 0;
! $tsmvlt = 0;
! if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
! open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query libvol' | grep 'Private' | wc -l |";
! while (<IN>) {
! chomp;
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmpvt = $fld[1];
! }
! }
! close IN;
! open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query libvol' | grep 'Scratch' | wc -l |";
! while (<IN>) {
! chomp;
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmscr = $fld[1];
! }
! }
! close IN;
!
! open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query drmedia' | grep 'Vault' | wc -l |";
! while (<IN>) {
! chomp;
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmvlt = $fld[1];
! }
! }
}
! $tsm_tape_info = join "\t", $tsmpvt, $tsmscr, $tsmvlt;
! $tsm_tape_header = join "\t", tsmpvt, tsmscr, tsmvlt;
!
! if ( scalar( split ' ', $tsm_tape_header ) !=
! scalar( split ' ', $tsm_tape_info ) )
! {
! print STDERR "WARNING: TSM Tape header does not match TSM Tape info.\n";
! $tsm_tape_header = '';
! $tsm_tape_info = '';
! $need_header = 1;
}
! #
! ## Get TSM Disk Storage Pool usage
! $tsmphcy = 0;
! $tsmphcn = 0;
! if ( -e $dsmadmc_cmd && -x $dsmadmc_cmd ) {
! open IN, "$dsmadmc_cmd -id=$TSMID -password=$TSMPW 'query stgpool' |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! if ( $fld[0] eq "PHCYDISKPO-" ) {
! $tsmphcy = $fld[3];
! }
! elsif ( $fld[0] eq "PHCNDISKPO-" ) {
! $tsmphcn = $fld[3];
! }
! }
! }
! close IN;
}
! $tsm_stg_info = join "\t", $tsmphcy, $tsmphcn;
! $tsm_stg_header = join "\t", tsmphcy, tsmphcn;
! if ( scalar( split ' ', $tsm_stg_header ) !=
! scalar( split ' ', $tsm_stg_info ) )
! {
! print STDERR "WARNING: TSM Storage Pool header does not match TSM Storage Pool info.\n";
! $tsm_stg_header = '';
! $tsm_stg_info = '';
! $need_header = 1;
! }
! #
! ## Get runq data
! if ( $ctxqsession_cmd == "" ) {
! $ctxqsession_cmd="/usr/lpp/CTXSmf/bin/ctxqsession";
}
! $citrix_sessions=0;
! $citrix_disconnect=0;
! if ( -e $ctxqsession_cmd && -x $ctxqsession_cmd ) {
! open IN, "$ctxqsession_cmd |";
! while (<IN>) {
! if ( /tcp\#/ ) {
! $citrix_sessions++;
! }
! if ( /\sdisc\s/ ) {
! $citrix_disconnect++;
! }
! }
! close IN;
! }
! $citrix_info = join "\t", $citrix_sessions, $citrix_disconnect;
! $citrix_header = join "\t", ctx_sess, ctx_disc;
! #
! ## construct our header
! $out_header = join "\t", "timestamp", "locltime", $load_header, $up_header,
! $proc_header, $vmstat_header, $fs_header, $iostat_header, $packet_header,
! $tcp_header, $tsm_header, $swap_header, $mem_header, $tsm_rmt_header,
! $tsm_log_header, $tsm_tape_header, $tsm_stg_header, $citrix_header;
! $out_header =~ tr/ \t/\t/s; # translate whitespace to single tabs
! ## construct a line of data
! $out_info = join "\t", $timestamp, $locltime, $load_info, $up_info, $proc_info,
! $vmstat_info, $fs_info, $iostat_info, $packet_info, $tcp_info, $tsm_info,
! $swap_info, $mem_info, $tsm_rmt_info, $tsm_log_info, $tsm_tape_info,
! $tsm_stg_info, $citrix_info;
! $out_info =~ tr/ \t/\t/s; # translate whitespace to single tabs
! # count the fields in header and info lines--make sure the counts match.
! $header_cnt = split ' ', $out_header;
! $info_cnt = split ' ', $out_info;
! if ( $header_cnt != $info_cnt ) {
! # oh, dear! How did this happen? Bad code! No biscuit!
! # somehow we collected more (or less) data than we have columns for.
! # That's bad, Ray.
! print STDERR
! "ERROR: header columns do not equal data columns. Exiting.\n";
! &exit_nicely;
! }
! #
! if ( $need_header == 1 ) {
! # If we did things right,
! # The only way we get here is if it's the first line of the output file,
! # or if we already know of a header change, such as if TSM spewed,
! # or new filesystems were mounted, or dismounted, or .....
! # In any of these cases, we'll be creating a new output file anyway,
! # so just let things happen.
! } elsif ( $prev_header != $out_header ) {
! # the header changed. Time for a new file.
! $need_header = 1;
! } elsif ( $header_cnt != $prev_header_cnt or $info_cnt != $prev_info_cnt ) {
! # crazy -- the previous count and the current count don't match,
! # so we must have different headers, which should have been caught
! # in the header comparison above, but apparently not.
! $need_header = 1;
! }
! $prev_header = $out_header;
! $prev_header_cnt = $header_cnt;
! $prev_info_cnt = $info_cnt;
! #
! ## Check to see if we've crossed days,
! ## or if we need a new header.
! ## In either case, we need a new file.
! #
! ( $nsec, $nmin, $nhour, $nmday, $nmon, $nyear, $nwday, $nyday, $nisdst ) =
! localtime(time);
! if ( ($nyear*1000 + $nyday) > ($oyear*1000 + $oyday) ) {
! # hey, we crossed days. Be nice--open a new file, to keep the
! # existing file from getting stupid-big. Note that
! # creating a new output file automatically sets need_header to 1.
! &new_output_file;
! } elsif ( $need_header ) {
! # We didn't switch days yet, but we still need a new header for various
! # possible reasons. So make a new output file (always need a new
! # output file whenever we need a new header--even the first time!)
! &new_output_file;
! }
! # Can't imagine how we'd get here without creating an output file.
! # But, here's the code for creating it, just in case.
! # if (! select OUT) {
! # open OUT, ">$stat_file" or die "ERROR: Could not open $stat_file: $!";
! # my $oldfh = select OUT;
! # $| = 1;
! # select $oldfh;
! # }
! ## Write output
! if ($need_header) {
! print OUT $out_header, "\n";
! $need_header = 0;
! }
! print OUT $out_info, "\n";
! # use this for testing, to speed things along.
! #sleep 5;
! sleep $INTERVAL - ( time() - $timestamp );
}
! &exit_nicely;
!
!
! ######################################################################
! #
! # subroutines
! #
!
! #
! ##################################################
! # exit_nicely ()
! # This subroutine is called by the signal handler, or at the end
! # of the while loop, if ever reached.
! #
! # It takes no arguments, and does not return - it simply exits
! # the fork it's running under.
sub exit_nicely {
! if ( <OUT> ) {
! close OUT;
! @args = split(' ',$compressor);
! push @args, "$stat_file";
! print @args, "\n";
! system(@args);
! }
! exit 0;
}
-
- #
- ##################################################
- # new_output_file ()
- #
- # Whenever a new header is needed, or if we change
- # days, then do the following:
- # o close previous output file
- # o fork a process to compress it
- # o create a new output file
- #
- sub new_output_file {
- if ( <OUT> ) {
- close OUT;
- }
- ( $osec, $omin, $ohour, $omday, $omon,
- $oyear, $owday, $oyday, $oisdst ) = localtime(time);
- # close & compress file in background process
- # create new file & continue in current process
- if ( $pid = fork ) {
- # parent process resumes here
- $stat_file =
- sprintf( "%s/percol-%.2d-%.2d-%.2d-%.2d%.2d%.2d",
- $out_dir, $oyear + 1900, $omon + 1,
- $omday, $ohour, $omin, $osec );
- open OUT, ">$stat_file" or die "ERROR: Could not open $stat_file: $!";
- my $oldfh = select OUT;
- $| = 1;
- select $oldfh;
- $need_header = 1;
- } elsif (defined $pid) {
- # child process resumes here
- &exit_nicely;
- }
- }
-
-
--- 451,640 ----
$mem_work = $m_work * 4096;
$mem_pres = $m_pres * 4096;
$mem_clnt = $m_clnt * 4096;
}
! }
! close IN;
! $mem_info = "$mem_work\t$mem_pres\t$mem_clnt\t$mem_totl";
! $mem_header = "mem_work\tmem_pres\tmem_clnt\tmem_totl";
! unless (strings_have_same_number_words($mem_header, $mem_info)) {
! warn "$0: warning: memory header does not match memory info.\n";
! $mem_header = '';
! $mem_info = '';
! $need_header = 1;
! }
! ## Get TSM Tape Drive usage
! $rmt = 0;
! $rmt5 = 5;
! open IN, "dsmadmc -id=view -password=view 'query mount' |grep matches |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! $rmt = $fld[1];
}
+ }
+ close IN;
+ $tsm_rmt_header = "rmt5\trmt\t";
+ $tsm_rmt_info = "$rmt5\t$rmt";
! unless (strings_have_same_number_words($tsm_rmt_header, $tsm_rmt_info)) {
! warn "$0: warning: TSM RMT header does not match TSM RMT info.\n";
! $tsm_rmt_header = '';
! $tsm_rmt_info = '';
! $need_header = 1;
! }
! ## Get TSM Recovery Log space usage
! $tsmdb = 0;
! open IN, "dsmadmc -id=view -password=view 'query log' |tail -r -n 4 |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmlog = $fld[8];
}
+ }
+ close IN;
+ $tsm_log_info = $tsmlog;
+ $tsm_log_header = 'tsmlog';
! unless (strings_have_same_number_words($tsm_log_header, $tsm_log_info)) {
! warn "$0: warning: TSM Log header does not match TSM Log info.\n";
! $tsm_log_header = '';
! $tsm_log_info = '';
! $need_header = 1;
! }
! ## Get TSM Tape usage
! $tsmpvt = 0;
! open IN, "dsmadmc -id=view -password=view 'query libvol' | grep 'Private' | wc -l |";
! while (<IN>) {
! chomp;
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmpvt = $fld[1];
}
+ }
+ close IN;
! $tsmscr = 0;
! open IN, "dsmadmc -id=view -password=view 'query libvol' | grep 'Scratch' | wc -l |";
! while (<IN>) {
! chomp;
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmscr = $fld[1];
}
+ }
+ close IN;
! $tsmvlt = 0;
! open IN, "dsmadmc -id=view -password=view 'query drmedia' | grep 'Vault' | wc -l |";
! while (<IN>) {
! chomp;
! @fld = split(/ +/,);
! if (/\d/) {
! $tsmvlt = $fld[1];
}
+ }
! $tsm_tape_header = join("\t", 'tsmpvt', 'tsmscr', 'tsmvlt');
! $tsm_tape_info = join("\t", $tsmpvt, $tsmscr, $tsmvlt);
! unless (strings_have_same_number_words($tsm_tape_header, $tsm_tape_info)) {
! warn "$0: warning: TSM Tape header does not match TSM Tape info.\n";
! $tsm_tape_header = '';
! $tsm_tape_info = '';
! $need_header = 1;
! }
! ## Get TSM Disk Storage Pool usage
! $tsmphcy = 0;
! $tsmphcn = 0;
! open IN, "dsmadmc -id=view -password=view 'query stgpool' |";
! while (<IN>) {
! @fld = split(/ +/,);
! if (/\d/) {
! if ($fld[0] eq "PHCYDISKPO-") {
! $tsmphcy = $fld[3];
! } elsif ($fld[0] eq "PHCNDISKPO-") {
! $tsmphcn = $fld[3];
! }
}
! }
! close IN;
! $tsm_stg_header = join("\t", 'tsmphcy', 'tsmphcn');
! $tsm_stg_info = join("\t", $tsmphcy, $tsmphcn);
! unless (strings_have_same_number_words($tsm_stg_header, $tsm_stg_info)) {
! warn "$0: warning: TSM Storage Pool header does not match ",
! "TSM Storage Pool info.\n";
! $tsm_stg_header = '';
! $tsm_stg_info = '';
! $need_header = 1;
! }
! ## Join header and info then verify column counts.
! $out_header = join("\t",
! "timestamp", "locltime", $load_header, $up_header,
! $proc_header, $vmstat_header, $fs_header, $iostat_header,
! $packet_header, $tcp_header, $tsm_header, $swap_header,
! $mem_header, $tsm_rmt_header, $tsm_log_header,
! $tsm_tape_header, $tsm_stg_header);
! $out_header =~ tr/ \t/\t/s; # translate whitespace to single tabs
! $out_info = join("\t",
! $timestamp, $locltime, $load_info, $up_info, $proc_info,
! $vmstat_info, $fs_info, $iostat_info, $packet_info,
! $tcp_info, $tsm_info, $swap_info, $mem_info, $tsm_rmt_info,
! $tsm_log_info, $tsm_tape_info, $tsm_stg_info);
! $out_info =~ tr/ \t/\t/s; # translate whitespace to single tabs
! my @out_header = split ' ', $out_header;
! my @out_info = split ' ', $out_info;
! $header_cnt = @out_header;
! $info_cnt = @out_info;
! if ($header_cnt != $info_cnt) {
! warn "ERROR: header columns do not equal data columns. Exiting.\n";
! &exit_nicely;
! } elsif ($header_cnt != $prev_header_cnt or $info_cnt != $prev_info_cnt) {
! $need_header = 1;
! }
! $prev_header_cnt = $header_cnt;
! $prev_info_cnt = $info_cnt;
! ## Write output
! if ($need_header) {
! print OUT $out_header, "\n";
! $need_header = 0;
! }
! print OUT $out_info, "\n";
! if ($iterations) {
! sleep($INTERVAL - (time() - $timestamp));
! }
! }
! close OUT;
! @args = ($COMPRESS, "-f", $stat_file);
! system(@args);
! exit 0;
+ # Subroutine to that tests if two strings have the same number of
+ # whitespace separated words.
+ sub strings_have_same_number_words {
+ my @words1 = split(' ', $_[0]);
+ my @words2 = split(' ', $_[1]);
+ scalar @words1 == scalar @words2;
}
! # This subroutine is called by the signal handler.
sub exit_nicely {
! close OUT;
! @args = ($COMPRESS, "-f", $stat_file);
! system(@args);
! exit 0;
}
More information about the Orca-dev
mailing list