Annotation of embedaddon/ntp/scripts/summary.in, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>