1 | #!/usr/bin/perl -w |
---|
2 | # $Id: summary.pl,v 1.1.1.1 1997-12-02 20:29:04 brlewis Exp $ |
---|
3 | # Perl version of (summary.sh, loop.awk, peer.awk): |
---|
4 | # Create summaries from xntpd's loop and peer statistics. |
---|
5 | # |
---|
6 | # Copyright (c) 1997, Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> |
---|
7 | # |
---|
8 | # This program is free software; you can redistribute it and/or modify |
---|
9 | # it under the terms of the GNU General Public License as published by |
---|
10 | # the Free Software Foundation; either version 2 of the License, or |
---|
11 | # (at your option) any later version. |
---|
12 | # |
---|
13 | # This program is distributed in the hope that it will be useful, but |
---|
14 | # WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
16 | # General Public License for more details. |
---|
17 | # |
---|
18 | # You should have received a copy of the GNU General Public License |
---|
19 | # along with this program; if not, write to the Free Software |
---|
20 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
21 | |
---|
22 | require 5.003; # "never tested with any other version of Perl" |
---|
23 | use strict; |
---|
24 | |
---|
25 | use Getopt::Long; |
---|
26 | |
---|
27 | my $statsdir = "/tmp/xntpd"; |
---|
28 | my $skip_time_steps = 3600.0; # ignore time offsets larger that this |
---|
29 | my $startdate = "19700101"; # first data file to use |
---|
30 | my $enddate=`date -u +%Y%m%d`; chomp $enddate; --$enddate; |
---|
31 | my $peer_dist_limit = 400.0; |
---|
32 | |
---|
33 | my %options = ("directory=s" => \$statsdir, |
---|
34 | "skip-time-steps:f" => \$skip_time_steps, |
---|
35 | "start-date=s" => \$startdate, |
---|
36 | "end-date=s" => \$enddate, |
---|
37 | "peer-dist-limit=f" => \$peer_dist_limit); |
---|
38 | |
---|
39 | if ( !GetOptions(%options) ) |
---|
40 | { |
---|
41 | print STDERR "valid options for $0 are:\n"; |
---|
42 | my $opt; |
---|
43 | foreach $opt (sort(keys %options)) { |
---|
44 | print STDERR "\t--$opt "; |
---|
45 | if ( ref($options{$opt}) eq "ARRAY" ) { |
---|
46 | print STDERR "(" . join (" ", @{$options{$opt}}) . ")\n"; |
---|
47 | } else { |
---|
48 | print STDERR "(${$options{$opt}})\n"; |
---|
49 | } |
---|
50 | } |
---|
51 | print STDERR "\n"; |
---|
52 | die; |
---|
53 | } |
---|
54 | |
---|
55 | die "$statsdir: no such directory" unless (-d $statsdir); |
---|
56 | die "$skip_time_steps: skip-time-steps must be positive" |
---|
57 | unless ($skip_time_steps >= 0.0); |
---|
58 | die "$startdate: invalid start date" |
---|
59 | unless ($startdate =~ m/.*([12]\d{3}[01]\d[0-3]\d)$/); |
---|
60 | die "$enddate: invalid end date" |
---|
61 | unless ($enddate =~ m/.*([12]\d{3}[01]\d[0-3]\d)$/); |
---|
62 | |
---|
63 | $skip_time_steps = 0.128 if ($skip_time_steps == 0); |
---|
64 | |
---|
65 | sub min |
---|
66 | { |
---|
67 | my ($result, @rest) = @_; |
---|
68 | map { $result = $_ if ($_ < $result) } @rest; |
---|
69 | return($result); |
---|
70 | } |
---|
71 | |
---|
72 | sub max |
---|
73 | { |
---|
74 | my ($result, @rest) = @_; |
---|
75 | map { $result = $_ if ($_ > $result) } @rest; |
---|
76 | return($result); |
---|
77 | } |
---|
78 | |
---|
79 | # calculate mean, range, and standard deviation for offset and frequency |
---|
80 | sub do_loop |
---|
81 | { |
---|
82 | my ($directory, $fname, $out_file) = @_; |
---|
83 | print "$directory/$fname\n"; |
---|
84 | open INPUT, "$directory/$fname"; |
---|
85 | open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; |
---|
86 | print OUTPUT "$fname\n"; |
---|
87 | my ($loop_tmax, $loop_fmax) = (-1e9, -1e9); |
---|
88 | my ($loop_tmin, $loop_fmin) = (1e9, 1e9); |
---|
89 | my ($loop_time_rms, $loop_freq_rms) = (0, 0); |
---|
90 | my $loop_count = 0; |
---|
91 | my $loop_time = 0; |
---|
92 | my $loop_freq = 0; |
---|
93 | my ($freq, $offs); |
---|
94 | my @Fld; |
---|
95 | while (<INPUT>) { |
---|
96 | chop; # strip record separator |
---|
97 | @Fld = split; |
---|
98 | next if ($#Fld != 4); |
---|
99 | # 50529 74356.259 -0.000112 16.1230 8 |
---|
100 | if ($Fld[2] > $skip_time_steps || $Fld[2] < -$skip_time_steps) { |
---|
101 | warn "ignoring loop offset $Fld[2] (file $fname, line $.)\n"; |
---|
102 | next |
---|
103 | } |
---|
104 | $loop_count++; |
---|
105 | ($offs, $freq) = ($Fld[2], $Fld[3]); |
---|
106 | $loop_tmax = max($loop_tmax, $offs); |
---|
107 | $loop_tmin = min($loop_tmin, $offs); |
---|
108 | $loop_fmax = max($loop_fmax, $freq); |
---|
109 | $loop_fmin = min($loop_fmin, $freq); |
---|
110 | $loop_time += $offs; |
---|
111 | $loop_time_rms += $offs * $offs; |
---|
112 | $loop_freq += $freq; |
---|
113 | $loop_freq_rms += $freq * $freq; |
---|
114 | } |
---|
115 | close INPUT; |
---|
116 | if ($loop_count > 1) { |
---|
117 | $loop_time /= $loop_count; |
---|
118 | $loop_time_rms = $loop_time_rms / $loop_count - $loop_time * $loop_time; |
---|
119 | if ($loop_time_rms < 0) { |
---|
120 | warn "loop_time_rms: $loop_time_rms < 0"; |
---|
121 | $loop_time_rms = 0; |
---|
122 | } |
---|
123 | $loop_time_rms = sqrt($loop_time_rms); |
---|
124 | $loop_freq /= $loop_count; |
---|
125 | $loop_freq_rms = $loop_freq_rms / $loop_count - $loop_freq * $loop_freq; |
---|
126 | if ($loop_freq_rms < 0) { |
---|
127 | warn "loop_freq_rms: $loop_freq_rms < 0"; |
---|
128 | $loop_freq_rms = 0; |
---|
129 | } |
---|
130 | $loop_freq_rms = sqrt($loop_freq_rms); |
---|
131 | printf OUTPUT |
---|
132 | ("loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n", |
---|
133 | $loop_count, ($loop_tmax + $loop_tmin) / 2 * 1e6, |
---|
134 | ($loop_tmax - $loop_tmin) / 2 * 1e6, $loop_time_rms * 1e6, |
---|
135 | ($loop_fmax + $loop_fmin) / 2, ($loop_fmax - $loop_fmin) / 2, |
---|
136 | $loop_freq_rms); |
---|
137 | } |
---|
138 | else { |
---|
139 | warn "no valid lines in $directory/$fname"; |
---|
140 | } |
---|
141 | close OUTPUT |
---|
142 | } |
---|
143 | |
---|
144 | # calculate mean, standard deviation, maximum offset, mean dispersion, |
---|
145 | # and maximum distance for each peer |
---|
146 | sub do_peer |
---|
147 | { |
---|
148 | my ($directory, $fname, $out_file) = @_; |
---|
149 | print "$directory/$fname\n"; |
---|
150 | open INPUT, "$directory/$fname"; |
---|
151 | open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; |
---|
152 | print OUTPUT "$fname\n"; |
---|
153 | # we toss out all distances greater than one second on the assumption the |
---|
154 | # peer is in initial acquisition |
---|
155 | my ($n, $MAXDISTANCE) = (0, 1.0); |
---|
156 | my %peer_time; |
---|
157 | my %peer_time_rms; |
---|
158 | my %peer_count; |
---|
159 | my %peer_delay; |
---|
160 | my %peer_disp; |
---|
161 | my %peer_dist; |
---|
162 | my %peer_ident; |
---|
163 | my %peer_tmin; |
---|
164 | my %peer_tmax; |
---|
165 | my @Fld; |
---|
166 | my ($i, $j); |
---|
167 | my ($dist, $offs); |
---|
168 | while (<INPUT>) { |
---|
169 | chop; # strip record separator |
---|
170 | @Fld = split; |
---|
171 | next if ($#Fld != 6); |
---|
172 | # 50529 83316.249 127.127.8.1 9674 0.008628 0.00000 0.00700 |
---|
173 | $dist = $Fld[6] + $Fld[5] / 2; |
---|
174 | next if ($dist > $MAXDISTANCE); |
---|
175 | $offs = $Fld[4]; |
---|
176 | if ($offs > $skip_time_steps || $offs < -$skip_time_steps) { |
---|
177 | warn "ignoring peer offset $offs (file $fname, line $.)\n"; |
---|
178 | next |
---|
179 | } |
---|
180 | $i = $n; |
---|
181 | for ($j = 0; $j < $n; $j++) { |
---|
182 | if ($Fld[2] eq $peer_ident{$j}) { |
---|
183 | $i = $j; # peer found |
---|
184 | last; |
---|
185 | } |
---|
186 | } |
---|
187 | if ($i == $n) { # add new peer |
---|
188 | $peer_ident{$i} = $Fld[2]; |
---|
189 | $peer_tmax{$i} = $peer_dist{$i} = -1e9; |
---|
190 | $peer_tmin{$i} = 1e9; |
---|
191 | $peer_time{$i} = $peer_time_rms{$i} = 0; |
---|
192 | $peer_delay{$i} = $peer_disp{$i} = 0; |
---|
193 | $peer_count{$i} = 0; |
---|
194 | $n++; |
---|
195 | } |
---|
196 | $peer_count{$i}++; |
---|
197 | $peer_tmax{$i} = max($peer_tmax{$i}, $offs); |
---|
198 | $peer_tmin{$i} = min($peer_tmin{$i}, $offs); |
---|
199 | $peer_dist{$i} = max($peer_dist{$i}, $dist); |
---|
200 | $peer_time{$i} += $offs; |
---|
201 | $peer_time_rms{$i} += $offs * $offs; |
---|
202 | $peer_delay{$i} += $Fld[5]; |
---|
203 | $peer_disp{$i} += $Fld[6]; |
---|
204 | } |
---|
205 | close INPUT; |
---|
206 | print OUTPUT |
---|
207 | " ident cnt mean rms max delay dist disp\n"; |
---|
208 | print OUTPUT |
---|
209 | "==========================================================================\n"; |
---|
210 | my @lines = (); |
---|
211 | for ($i = 0; $i < $n; $i++) { |
---|
212 | next if $peer_count{$i} < 2; |
---|
213 | $peer_time{$i} /= $peer_count{$i}; |
---|
214 | $peer_time_rms{$i} = sqrt($peer_time_rms{$i} / $peer_count{$i} - |
---|
215 | $peer_time{$i} * $peer_time{$i}); |
---|
216 | $peer_delay{$i} /= $peer_count{$i}; |
---|
217 | $peer_disp{$i} /= $peer_count{$i}; |
---|
218 | $peer_tmax{$i} = $peer_tmax{$i} - $peer_time{$i}; |
---|
219 | $peer_tmin{$i} = $peer_time{$i} - $peer_tmin{$i}; |
---|
220 | if ($peer_tmin{$i} > $peer_tmax{$i}) { # can this happen at all? |
---|
221 | $peer_tmax{$i} = $peer_tmin{$i}; |
---|
222 | } |
---|
223 | push @lines, sprintf |
---|
224 | "%-15s %4d %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n", |
---|
225 | $peer_ident{$i}, $peer_count{$i}, $peer_time{$i} * 1e3, |
---|
226 | $peer_time_rms{$i} * 1e3, $peer_tmax{$i} * 1e3, |
---|
227 | $peer_delay{$i} * 1e3, $peer_dist{$i} * 1e3, $peer_disp{$i} * 1e3; |
---|
228 | } |
---|
229 | print OUTPUT sort @lines; |
---|
230 | close OUTPUT; |
---|
231 | } |
---|
232 | |
---|
233 | sub do_clock |
---|
234 | { |
---|
235 | my ($directory, $fname, $out_file) = @_; |
---|
236 | print "$directory/$fname\n"; |
---|
237 | open INPUT, "$directory/$fname"; |
---|
238 | open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; |
---|
239 | print OUTPUT "$fname\n"; |
---|
240 | close INPUT; |
---|
241 | close OUTPUT; |
---|
242 | } |
---|
243 | |
---|
244 | sub peer_summary |
---|
245 | { |
---|
246 | my $in_file = shift; |
---|
247 | my ($i, $j, $n); |
---|
248 | my (%peer_ident, %peer_count, %peer_mean, %peer_var, %peer_max); |
---|
249 | my (%peer_1, %peer_2, %peer_3, %peer_4); |
---|
250 | my $dist; |
---|
251 | my $max; |
---|
252 | open INPUT, "<$in_file" or die "can't open $in_file: $!"; |
---|
253 | my @Fld; |
---|
254 | $n = 0; |
---|
255 | while (<INPUT>) { |
---|
256 | chop; # strip record separator |
---|
257 | @Fld = split; |
---|
258 | next if ($#Fld < 7 || $Fld[0] eq 'ident'); |
---|
259 | $i = $n; |
---|
260 | for ($j = 0; $j < $n; $j++) { |
---|
261 | if ($Fld[0] eq $peer_ident{$j}) { |
---|
262 | $i = $j; |
---|
263 | last; # peer found |
---|
264 | } |
---|
265 | } |
---|
266 | if ($i == $n) { # add new peer |
---|
267 | $peer_count{$i} = $peer_mean{$i} = $peer_var{$i} = 0; |
---|
268 | $peer_max{$i} = 0; |
---|
269 | $peer_1{$i} = $peer_2{$i} = $peer_3{$i} = $peer_4{$i} = 0; |
---|
270 | $peer_ident{$i} = $Fld[0]; |
---|
271 | ++$n; |
---|
272 | } |
---|
273 | $dist = $Fld[6] - $Fld[5] / 2; |
---|
274 | if ($dist < $peer_dist_limit) { |
---|
275 | $peer_count{$i}++; |
---|
276 | $peer_mean{$i} += $Fld[2]; |
---|
277 | $peer_var{$i} += $Fld[3] * $Fld[3]; |
---|
278 | $max = $Fld[4]; |
---|
279 | $peer_max{$i} = max($peer_max{$i}, $max); |
---|
280 | if ($max > 1) { |
---|
281 | $peer_1{$i}++; |
---|
282 | if ($max > 5) { |
---|
283 | $peer_2{$i}++; |
---|
284 | if ($max > 10) { |
---|
285 | $peer_3{$i}++; |
---|
286 | if ($max > 50) { |
---|
287 | $peer_4{$i}++; |
---|
288 | } |
---|
289 | } |
---|
290 | } |
---|
291 | } |
---|
292 | } |
---|
293 | else { |
---|
294 | warn "dist exceeds limit: $dist (file $in_file, line $.)\n"; |
---|
295 | } |
---|
296 | } |
---|
297 | close INPUT; |
---|
298 | my @lines = (); |
---|
299 | print |
---|
300 | " host days mean rms max >1 >5 >10 >50\n"; |
---|
301 | print |
---|
302 | "==================================================================\n"; |
---|
303 | for ($i = 0; $i < $n; $i++) { |
---|
304 | next if ($peer_count{$i} < 2); |
---|
305 | $peer_mean{$i} /= $peer_count{$i}; |
---|
306 | $peer_var{$i} = sqrt($peer_var{$i} / $peer_count{$i} - |
---|
307 | $peer_mean{$i} * $peer_mean{$i}); |
---|
308 | push @lines, sprintf |
---|
309 | "%-15s %3d %9.3f% 9.3f %9.3f %3d %3d %3d %3d\n", |
---|
310 | $peer_ident{$i}, $peer_count{$i}, $peer_mean{$i}, $peer_var{$i}, |
---|
311 | $peer_max{$i}, $peer_1{$i}, $peer_2{$i}, $peer_3{$i}, $peer_4{$i}; |
---|
312 | } |
---|
313 | print sort @lines; |
---|
314 | } |
---|
315 | |
---|
316 | my $loop_summary="/tmp/loop_summary"; |
---|
317 | my $peer_summary="/tmp/peer_summary"; |
---|
318 | my $clock_summary="/tmp/clock_summary"; |
---|
319 | my (@loopfiles, @peerfiles, @clockfiles); |
---|
320 | |
---|
321 | print STDERR "Creating summaries from $statsdir ($startdate to $enddate)\n"; |
---|
322 | |
---|
323 | opendir SDIR, $statsdir or die "directory ${statsdir}: $!"; |
---|
324 | rewinddir SDIR; |
---|
325 | @loopfiles=sort grep /loop.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; |
---|
326 | rewinddir SDIR; |
---|
327 | @peerfiles=sort grep /peer.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; |
---|
328 | rewinddir SDIR; |
---|
329 | @clockfiles=sort grep /clock.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; |
---|
330 | closedir SDIR; |
---|
331 | |
---|
332 | map { unlink $_ if -f $_ } ($loop_summary, $peer_summary, $clock_summary); |
---|
333 | |
---|
334 | my $date; |
---|
335 | map { |
---|
336 | $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; |
---|
337 | if ($date ge $startdate && $date le $enddate) { |
---|
338 | do_loop $statsdir, $_, $loop_summary; |
---|
339 | } |
---|
340 | } @loopfiles; |
---|
341 | |
---|
342 | map { |
---|
343 | $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; |
---|
344 | if ($date ge $startdate && $date le $enddate) { |
---|
345 | do_peer $statsdir, $_, $peer_summary; |
---|
346 | } |
---|
347 | } @peerfiles; |
---|
348 | |
---|
349 | map { |
---|
350 | $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; |
---|
351 | if ($date ge $startdate && $date le $enddate) { |
---|
352 | do_clock $statsdir, $_, $clock_summary; |
---|
353 | } |
---|
354 | } @clockfiles; |
---|
355 | |
---|
356 | print STDERR "Creating peer summary with limit $peer_dist_limit\n"; |
---|
357 | peer_summary $peer_summary if (-f $peer_summary); |
---|