#!/opt/casp/tools/bin/linux2/perl5/bin/perl -I/opt/casp/tools/bin/linux2/perl5/lib -I/opt/casp use INSTALL::common; use INSTALL::global; use INSTALL::parameter; use INSTALL::os; use INSTALL::webserver; use INSTALL::process_info; use strict; my $pParameters = \%INSTALL::parameter::variables; my $pOS = \%INSTALL::os::Details; my $CONST_Counters = 19; my @CONST_CounterNames = ("Total requests", "Total script errors", "Errors per second", "Current requests", "Executing requests", "Total timed-out requests", "Requests per second", "Current sessions", "Total timed-out sessions", "Thread count", "Total request bytes in", "Total request bytes out", "Total request execute time", "Total request wait time", "Total cached script engines", "Total cached scripts", "Current vhost count", "Threads in use", undef ); my @CONST_CounterDisplay = (0, 1, #2, #3, #4, 5, 6, 7, 8, #10, #11, #12, #13, 14, 15, 16, 9, (($pOS->{os} =~ /Linux/i) ? 17 : ()), #18 ); my @CONST_JoinMethods = ("Add", "Avg", ); my @CONST_CountersJoinMethod = ( "Add", "Add", "Avg", "Add", "Add", "Add", "Avg", "Add", "Add", "Add", "Add", "Add", "Add", "Add", "Add", "Add", "Add", "Add", "Add", ); sub display_statistics { (@_ == 1) || (@_ == ($CONST_Counters + 1)) || die "Invalid number of arguments."; my ($header, @statistics) = @_; if (@statistics) { my $maxlength = 0; foreach (@CONST_CounterDisplay) { my $length = length($CONST_CounterNames[$_]); if ($length > $maxlength) { $maxlength = $length; } } print "$header:\n"; foreach (@CONST_CounterDisplay) { my $trailing = " " x ($maxlength - length($CONST_CounterNames[$_]) + 8); print(" $CONST_CounterNames[$_]:$trailing$statistics[$_]\n"); } print "\n"; } else { print "$header: Not currently running.\n\n"; } } sub join_statistics { my @total; foreach my $pStats (@_) { for(my $i=0; $i<$CONST_Counters; $i++) { $total[$i] += $pStats->[$i]; } } my $divisor = scalar(@_); for(my $i=0; $i<$CONST_Counters; $i++) { if ($CONST_CountersJoinMethod[$i] eq "Avg") { $total[$i] /= $divisor; } } return(@total); } sub gather_statistics { ($#_ == 0) || die "Invalid number of arguments."; my ($engine) = @_; local *CASPCNFG; if (open(CASPCNFG,"<$engine/casp.cnfg")) { my $port; foreach() { if (/^\s*portnumber\s*=\s*([0-9]+)/) { $port = $1; last; } } close(CASPCNFG); if (not defined $port) { error("Invalid casp.cnfg: $engine/casp.cnfg"); goto GATHER_ERROR; } my $psm_file = "/tmp/.casp$port/chili-psm"; if (-f $psm_file) { local *CHILI_PSM; if (open(CHILI_PSM,"<$psm_file")) { my $stats_size = (4*$CONST_Counters); # Seek to the beginning of the counters. seek(CHILI_PSM,-$stats_size,2); my $binary_stats; my @result; if (read(CHILI_PSM,$binary_stats,$stats_size) == $stats_size) { my $unpack_pattern = "L" x $CONST_Counters; @result = unpack($unpack_pattern,$binary_stats); } close(CHILI_PSM); if (@result) { return(@result); } } } } GATHER_ERROR: return(wantarray ? () : undef); } #============================================================================== #------------------------ Default global values #============================================================================== my $pGlobals = \%INSTALL::global::variables; sub usage { report("Usage: perfmon engine= []"); report(" perfmon engines=,,... []"); report(""); report("Options:"); report(" ", "loop=|-1 Loop time (if -1, endless loop).", "sleep= Sleep seconds between each loop.", "mode=separate|combined Display each engine separately or combined.", "display=terminal|tty Display to terminal or tty", " (tty omits clearing the screen)", # "display=terminal|tty|admin Display to terminal or to admin console.", "" ); report("Defaults:"); report(" ", "loop=1", "sleep=1", "mode=separate", # "display=terminal", "" ); report("Example: $0 engine=/opt/casp/asp-apache-3000 loop=-1"); } my @required_params = ("engine(s)?"); my @optional_params = ("loop", "sleep", "mode", "display"); if (($#ARGV < 0) || ((grep { my $pattern = join("|",@required_params); /^$pattern$/ } keys %{$pParameters}) != @required_params) || (grep { my $pattern = join("|",@required_params,@optional_params); $_ !~ /^$pattern$/ } keys %{$pParameters})) { usage; exit(1); } my @engines; if (exists $pParameters->{engine}) { push @engines, $pParameters->{engine}; } if (exists $pParameters->{engines}) { push @engines,split(/\s*,\s*/,$pParameters->{engines}); } foreach my $engine (@engines) { if ((not -d $engine) || (not -f "$engine/casp.cnfg")) { exit(not error("Invalid engine directory specified: $engine")); } } $SIG{INT} = "DEFAULT"; my @CONST_Modes = ("combined", "separate" ); my $mode = "separate"; if (exists $pParameters->{mode}) { my $mode_pattern = join("|",@CONST_Modes); if ($pParameters->{mode} !~ /^\s*($mode_pattern)\s*$/) { error("Invalid mode specifed: $pParameters->{mode}."); } else { $mode = $pParameters->{mode}; } } my @CONST_Displays = ("terminal", "tty", "admin" ); my $display = "terminal"; if (exists $pParameters->{display}) { my $display_pattern = join("|",@CONST_Displays); if ($pParameters->{display} !~ /^\s*($display_pattern)\s*$/) { error("Invalid display specifed: $pParameters->{display}."); } else { $display = $pParameters->{display}; } } my $sleep = (exists $pParameters->{sleep} && ($pParameters->{sleep} > 0)) ? $pParameters->{sleep} : 1; my $loop = (exists $pParameters->{loop}) ? $pParameters->{loop} : 1; @engines = realpath(@engines); while($loop) { if ($mode eq "separate") { foreach my $engine (@engines) { my @statistics = gather_statistics($engine); unless($display eq "admin") { if ($display eq "terminal") { system("clear"); } print("Current Time: ",scalar(localtime(time)),"\n"); display_statistics($engine,@statistics); } else { print pack("L" x scalar(@statistics),@statistics); } } } elsif ($mode eq "combined") { my @statistics = join_statistics(map([gather_statistics($_)],@engines)); if ($display eq "terminal") { system("clear"); print("Current Time: ",scalar(localtime(time)),"\n"); print "Combined statistics\n"; display_statistics(join(", ",@engines),@statistics); } else { print pack("L" x scalar(@statistics),@statistics); } } if ($loop > 0) { $loop--; } if ($loop) { sleep($sleep); } }