# The contents of this file are subject to the Netscape Public # License Version 1.1 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at http://www.mozilla.org/NPL/ # # Software distributed under the License is distributed on an "AS # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or # implied. See the License for the specific language governing # rights and limitations under the License. # # The Original Code is the Netscape Mailstone utility, # released March 17, 2000. # # The Initial Developer of the Original Code is Netscape # Communications Corporation. Portions created by Netscape are # Copyright (C) 1997-2000 Netscape Communications Corporation. All # Rights Reserved. # # Contributor(s): Dan Christian # Marcel DePaolis # # Alternatively, the contents of this file may be used under the # terms of the GNU Public License (the "GPL"), in which case the # provisions of the GPL are applicable instead of those above. # If you wish to allow use of your version of this file only # under the terms of the GPL and not to allow others to use your # version of this file under the NPL, indicate your decision by # deleting the provisions above and replace them with the notice # and other provisions required by the GPL. If you do not delete # the provisions above, a recipient may use your version of this # file under either the NPL or the GPL. ##################################################### # This file deals with the summary data only # Should be packages do 'genplot.pl' || die "$@\n"; sub walkSetupTotals { my $a = shift; my $f = shift; my $p = shift; if ($p =~ /(\w+):(\w+):$/) { my $tm = $2; if (!($finals{Total}->{$tm}->{$f})) { $finals{Total}->{$tm}->{$f} = $a; } elsif ($f =~ /Min$/) { $finals{Total}->{$tm}->{$f} = $a if (($a > 0.0) && ($a < $finals{Total}->{$tm}->{$f})); } elsif ($f =~ /Max$/) { $finals{Total}->{$tm}->{$f} = $a if ($a > $finals{Total}->{$tm}->{$f}); } else { $finals{Total}->{$tm}->{$f} += $a;} } elsif ($p =~ /(\w+):$/) { $finals{Total}->{$f} += $a; } } sub setupTotals { # Figure out combined timers for "Total" protocol # We might do a smarter merge here (look at context and try to match order) # As long as the first protocol is a superset, it wont matter my @tnames; foreach $proto (@protocols) { foreach $n (@{$protocolFields{$proto}}) { my $t = $n; $t =~ s/([][{}*+?^.\/])/\\$1/g; # quote regex syntax my $found = 0; foreach $tn (@tnames) { # see if it is in the list already next unless ($tn =~ /$t/); $found = 1; last; } #print "proto $proto: Found $n\n" if ($found > 0); next if ($found > 0); #print "proto $proto: Add $n\n"; push @tnames, $n; # add to list } } #print "'Total' timers @tnames\n"; $protocolFields{"Total"} = \@tnames; # Create "Total" hashes $finals{Total} = ArrayInstance->new(); foreach $n (@{$protocolFields{"Total"}}) { # all timers my $t = $n; # dont modify original list if ($t =~ /^\[(\w+)\]$/) { # Timer case, strip off brackets $finals{Total}->{$1} = ArrayInstance->new(); #print "Creating Total timer field $1\n"; } else { # scalar $finals{Total}->{$n} = 0; #print "Creating Total scalar field $n\n"; } } # Total finals array foreach $proto (@protocols) { foreach $t (@{$protocolFields{$proto}}) { if ($t =~ /^\[(\w+)\]$/) { # Timer case, strip off brackets my $tm = $1; foreach $f (@timerFieldsAll) { my $a = $finals{$proto}->{$tm}->{$f}; if (!($finals{Total}->{$tm}->{$f})) { # never touched $finals{Total}->{$tm}->{$f} = $a; } elsif ($f =~ /Min$/) { $finals{Total}->{$tm}->{$f} = $a if (($a > 0.0) && ($a < $finals{Total}->{$tm}->{$f})); } elsif ($f =~ /Max$/) { $finals{Total}->{$tm}->{$f} = $a if ($a > $finals{Total}->{$tm}->{$f}); } else { $finals{Total}->{$tm}->{$f} += $a; } } } else { $finals{Total}->{$t} += $finals{$proto}->{$t}; } } } # Convert Time2 to standard deviation foreach $proto (@protocolsAll) { foreach $n (@{$protocolFields{$proto}}) { my $t = $n; # dont modify original list if ($t =~ /^\[(\w+)\]$/) { $t = $1; } # strip off brackets next unless ($finals{$proto}->{$t}); # proto doesnt have timer next unless ($finals{$proto}->{$t}->{Try}); next unless ($finals{$proto}->{$t}->{Time2} > 0); my $ss = $finals{$proto}->{$t}->{Time2}; my $tot = $finals{$proto}->{$t}->{Time}; my $n = $finals{$proto}->{$t}->{Try}; next unless ($n > 0); # skip if this is 0 my $var = ($ss - (($tot * $tot) / $n)) / $n; print "$proto->$t var < 0: Time2=$ss Time=$tot n=$n\n" if ($var < 0); $finals{$proto}->{$t}->{Time2} = ($var > 0) ? sqrt ($var) : 0.0; } } # Divide total times by trys to get averate time foreach $proto (@protocolsAll) { foreach $n (@{$protocolFields{$proto}}) { my $t = $n; # dont modify original list if ($t =~ /^\[(\w+)\]$/) { $t = $1; } # strip off brackets next unless ($finals{$proto}->{$t}); # proto doesnt have timer ($finals{$proto}->{$t}->{Try}) || next; $finals{$proto}->{$t}->{Time} /= $finals{$proto}->{$t}->{Try} } } } # The text version is designed to be machine processable # commify and kformat are not used sub genTextReport { fileBackup ($resultstxt); # if processing as we go, backup old file # Open a text file to hold the results open(RESULTSTXT, ">$resultstxt") || die "Couldn't open $resultstxt: $!"; # Store results as text printf RESULTSTXT "---- Netscape MailStone Results $params{TSTAMP} ----\n"; printf RESULTSTXT "\t\t%s\n", $params{TITLE}; printf RESULTSTXT "\t\t%s\n", $params{COMMENTS}; printf RESULTSTXT "\n"; printf RESULTSTXT "Test duration: %d %s. Rampup: %d %s. Reported duration %s seconds\n", figureTimeNumber ($params{TIME}), figureTimeUnits ($params{TIME}, "minutes"), figureTimeNumber ($params{RAMPTIME}), figureTimeUnits ($params{RAMPTIME}, "seconds"), $realTestSecs; printf RESULTSTXT "Number of reporting clients: %s of %s\n", $reportingClients, $totalProcs; foreach $proto (@protocolsAll) { # do op counters printf RESULTSTXT "\n%-15s ", $proto; foreach $f (@timerFieldsAll) { #($f =~ m/^Time2$/o) && next; printf RESULTSTXT "%13s", ($fieldNames{$f}) ? $fieldNames{$f} : $f; } foreach $n (@{$protocolFields{$proto}}) { my $t = $n; # dont modify original list unless ($t =~ /^\[(\w+)\]$/) { # scalar case #next; # skip scalars for now # do scalar counters. Column should line up with "Try" printf RESULTSTXT "\n%-15s ", $proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t); printf RESULTSTXT "%13s", $finals{$proto}->{$t}; next; } else { # strip off brackets $t = $1; } printf RESULTSTXT "\n%-15s ", $proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t); foreach $f (@timerFieldsAll) { #($f =~ m/^Time2$/o) && next; if ($f =~ m/Time/o) { printf RESULTSTXT "%13.3f", $finals{$proto}->{$t}->{$f}; } elsif ($f =~ m/Bytes/o) { printf RESULTSTXT "%13d", $finals{$proto}->{$t}->{$f}; } else { printf RESULTSTXT "%13s", $finals{$proto}->{$t}->{$f}; } } } # do ops/sec printf RESULTSTXT "\n\n%-15s ", $proto; foreach $f (@timerFieldsAll) { ($f =~ m/^Time/o) && next; printf RESULTSTXT "%9s/sec", ($fieldNames{$f}) ? $fieldNames{$f} : $f; } foreach $n (@{$protocolFields{$proto}}) { my $t = $n; # dont modify original list unless ($t =~ /^\[(\w+)\]$/) { # scalar case #next; # skip scalars for now # do scalar counter/sec. Column should line up with "Try" printf RESULTSTXT "\n%-15s ", $proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t) . "/s"; printf RESULTSTXT "%13.3f", $finals{$proto}->{$t} / $realTestSecs; next; } else { $t = $1; } printf RESULTSTXT "\n%-15s ", $proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t) . "/s"; foreach $f (@timerFieldsAll) { ($f =~ m/^Time/o) && next; if ($f =~ m/Bytes/o) { printf RESULTSTXT "%13d", $finals{$proto}->{$t}->{$f} / $realTestSecs; } else { printf RESULTSTXT "%13.3f", $finals{$proto}->{$t}->{$f} / $realTestSecs; } } } printf RESULTSTXT "\n\n"; } if ($params{SYSCONFIG}) { print RESULTSTXT "\nSytem config details\n"; if (($params{SYSCONFIG} =~ m/^\S+$/o) && (open(SCFILE, "<$params{SYSCONFIG}"))) { while () { (m/^<\S+>\s*$/o) && next; # skip HTML only on them s/<\S+>//g; # trim out obvious HTML commands s///g; # trim out HTML comments print RESULTSTXT $_; } close(SCFILE); } else { my $l = $params{SYSCONFIG}; # filter similar to above $l =~ s/<\S+>//g; # trim out obvious HTML commands $l =~ s///g; # trim out HTML comments $l =~ s/\\\n/\n/g; # turn quoted newline to plain newline print RESULTSTXT $l; } } close(RESULTSTXT); } # Write the main part of the HTML page sub genHTMLReportStart { fileBackup ($resultshtml); # if processing as we go, backup old file # Open an html file to hold the results open(RESULTSHTML, ">$resultshtml") || die "Couldn't open $resultshtml: $!"; print RESULTSHTML < Netscape MailStone Results $params{TSTAMP}

Netscape MailStone Results $params{TSTAMP}

$params{TITLE}

$params{COMMENTS}
END printf RESULTSHTML "
Test duration: %d %s. ", figureTimeNumber ($params{TIME}), figureTimeUnits ($params{TIME}, "minutes"); printf RESULTSHTML "Rampup: %d %s. ", figureTimeNumber ($params{RAMPTIME}), figureTimeUnits ($params{RAMPTIME}, "seconds"); printf RESULTSHTML "Reported duration: %s seconds\n", commify ($realTestSecs); printf RESULTSHTML "
Reporting clients: %s of %s\n", commify ($reportingClients), commify ($totalProcs); print RESULTSHTML < Test complete workload description. Filtered workload description.
Plain text version of results. Log of stderr and debugging output.
END { # list user requested logging my @logfiles = <$resultdir/*-pre.log>; if (@logfiles) { foreach $f (@logfiles) { $f =~ s/$resultdir\///o; # strip directory out $f =~ s/-pre\.log$//o; # strip extension off print RESULTSHTML "Pre test log: $f
\n"; } } @logfiles = <$resultdir/*-run.log>; if (@logfiles) { foreach $f (@logfiles) { $f =~ s/$resultdir\///o; # strip directory out $f =~ s/-run\.log$//o; # strip extension off print RESULTSHTML "Monitoring log: $f
\n"; } } @logfiles = <$resultdir/*-post.log>; if (@logfiles) { foreach $f (@logfiles) { $f =~ s/$resultdir\///o; # strip directory out $f =~ s/-post\.log$//o; # strip extension off print RESULTSHTML "Post test log: $f
\n"; } } } #print RESULTSHTML #"

Results per protocol

\n"; foreach $proto (@protocolsAll) { printf RESULTSHTML "\n", $proto; printf RESULTSHTML "", 2+$#{@{$protocolFields{$proto}}}; print RESULTSHTML "\n"; # do op counters print RESULTSHTML "\n"; foreach $f (@timerFieldsAll) { #($f =~ m/^Time2$/o) && next; printf RESULTSHTML " ", ($fieldNames{$f}) ? $fieldNames{$f} : $f; } print RESULTSHTML "\n"; foreach $n (@{$protocolFields{$proto}}) { my $t = $n; # dont modify original list unless ($t =~ /^\[(\w+)\]$/) { # scalar case next; # skip scalars for now # do scalar counters. Column should line up with "Try" printf RESULTSHTML "\n", ($timerNames{$t}) ? $timerNames{$t} : $t; printf RESULTSHTML " ", commify ($finals{$proto}->{$t}); next; } else { $t = $1; } printf RESULTSHTML "\n", ($timerNames{$t}) ? $timerNames{$t} : $t; foreach $f (@timerFieldsAll) { #($f =~ m/^Time2$/o) && next; if ($f =~ m/Time/o) { printf RESULTSHTML " ", tformat ($finals{$proto}->{$t}->{$f}); } elsif ($f =~ m/Bytes/o) { printf RESULTSHTML " ", kformat ($finals{$proto}->{$t}->{$f}); } else { printf RESULTSHTML " ", commify ($finals{$proto}->{$t}->{$f}); } } print RESULTSHTML "\n"; } # do ops/sec print RESULTSHTML "\n"; foreach $f (@timerFieldsAll) { ($f =~ m/^Time/o) && next; printf RESULTSHTML " ", ($fieldNames{$f}) ? $fieldNames{$f} : $f; } print RESULTSHTML "\n"; foreach $n (@{$protocolFields{$proto}}) { my $t = $n; # dont modify original list unless ($t =~ /^\[(\w+)\]$/) { # scalar case next; # skip scalars for now # do scalar counters. Column should line up with "Try" printf RESULTSHTML "\n", ($timerNames{$t}) ? $timerNames{$t} : $t; printf RESULTSHTML " ", $finals{$proto}->{$t} / $realTestSecs; next; } else { $t = $1; } printf RESULTSHTML "\n", ($timerNames{$t}) ? $timerNames{$t} : $t; foreach $f (@timerFieldsAll) { ($f =~ m/^Time/o) && next; if ($f =~ m/Bytes/o) { printf RESULTSHTML " ", kformat ($finals{$proto}->{$t}->{$f} / $realTestSecs); } else { printf RESULTSHTML " ", $finals{$proto}->{$t}->{$f} / $realTestSecs; } } print RESULTSHTML "\n"; } printf RESULTSHTML "
$proto Counters
$proto%s
%s%s
%s%s%s%s
$proto%s/sec
%s%.3f
%s%s%.3f

\n\n"; } print RESULTSHTML <
END } %genplotGraphs = (); # Call genplot; and, if a graph is generated, insert the HTML reference to it sub genHTMLReportGraph { my $name = shift; my $title = shift; my $label = shift; my $protos = shift || die "genHTMLReportGraph: '$name' missing protocols"; my $field = shift; my $vars = shift || die "genHTMLReportGraph: '$name' missing vars"; if ($genplotGraphs{$name}) { print "Graph $name has already been generated.\n"; return; } $genplotGraphs{$name} = $title; # Delineate and tag each graph print RESULTSHTML "
\n"; if (genPlot ($name, $title, $label, $protos, $field, $vars) > 0) { print RESULTSHTML <

$title

$label

END } else { print RESULTSHTML "
Graph \"$name\" contained no data (@{$vars}).
\n"; } } # Write the final parts of the HTML page sub genHTMLReportEnd { print RESULTSHTML <
END if ($params{SYSCONFIG}) { print RESULTSHTML "
"; print RESULTSHTML "

Details

\n"; if (($params{SYSCONFIG} =~ m/^\S+$/o) && (open(SCFILE, "<$params{SYSCONFIG}"))) { # see if its a file while () { print RESULTSHTML $_; } close(SCFILE); } else { # output text directly my $l = $params{SYSCONFIG}; $l =~ s/\\\n/\n/g; # turn quoted newline to plain newline print RESULTSHTML $l; } } print RESULTSHTML < END close(RESULTSHTML); } # Actually generate the standard stuff setupTotals(); genTextReport(); genHTMLReportStart(); my $graphCount = 0; foreach $section (@workload) { next unless ($section->{sectionTitle} =~ /GRAPH/o); my $name = $section->{sectionParams}; $name =~ s/name=\s*//; # strip off initial bit my @varlist = split (/[\s,]+/, $section->{VARIABLES}); $graphCount++; genHTMLReportGraph ($name, $section->{TITLE}, $section->{LABEL}, ($section->{FIELD} =~ /Time/o) ? \@protocols : \@protocolsAll, $section->{FIELD}, \@varlist); } if ($graphCount <= 0) { # use built ins # generate the graphs we want # NOTE: the first argument (name), must be unique; sets file name genHTMLReportGraph ("connects", "Number of connections attempted", "Connections/sec", \@protocolsAll, "Try", ["conn" ]); genHTMLReportGraph ("connections", "Total connections", "Connections", \@protocolsAll, "", ["connections" ]); genHTMLReportGraph ("errors", "Number of connection errors", "Errors/sec", \@protocolsAll, "Error", ["conn", "banner", "login", "logout" ]); genHTMLReportGraph ("retrieves", "Number of messages read", "Messages/sec", \@protocolsAll, "Try", ["retrieve" ]); genHTMLReportGraph ("submits", "Number of messages written", "Messages/sec", \@protocolsAll, "Try", ["submit" ]); genHTMLReportGraph ("commands", "Protocol commands", "Commands/sec", \@protocolsAll, "Try", ["cmd" ]); genHTMLReportGraph ("readBytes", "Bytes read", "Bytes/sec", \@protocolsAll, "BytesR", ["login", "banner", "cmd", "retrieve", "submit", "logout" ]); genHTMLReportGraph ("writeBytes", "Bytes written", "Bytes/sec", \@protocolsAll, "BytesW", ["login", "banner", "cmd", "retrieve", "submit", "logout" ]); genHTMLReportGraph ("msgTime", "Message transfer time", "Seconds per message", \@protocols, "Time", ["cmd", "submit", "retrieve" ]); genHTMLReportGraph ("setupTime", "Connection setup time", "Seconds per connection", \@protocols, "Time", ["conn", "banner", "login" ]); genHTMLReportGraph ("blocks", "Number of mailstone blocks executed", "Blocks/sec", \@protocolsAll, "", ["blocks" ]); } if ($params{ADDGRAPHS}) { # pick up additional graphs my @graphs = (); readWorkloadFile ($params{ADDGRAPHS}, \@graphs); foreach $section (@graphs) { next unless ($section->{sectionTitle} =~ /GRAPH/o); my $name = $section->{sectionParams}; $name =~ s/name=\s*//; # strip off initial bit my @varlist = split (/[\s,]+/, $section->{VARIABLES}); $graphCount++; genHTMLReportGraph ($name, $section->{TITLE}, $section->{LABEL}, ($section->{FIELD} =~ /Time/o) ? \@protocols : \@protocolsAll, $section->{FIELD}, \@varlist); } } genHTMLReportEnd(); return 1;