File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / scripts / summary.in
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: #! @PATH_PERL@ -w
    2: # $Id: summary.in,v 1.1 2012/05/29 12:08:38 misho 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, 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>