Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_init / ns_timeagg.pl
1 #!/usr/bin/perl -w\r
2 #\r
3 # Copyright (c) 2002-2003\r
4 #      The President and Fellows of Harvard College.\r
5 #\r
6 # Redistribution and use in source and binary forms, with or without\r
7 # modification, are permitted provided that the following conditions\r
8 # are met:\r
9 # 1. Redistributions of source code must retain the above copyright\r
10 #    notice, this list of conditions and the following disclaimer.\r
11 # 2. Redistributions in binary form must reproduce the above copyright\r
12 #    notice, this list of conditions and the following disclaimer in the\r
13 #    documentation and/or other materials provided with the distribution.\r
14 # 3. Neither the name of the University nor the names of its contributors\r
15 #    may be used to endorse or promote products derived from this software\r
16 #    without specific prior written permission.\r
17 #\r
18 # THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
19 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
21 # ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
22 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
24 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
25 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
26 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
27 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
28 # SUCH DAMAGE.\r
29 #\r
30 # $Id: ns_timeagg,v 1.7 2003/07/28 14:27:17 ellard Exp $\r
31 \r
32 use Getopt::Std;\r
33 \r
34 $ProgDir = $0;\r
35 $ProgDir =~ /(^.*)\//;\r
36 $ProgDir = $1;\r
37 if (!$ProgDir) {\r
38         $ProgDir = ".";\r
39 }\r
40 \r
41 require "$ProgDir/common.pl";\r
42 \r
43 $UseClient      = 0;\r
44 $UseFH          = 0;\r
45 $UseUID         = 0;\r
46 $UseGID         = 0;\r
47 $NEW_INTERVAL   = 300;\r
48 $OMIT_ZEROS     = 0;\r
49 \r
50 $Usage =<< ".";\r
51 \r
52 Usage: $0 [options] [table1.ns [table2.ns ... ]]\r
53 \r
54 If no table files are specified, then the input is read from stdin.\r
55 \r
56 Command line options:\r
57 \r
58 -h              Print usage message and exit.\r
59 \r
60 -B flags        Choose fields to NOT aggregate.  The fields are:\r
61                 C - client host ID\r
62                 U - Effective user ID\r
63                 G - Effective group ID\r
64                 F - File handle\r
65 \r
66 -R secs         Round the start time to the closest multiple of\r
67                 the given number of seconds.  This is useful for\r
68                 dealing with small amounts of clock drift.  For example,\r
69                 if the trace starts at 12:00:01 instead of 12:00:00,\r
70                 it is probably convenient to pretend that it started\r
71                 at 12:00:00.\r
72 \r
73 -t secs         Aggregate over the given number of seconds.   The default\r
74                 is $NEW_INTERVAL.  If the current interval does not\r
75                 divide the new interval, warning messages are printed\r
76                 and the output might not be meaningful.\r
77 \r
78                 If secs is 0, then the total for the entire table is\r
79                 computed.\r
80 \r
81 -Z              Omit count lines that have a zero total operation count.\r
82 .\r
83 \r
84 $cmdline = "$0 " . join (' ', @ARGV);\r
85 $Options = "B:hR:t:Z";\r
86 if (! getopts ($Options)) {\r
87         print STDERR "$0: Incorrect usage.\n";\r
88         print STDERR $Usage;\r
89         exit (1);\r
90 }\r
91 if (defined $opt_h) {\r
92         print $Usage;\r
93         exit (0);\r
94 }\r
95 \r
96 if (defined $opt_t) {\r
97         if ($opt_t <= 0) {\r
98                 $EndTime = 0;\r
99         }\r
100         $NEW_INTERVAL   = $opt_t;\r
101 }\r
102 \r
103 $TIME_ROUNDING  = defined $opt_R ? $opt_R : 0;\r
104 \r
105 if (defined $opt_B) {\r
106         $UseClient = ($opt_B =~ /C/);\r
107         $UseUID = ($opt_B =~ /U/);\r
108         $UseGID  = ($opt_B =~ /G/);\r
109         $UseFH = ($opt_B =~ /F/);\r
110 }\r
111 \r
112 # We need to let the measurement of time be a little bit inexact, so\r
113 # that a small rounding error or truncation doesn't throw everything\r
114 # off.\r
115 \r
116 $TimerInacc = 0.05;\r
117 \r
118 # Print out the commandline as a comment in the output.\r
119 \r
120 print "#cmdline $cmdline\n";\r
121 \r
122 # It would be nice to make this do the right thing with Latency lines,\r
123 # and perhaps file op counts.\r
124 \r
125 while ($l = <>) {\r
126         if ($l =~ /^#C/) {\r
127                 print $l;\r
128                 next;\r
129         }\r
130 \r
131         next if ($l =~ /^#/);\r
132 \r
133         my ($type, $time, $client, $fh, $euid, $egid, @vals) = split (' ', $l);\r
134 \r
135         next unless ($type eq 'C');\r
136 \r
137         # Something wrong with the input?\r
138 \r
139         next if (@vals == 0);\r
140 \r
141         if (!defined $StartTime) {\r
142                 $StartTime = findStartTime ($time, $TIME_ROUNDING);\r
143                 if ($NEW_INTERVAL > 0) {\r
144                         $EndTime = $StartTime + $NEW_INTERVAL - $TimerInacc;\r
145                 }\r
146         }\r
147 \r
148         if ($EndTime > 0 && $time >= $EndTime) {\r
149                 my $diff = int ($time - $StartTime);\r
150                 if ($diff > 0) {\r
151                         if ($NEW_INTERVAL % $diff != 0) {\r
152                                 print STDERR "$0: time interval mismatch ";\r
153                                 print STDERR "(from $diff to $NEW_INTERVAL)\n";\r
154                         }\r
155                 }\r
156 \r
157                 dumpKeys ($StartTime);\r
158 \r
159                 $StartTime += $NEW_INTERVAL;\r
160                 $EndTime = $StartTime + $NEW_INTERVAL - $TimerInacc;\r
161         }\r
162 \r
163 \r
164         # Aggregate across clients, files, users, and groups unless\r
165         # specifically asked NOT to.\r
166 \r
167         $client = $UseClient ? $client : 'u';\r
168         $fh = $UseFH ? $fh : 'u';\r
169         $euid = $UseUID ? $euid : 'u';\r
170         $egid = $UseGID  ? $egid : 'u';\r
171 \r
172         $key = "$client,$fh,$euid,$egid";\r
173 \r
174         if (exists $Totals{$key}) {\r
175                 my (@tots) = split (' ', $Totals{$key});\r
176                 for (my $i = 0; $i < @vals; $i++) {\r
177                         $tots[$i] += $vals[$i];\r
178                 }\r
179                 $Totals{$key} = join (' ', @tots);\r
180         }\r
181         else {\r
182                 $Totals{$key} = join (' ', @vals);\r
183         }\r
184 }\r
185 \r
186 if ($EndTime <= 0) {\r
187         dumpKeys ($StartTime);\r
188 }\r
189 \r
190 sub dumpKeys {\r
191         my ($start) = @_;\r
192         my ($i, $k, $ks);\r
193 \r
194         foreach $k ( keys %Totals ) {\r
195                 my (@v) = split (' ', $Totals{$k});\r
196 \r
197                 if ($OMIT_ZEROS && $v[0] == 0) {\r
198                         next;\r
199                 }\r
200 \r
201                 $ks = $k;\r
202                 $ks =~ s/,/\ /g;\r
203 \r
204                 print "C $start $ks";\r
205 \r
206                 for ($i = 0; $i < @v; $i++) {\r
207                         print " $v[$i]";\r
208                 }\r
209                 print "\n";\r
210 \r
211                 for ($i = 0; $i < @v; $i++) {\r
212                         $v[$i] = 0;\r
213                 }\r
214                 $Totals{$k} = join (' ', @v);\r
215         }\r
216 }\r
217 \r
218 exit 0;\r