Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_init / ns_timeagg.pl
diff --git a/TBBT/trace_init/ns_timeagg.pl b/TBBT/trace_init/ns_timeagg.pl
new file mode 100755 (executable)
index 0000000..9e5e536
--- /dev/null
@@ -0,0 +1,218 @@
+#!/usr/bin/perl -w\r
+#\r
+# Copyright (c) 2002-2003\r
+#      The President and Fellows of Harvard College.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions\r
+# are met:\r
+# 1. Redistributions of source code must retain the above copyright\r
+#    notice, this list of conditions and the following disclaimer.\r
+# 2. Redistributions in binary form must reproduce the above copyright\r
+#    notice, this list of conditions and the following disclaimer in the\r
+#    documentation and/or other materials provided with the distribution.\r
+# 3. Neither the name of the University nor the names of its contributors\r
+#    may be used to endorse or promote products derived from this software\r
+#    without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+# SUCH DAMAGE.\r
+#\r
+# $Id: ns_timeagg,v 1.7 2003/07/28 14:27:17 ellard Exp $\r
+\r
+use Getopt::Std;\r
+\r
+$ProgDir = $0;\r
+$ProgDir =~ /(^.*)\//;\r
+$ProgDir = $1;\r
+if (!$ProgDir) {\r
+       $ProgDir = ".";\r
+}\r
+\r
+require "$ProgDir/common.pl";\r
+\r
+$UseClient     = 0;\r
+$UseFH         = 0;\r
+$UseUID                = 0;\r
+$UseGID                = 0;\r
+$NEW_INTERVAL  = 300;\r
+$OMIT_ZEROS    = 0;\r
+\r
+$Usage =<< ".";\r
+\r
+Usage: $0 [options] [table1.ns [table2.ns ... ]]\r
+\r
+If no table files are specified, then the input is read from stdin.\r
+\r
+Command line options:\r
+\r
+-h             Print usage message and exit.\r
+\r
+-B flags       Choose fields to NOT aggregate.  The fields are:\r
+               C - client host ID\r
+               U - Effective user ID\r
+               G - Effective group ID\r
+               F - File handle\r
+\r
+-R secs                Round the start time to the closest multiple of\r
+               the given number of seconds.  This is useful for\r
+               dealing with small amounts of clock drift.  For example,\r
+               if the trace starts at 12:00:01 instead of 12:00:00,\r
+               it is probably convenient to pretend that it started\r
+               at 12:00:00.\r
+\r
+-t secs                Aggregate over the given number of seconds.   The default\r
+               is $NEW_INTERVAL.  If the current interval does not\r
+               divide the new interval, warning messages are printed\r
+               and the output might not be meaningful.\r
+\r
+               If secs is 0, then the total for the entire table is\r
+               computed.\r
+\r
+-Z             Omit count lines that have a zero total operation count.\r
+.\r
+\r
+$cmdline = "$0 " . join (' ', @ARGV);\r
+$Options = "B:hR:t:Z";\r
+if (! getopts ($Options)) {\r
+       print STDERR "$0: Incorrect usage.\n";\r
+       print STDERR $Usage;\r
+       exit (1);\r
+}\r
+if (defined $opt_h) {\r
+       print $Usage;\r
+       exit (0);\r
+}\r
+\r
+if (defined $opt_t) {\r
+       if ($opt_t <= 0) {\r
+               $EndTime = 0;\r
+       }\r
+       $NEW_INTERVAL   = $opt_t;\r
+}\r
+\r
+$TIME_ROUNDING = defined $opt_R ? $opt_R : 0;\r
+\r
+if (defined $opt_B) {\r
+       $UseClient = ($opt_B =~ /C/);\r
+       $UseUID = ($opt_B =~ /U/);\r
+       $UseGID  = ($opt_B =~ /G/);\r
+       $UseFH = ($opt_B =~ /F/);\r
+}\r
+\r
+# We need to let the measurement of time be a little bit inexact, so\r
+# that a small rounding error or truncation doesn't throw everything\r
+# off.\r
+\r
+$TimerInacc = 0.05;\r
+\r
+# Print out the commandline as a comment in the output.\r
+\r
+print "#cmdline $cmdline\n";\r
+\r
+# It would be nice to make this do the right thing with Latency lines,\r
+# and perhaps file op counts.\r
+\r
+while ($l = <>) {\r
+       if ($l =~ /^#C/) {\r
+               print $l;\r
+               next;\r
+       }\r
+\r
+       next if ($l =~ /^#/);\r
+\r
+       my ($type, $time, $client, $fh, $euid, $egid, @vals) = split (' ', $l);\r
+\r
+       next unless ($type eq 'C');\r
+\r
+       # Something wrong with the input?\r
+\r
+       next if (@vals == 0);\r
+\r
+       if (!defined $StartTime) {\r
+               $StartTime = findStartTime ($time, $TIME_ROUNDING);\r
+               if ($NEW_INTERVAL > 0) {\r
+                       $EndTime = $StartTime + $NEW_INTERVAL - $TimerInacc;\r
+               }\r
+       }\r
+\r
+       if ($EndTime > 0 && $time >= $EndTime) {\r
+               my $diff = int ($time - $StartTime);\r
+               if ($diff > 0) {\r
+                       if ($NEW_INTERVAL % $diff != 0) {\r
+                               print STDERR "$0: time interval mismatch ";\r
+                               print STDERR "(from $diff to $NEW_INTERVAL)\n";\r
+                       }\r
+               }\r
+\r
+               dumpKeys ($StartTime);\r
+\r
+               $StartTime += $NEW_INTERVAL;\r
+               $EndTime = $StartTime + $NEW_INTERVAL - $TimerInacc;\r
+       }\r
+\r
+\r
+       # Aggregate across clients, files, users, and groups unless\r
+       # specifically asked NOT to.\r
+\r
+       $client = $UseClient ? $client : 'u';\r
+       $fh = $UseFH ? $fh : 'u';\r
+       $euid = $UseUID ? $euid : 'u';\r
+       $egid = $UseGID  ? $egid : 'u';\r
+\r
+       $key = "$client,$fh,$euid,$egid";\r
+\r
+       if (exists $Totals{$key}) {\r
+               my (@tots) = split (' ', $Totals{$key});\r
+               for (my $i = 0; $i < @vals; $i++) {\r
+                       $tots[$i] += $vals[$i];\r
+               }\r
+               $Totals{$key} = join (' ', @tots);\r
+       }\r
+       else {\r
+               $Totals{$key} = join (' ', @vals);\r
+       }\r
+}\r
+\r
+if ($EndTime <= 0) {\r
+       dumpKeys ($StartTime);\r
+}\r
+\r
+sub dumpKeys {\r
+       my ($start) = @_;\r
+       my ($i, $k, $ks);\r
+\r
+       foreach $k ( keys %Totals ) {\r
+               my (@v) = split (' ', $Totals{$k});\r
+\r
+               if ($OMIT_ZEROS && $v[0] == 0) {\r
+                       next;\r
+               }\r
+\r
+               $ks = $k;\r
+               $ks =~ s/,/\ /g;\r
+\r
+               print "C $start $ks";\r
+\r
+               for ($i = 0; $i < @v; $i++) {\r
+                       print " $v[$i]";\r
+               }\r
+               print "\n";\r
+\r
+               for ($i = 0; $i < @v; $i++) {\r
+                       $v[$i] = 0;\r
+               }\r
+               $Totals{$k} = join (' ', @v);\r
+       }\r
+}\r
+\r
+exit 0;\r