]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/scripts/summary.in
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / scripts / summary.in
1 #! @PATH_PERL@ -w
2 # $Id$
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, 1999 by 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 package summary;
22 use 5.006_000;
23 use strict;
24
25 my ($log_date_pattern, $statsdir, $outputdir, $skip_time_steps, $startdate,
26     $enddate, $peer_dist_limit);
27
28 exit run(@ARGV) unless caller;
29
30 sub run {
31     my $opts;
32     if (!processOptions(\@ARGV, $opts)) {
33         usage(1);
34     };
35
36     $log_date_pattern = '[12]\d{3}[01]\d[0-3]\d';
37     $statsdir         = $opts->{directory};
38     $outputdir        = $opts->{'output-directory'};
39     $skip_time_steps  = $opts->{'skip-time-steps'};
40     $startdate        = $opts->{'start-date'};
41     $enddate          = $opts->{'end-date'};
42     if (!$enddate){
43         $enddate = `date -u +%Y%m%d`; 
44         chomp $enddate;
45         --$enddate;
46     }
47     $peer_dist_limit = $opts->{'peer-dist-limit'};
48
49     # check possibly current values of options
50     die "$statsdir: no such directory" unless (-d $statsdir);
51     die "$outputdir: no such directory" unless (-d $outputdir);
52     die "$skip_time_steps: skip-time-steps must be positive"
53         unless ($skip_time_steps >= 0.0);
54     die "$startdate: invalid start date|$`|$&|$'"
55         unless ($startdate =~ m/.*$log_date_pattern$/);
56     die "$enddate: invalid end date"
57         unless ($enddate =~ m/.*$log_date_pattern$/);
58
59     $skip_time_steps = 0.128 if ($skip_time_steps == 0);
60
61     my $loop_summary="$outputdir/loop_summary";
62     my $peer_summary="$outputdir/peer_summary";
63     my $clock_summary="$outputdir/clock_summary";
64     my (@loopfiles, @peerfiles, @clockfiles);
65
66     print STDERR "Creating summaries from $statsdir ($startdate to $enddate)\n";
67
68     opendir SDIR, $statsdir or die "directory ${statsdir}: $!";
69     rewinddir SDIR;
70     @loopfiles=sort grep /loop.*$log_date_pattern/, readdir SDIR;
71     rewinddir SDIR;
72     @peerfiles=sort grep /peer.*$log_date_pattern/, readdir SDIR;
73     rewinddir SDIR;
74     @clockfiles=sort grep /clock.*$log_date_pattern/, readdir SDIR;
75     closedir SDIR;
76
77     # remove old summary files
78     for ($loop_summary, $peer_summary, $clock_summary) { unlink $_ if -f $_ };
79
80     my $date;
81     for (@loopfiles) {
82         $date = $_; $date =~ s/.*($log_date_pattern)$/$1/;
83         if ($date ge $startdate && $date le $enddate) {
84             do_loop($statsdir, $_, $loop_summary);
85         }
86     }
87
88     for (@peerfiles) {
89         $date = $_; $date =~ s/.*($log_date_pattern)$/$1/;
90         if ($date ge $startdate && $date le $enddate) {
91             do_peer($statsdir, $_, $peer_summary);
92         }
93     }
94
95     for (@clockfiles) {
96         $date = $_; $date =~ s/.*($log_date_pattern)$/$1/;
97         if ($date ge $startdate && $date le $enddate) {
98             do_clock($statsdir, $_, $clock_summary);
99         }
100     }
101
102     print STDERR "Creating peer summary with limit $peer_dist_limit\n";
103     peer_summary($peer_summary) if (-f $peer_summary);
104 }
105
106 sub min
107 {
108     my ($result, @rest) = @_;
109     map { $result = $_ if ($_ < $result) } @rest;
110     return($result);
111 }
112
113 sub max
114 {
115     my ($result, @rest) = @_;
116     map { $result = $_ if ($_ > $result) } @rest;
117     return($result);
118 }
119
120 # calculate mean, range, and standard deviation for offset and frequency
121 sub do_loop
122 {
123     my ($directory, $fname, $out_file) = @_;
124     print "$directory/$fname\n";
125     open INPUT, "$directory/$fname" or warn "can't open $directory/$fname: $!";
126     open OUTPUT, ">>$out_file" or die "can't open $out_file: $!";
127     print OUTPUT "$fname\n";
128     my ($loop_tmax, $loop_fmax) = (-1e9, -1e9);
129     my ($loop_tmin, $loop_fmin) = (1e9, 1e9);
130     my ($loop_time_rms, $loop_freq_rms) = (0, 0);
131     my $loop_count = 0;
132     my $loop_time = 0;
133     my $loop_freq = 0;
134     my ($freq, $offs);
135     my @Fld;
136     while (<INPUT>) {
137         chop;   # strip record separator
138         @Fld = split;
139         next if ($#Fld < 4);
140 #NTPv3: 50529 74356.259 -0.000112 16.1230 8
141 #NTPv3: day, sec.msec, offset, drift_comp, sys_poll
142 #NTPv4: 51333 54734.582 0.000001648 16.981964 0.000001094 0.020938 6
143 #NTPv4: day, sec.msec, offset, drift_comp, sys_error, clock_stabil, sys_poll
144         if ($Fld[2] > $skip_time_steps || $Fld[2] < -$skip_time_steps) {
145             warn "ignoring loop offset $Fld[2] (file $fname, line $.)\n";
146             next
147         }
148         $loop_count++;
149         ($offs, $freq) = ($Fld[2], $Fld[3]);
150         $loop_tmax = max($loop_tmax, $offs);
151         $loop_tmin = min($loop_tmin, $offs);
152         $loop_fmax = max($loop_fmax, $freq);
153         $loop_fmin = min($loop_fmin, $freq);
154         $loop_time += $offs;
155         $loop_time_rms += $offs * $offs;
156         $loop_freq += $freq;
157         $loop_freq_rms += $freq * $freq;
158     }
159     close INPUT;
160     if ($loop_count > 1) {
161         $loop_time /= $loop_count;
162         $loop_time_rms = $loop_time_rms / $loop_count - $loop_time * $loop_time;
163         if ($loop_time_rms < 0) {
164             warn "loop_time_rms: $loop_time_rms < 0";
165             $loop_time_rms = 0;
166         }
167         $loop_time_rms = sqrt($loop_time_rms);
168         $loop_freq /= $loop_count;
169         $loop_freq_rms = $loop_freq_rms / $loop_count - $loop_freq * $loop_freq;
170         if ($loop_freq_rms < 0) {
171             warn "loop_freq_rms: $loop_freq_rms < 0";
172             $loop_freq_rms = 0;
173         }
174         $loop_freq_rms = sqrt($loop_freq_rms);
175         printf OUTPUT
176             ("loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n",
177              $loop_count, ($loop_tmax + $loop_tmin) / 2 * 1e6,
178              ($loop_tmax - $loop_tmin) / 2 * 1e6, $loop_time_rms * 1e6,
179              ($loop_fmax + $loop_fmin) / 2, ($loop_fmax - $loop_fmin) / 2,
180              $loop_freq_rms);
181     }
182     else {
183         warn "no valid lines in $directory/$fname";
184     }
185     close OUTPUT
186 }
187
188 # calculate mean, standard deviation, maximum offset, mean dispersion,
189 # and maximum distance for each peer
190 sub do_peer
191 {
192     my ($directory, $fname, $out_file) = @_;
193     print "$directory/$fname\n";
194     open INPUT, "$directory/$fname" or warn "can't open $directory/$fname: $!";
195     open OUTPUT, ">>$out_file" or die "can't open $out_file: $!";
196     print OUTPUT "$fname\n";
197 # we toss out all distances greater than one second on the assumption the
198 # peer is in initial acquisition
199     my ($n, $MAXDISTANCE) = (0, 1.0);
200     my %peer_time;
201     my %peer_time_rms;
202     my %peer_count;
203     my %peer_delay;
204     my %peer_disp;
205     my %peer_dist;
206     my %peer_ident;
207     my %peer_tmin;
208     my %peer_tmax;
209     my @Fld;
210     my ($i, $j);
211     my ($dist, $offs);
212     while (<INPUT>) {
213         chop;   # strip record separator
214         @Fld = split;
215         next if ($#Fld < 6);
216 #NTPv3: 50529 83316.249 127.127.8.1 9674 0.008628 0.00000 0.00700
217 #NTPv3: day, sec.msec, addr, status, offset, delay, dispersion
218 #NTPv4: 51333 56042.037 127.127.8.1 94f5 -0.000014657 0.000000000 0.000000000 0.000013214
219 #NTPv4: day, sec.msec, addr, status, offset, delay, dispersion, skew
220
221         $dist = $Fld[6] + $Fld[5] / 2;
222         next if ($dist > $MAXDISTANCE);
223         $offs = $Fld[4];
224         if ($offs > $skip_time_steps || $offs < -$skip_time_steps) {
225             warn "ignoring peer offset $offs (file $fname, line $.)\n";
226             next
227         }
228         $i = $n;
229         for ($j = 0; $j < $n; $j++) {
230             if ($Fld[2] eq $peer_ident{$j}) {
231                 $i = $j;                # peer found
232                 last;
233             }
234         }
235         if ($i == $n) {         # add new peer
236             $peer_ident{$i} = $Fld[2];
237             $peer_tmax{$i} = $peer_dist{$i} = -1e9;
238             $peer_tmin{$i} = 1e9;
239             $peer_time{$i} = $peer_time_rms{$i} = 0;
240             $peer_delay{$i} = $peer_disp{$i} = 0;
241             $peer_count{$i} = 0;
242             $n++;
243         }
244         $peer_count{$i}++;
245         $peer_tmax{$i} = max($peer_tmax{$i}, $offs);
246         $peer_tmin{$i} = min($peer_tmin{$i}, $offs);
247         $peer_dist{$i} = max($peer_dist{$i}, $dist);
248         $peer_time{$i} += $offs;
249         $peer_time_rms{$i} += $offs * $offs;
250         $peer_delay{$i} += $Fld[5];
251         $peer_disp{$i} += $Fld[6];
252     }
253     close INPUT;
254     print OUTPUT
255 "       ident     cnt     mean     rms      max     delay     dist     disp\n";
256     print OUTPUT
257 "==========================================================================\n";
258     my @lines = ();
259     for ($i = 0; $i < $n; $i++) {
260         next if $peer_count{$i} < 2;
261         $peer_time{$i} /= $peer_count{$i};
262         eval { $peer_time_rms{$i} = sqrt($peer_time_rms{$i} / $peer_count{$i} -
263                                          $peer_time{$i} * $peer_time{$i}); };
264         $peer_time_rms{$i} = 0, warn $@ if $@;
265         $peer_delay{$i} /= $peer_count{$i};
266         $peer_disp{$i} /= $peer_count{$i};
267         $peer_tmax{$i} = $peer_tmax{$i} - $peer_time{$i};
268         $peer_tmin{$i} = $peer_time{$i} - $peer_tmin{$i};
269         if ($peer_tmin{$i} > $peer_tmax{$i}) {  # can this happen at all?
270             $peer_tmax{$i} = $peer_tmin{$i};
271         }
272         push @lines, sprintf
273             "%-15s %4d %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
274             $peer_ident{$i}, $peer_count{$i}, $peer_time{$i} * 1e3,
275             $peer_time_rms{$i} * 1e3, $peer_tmax{$i} * 1e3,
276             $peer_delay{$i} * 1e3, $peer_dist{$i} * 1e3, $peer_disp{$i} * 1e3;
277     }
278     print OUTPUT sort @lines;
279     close OUTPUT;
280 }
281
282 sub do_clock
283 {
284     my ($directory, $fname, $out_file) = @_;
285     print "$directory/$fname\n";
286     open INPUT, "$directory/$fname";
287     open OUTPUT, ">>$out_file" or die "can't open $out_file: $!";
288     print OUTPUT "$fname\n";
289     close INPUT;
290     close OUTPUT;
291 }
292
293 sub peer_summary
294 {
295     my $in_file = shift;
296     my ($i, $j, $n);
297     my (%peer_ident, %peer_count, %peer_mean, %peer_var, %peer_max);
298     my (%peer_1, %peer_2, %peer_3, %peer_4);
299     my $dist;
300     my $max;
301     open INPUT, "<$in_file" or die "can't open $in_file: $!";
302     my @Fld;
303     $n = 0;
304     while (<INPUT>) {
305         chop;   # strip record separator
306         @Fld = split;
307         next if ($#Fld < 7 || $Fld[0] eq 'ident');
308         $i = $n;
309         for ($j = 0; $j < $n; $j++) {
310             if ($Fld[0] eq $peer_ident{$j}) {
311                 $i = $j;
312                 last;                   # peer found
313             }
314         }
315         if ($i == $n) {                 # add new peer
316             $peer_count{$i} = $peer_mean{$i} = $peer_var{$i} = 0;
317             $peer_max{$i} = 0;
318             $peer_1{$i} = $peer_2{$i} = $peer_3{$i} = $peer_4{$i} = 0;
319             $peer_ident{$i} = $Fld[0];
320             ++$n;
321         }
322         $dist = $Fld[6] - $Fld[5] / 2;
323         if ($dist < $peer_dist_limit) {
324             $peer_count{$i}++;
325             $peer_mean{$i} += $Fld[2];
326             $peer_var{$i} += $Fld[3] * $Fld[3];
327             $max = $Fld[4];
328             $peer_max{$i} = max($peer_max{$i}, $max);
329             if ($max > 1) {
330                 $peer_1{$i}++;
331                 if ($max > 5) {
332                     $peer_2{$i}++;
333                     if ($max > 10) {
334                         $peer_3{$i}++;
335                         if ($max > 50) {
336                             $peer_4{$i}++;
337                         }
338                     }
339                 }
340             }
341         }
342         else {
343             warn "dist exceeds limit: $dist (file $in_file, line $.)\n";
344         }
345     }
346     close INPUT;
347     my @lines = ();
348     print
349         "       host     days    mean       rms       max   >1  >5 >10 >50\n";
350     print
351         "==================================================================\n";
352     for ($i = 0; $i < $n; $i++) {
353         next if ($peer_count{$i} < 2);
354         $peer_mean{$i} /= $peer_count{$i};
355         eval { $peer_var{$i} = sqrt($peer_var{$i} / $peer_count{$i} -
356                                     $peer_mean{$i} * $peer_mean{$i}); };
357         $peer_var{$i} = 0, warn $@ if $@;
358         push @lines, sprintf
359             "%-15s %3d %9.3f% 9.3f %9.3f %3d %3d %3d %3d\n",
360             $peer_ident{$i}, $peer_count{$i}, $peer_mean{$i}, $peer_var{$i},
361             $peer_max{$i}, $peer_1{$i}, $peer_2{$i}, $peer_3{$i}, $peer_4{$i};
362     }
363     print sort @lines;
364 }
365
366 @summary_opts@
367
368 1;
369 __END__