Annotation of embedaddon/ntp/scripts/summary.in, revision 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>