1abb0f93cSkardel#! @PATH_PERL@ -w 2*eabc0478Schristos# @configure_input@ 3cdfa2a7eSchristos# Id 4abb0f93cSkardel# Perl version of (summary.sh, loop.awk, peer.awk): 5abb0f93cSkardel# Create summaries from xntpd's loop and peer statistics. 6abb0f93cSkardel# 7abb0f93cSkardel# Copyright (c) 1997, 1999 by Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> 8abb0f93cSkardel# 9abb0f93cSkardel# This program is free software; you can redistribute it and/or modify 10abb0f93cSkardel# it under the terms of the GNU General Public License as published by 11abb0f93cSkardel# the Free Software Foundation; either version 2 of the License, or 12abb0f93cSkardel# (at your option) any later version. 13abb0f93cSkardel# 14abb0f93cSkardel# This program is distributed in the hope that it will be useful, but 15abb0f93cSkardel# WITHOUT ANY WARRANTY; without even the implied warranty of 16abb0f93cSkardel# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17abb0f93cSkardel# General Public License for more details. 18abb0f93cSkardel# 19abb0f93cSkardel# You should have received a copy of the GNU General Public License 20abb0f93cSkardel# along with this program; if not, write to the Free Software 21abb0f93cSkardel# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 228585484eSchristospackage summary; 238585484eSchristosuse 5.006_000; 24abb0f93cSkardeluse strict; 25abb0f93cSkardel 268585484eSchristosmy ($log_date_pattern, $statsdir, $outputdir, $skip_time_steps, $startdate, 278585484eSchristos $enddate, $peer_dist_limit); 28abb0f93cSkardel 298585484eSchristosexit run(@ARGV) unless caller; 30abb0f93cSkardel 318585484eSchristossub run { 328585484eSchristos my $opts; 338585484eSchristos if (!processOptions(\@ARGV, $opts)) { 348585484eSchristos usage(1); 358585484eSchristos }; 36abb0f93cSkardel 378585484eSchristos $log_date_pattern = '[12]\d{3}[01]\d[0-3]\d'; 388585484eSchristos $statsdir = $opts->{directory}; 398585484eSchristos $outputdir = $opts->{'output-directory'}; 408585484eSchristos $skip_time_steps = $opts->{'skip-time-steps'}; 418585484eSchristos $startdate = $opts->{'start-date'}; 428585484eSchristos $enddate = $opts->{'end-date'}; 438585484eSchristos if (!$enddate){ 448585484eSchristos $enddate = `date -u +%Y%m%d`; 458585484eSchristos chomp $enddate; 468585484eSchristos --$enddate; 47abb0f93cSkardel } 488585484eSchristos $peer_dist_limit = $opts->{'peer-dist-limit'}; 49abb0f93cSkardel 50abb0f93cSkardel # check possibly current values of options 51abb0f93cSkardel die "$statsdir: no such directory" unless (-d $statsdir); 52abb0f93cSkardel die "$outputdir: no such directory" unless (-d $outputdir); 53abb0f93cSkardel die "$skip_time_steps: skip-time-steps must be positive" 54abb0f93cSkardel unless ($skip_time_steps >= 0.0); 55abb0f93cSkardel die "$startdate: invalid start date|$`|$&|$'" 56abb0f93cSkardel unless ($startdate =~ m/.*$log_date_pattern$/); 57abb0f93cSkardel die "$enddate: invalid end date" 58abb0f93cSkardel unless ($enddate =~ m/.*$log_date_pattern$/); 59abb0f93cSkardel 60abb0f93cSkardel $skip_time_steps = 0.128 if ($skip_time_steps == 0); 61abb0f93cSkardel 628585484eSchristos my $loop_summary="$outputdir/loop_summary"; 638585484eSchristos my $peer_summary="$outputdir/peer_summary"; 648585484eSchristos my $clock_summary="$outputdir/clock_summary"; 658585484eSchristos my (@loopfiles, @peerfiles, @clockfiles); 668585484eSchristos 678585484eSchristos print STDERR "Creating summaries from $statsdir ($startdate to $enddate)\n"; 688585484eSchristos 698585484eSchristos opendir SDIR, $statsdir or die "directory ${statsdir}: $!"; 708585484eSchristos rewinddir SDIR; 718585484eSchristos @loopfiles=sort grep /loop.*$log_date_pattern/, readdir SDIR; 728585484eSchristos rewinddir SDIR; 738585484eSchristos @peerfiles=sort grep /peer.*$log_date_pattern/, readdir SDIR; 748585484eSchristos rewinddir SDIR; 758585484eSchristos @clockfiles=sort grep /clock.*$log_date_pattern/, readdir SDIR; 768585484eSchristos closedir SDIR; 778585484eSchristos 788585484eSchristos # remove old summary files 798585484eSchristos for ($loop_summary, $peer_summary, $clock_summary) { unlink $_ if -f $_ }; 808585484eSchristos 818585484eSchristos my $date; 828585484eSchristos for (@loopfiles) { 838585484eSchristos $date = $_; $date =~ s/.*($log_date_pattern)$/$1/; 848585484eSchristos if ($date ge $startdate && $date le $enddate) { 858585484eSchristos do_loop($statsdir, $_, $loop_summary); 868585484eSchristos } 878585484eSchristos } 888585484eSchristos 898585484eSchristos for (@peerfiles) { 908585484eSchristos $date = $_; $date =~ s/.*($log_date_pattern)$/$1/; 918585484eSchristos if ($date ge $startdate && $date le $enddate) { 928585484eSchristos do_peer($statsdir, $_, $peer_summary); 938585484eSchristos } 948585484eSchristos } 958585484eSchristos 968585484eSchristos for (@clockfiles) { 978585484eSchristos $date = $_; $date =~ s/.*($log_date_pattern)$/$1/; 988585484eSchristos if ($date ge $startdate && $date le $enddate) { 998585484eSchristos do_clock($statsdir, $_, $clock_summary); 1008585484eSchristos } 1018585484eSchristos } 1028585484eSchristos 1038585484eSchristos print STDERR "Creating peer summary with limit $peer_dist_limit\n"; 1048585484eSchristos peer_summary($peer_summary) if (-f $peer_summary); 1058585484eSchristos} 1068585484eSchristos 107abb0f93cSkardelsub min 108abb0f93cSkardel{ 109abb0f93cSkardel my ($result, @rest) = @_; 110abb0f93cSkardel map { $result = $_ if ($_ < $result) } @rest; 111abb0f93cSkardel return($result); 112abb0f93cSkardel} 113abb0f93cSkardel 114abb0f93cSkardelsub max 115abb0f93cSkardel{ 116abb0f93cSkardel my ($result, @rest) = @_; 117abb0f93cSkardel map { $result = $_ if ($_ > $result) } @rest; 118abb0f93cSkardel return($result); 119abb0f93cSkardel} 120abb0f93cSkardel 121abb0f93cSkardel# calculate mean, range, and standard deviation for offset and frequency 122abb0f93cSkardelsub do_loop 123abb0f93cSkardel{ 124abb0f93cSkardel my ($directory, $fname, $out_file) = @_; 125abb0f93cSkardel print "$directory/$fname\n"; 126abb0f93cSkardel open INPUT, "$directory/$fname" or warn "can't open $directory/$fname: $!"; 127abb0f93cSkardel open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; 128abb0f93cSkardel print OUTPUT "$fname\n"; 129abb0f93cSkardel my ($loop_tmax, $loop_fmax) = (-1e9, -1e9); 130abb0f93cSkardel my ($loop_tmin, $loop_fmin) = (1e9, 1e9); 131abb0f93cSkardel my ($loop_time_rms, $loop_freq_rms) = (0, 0); 132abb0f93cSkardel my $loop_count = 0; 133abb0f93cSkardel my $loop_time = 0; 134abb0f93cSkardel my $loop_freq = 0; 135abb0f93cSkardel my ($freq, $offs); 136abb0f93cSkardel my @Fld; 137abb0f93cSkardel while (<INPUT>) { 138abb0f93cSkardel chop; # strip record separator 139abb0f93cSkardel @Fld = split; 140abb0f93cSkardel next if ($#Fld < 4); 141abb0f93cSkardel#NTPv3: 50529 74356.259 -0.000112 16.1230 8 142abb0f93cSkardel#NTPv3: day, sec.msec, offset, drift_comp, sys_poll 143abb0f93cSkardel#NTPv4: 51333 54734.582 0.000001648 16.981964 0.000001094 0.020938 6 144abb0f93cSkardel#NTPv4: day, sec.msec, offset, drift_comp, sys_error, clock_stabil, sys_poll 145abb0f93cSkardel if ($Fld[2] > $skip_time_steps || $Fld[2] < -$skip_time_steps) { 146abb0f93cSkardel warn "ignoring loop offset $Fld[2] (file $fname, line $.)\n"; 147abb0f93cSkardel next 148abb0f93cSkardel } 149abb0f93cSkardel $loop_count++; 150abb0f93cSkardel ($offs, $freq) = ($Fld[2], $Fld[3]); 151abb0f93cSkardel $loop_tmax = max($loop_tmax, $offs); 152abb0f93cSkardel $loop_tmin = min($loop_tmin, $offs); 153abb0f93cSkardel $loop_fmax = max($loop_fmax, $freq); 154abb0f93cSkardel $loop_fmin = min($loop_fmin, $freq); 155abb0f93cSkardel $loop_time += $offs; 156abb0f93cSkardel $loop_time_rms += $offs * $offs; 157abb0f93cSkardel $loop_freq += $freq; 158abb0f93cSkardel $loop_freq_rms += $freq * $freq; 159abb0f93cSkardel } 160abb0f93cSkardel close INPUT; 161abb0f93cSkardel if ($loop_count > 1) { 162abb0f93cSkardel $loop_time /= $loop_count; 163abb0f93cSkardel $loop_time_rms = $loop_time_rms / $loop_count - $loop_time * $loop_time; 164abb0f93cSkardel if ($loop_time_rms < 0) { 165abb0f93cSkardel warn "loop_time_rms: $loop_time_rms < 0"; 166abb0f93cSkardel $loop_time_rms = 0; 167abb0f93cSkardel } 168abb0f93cSkardel $loop_time_rms = sqrt($loop_time_rms); 169abb0f93cSkardel $loop_freq /= $loop_count; 170abb0f93cSkardel $loop_freq_rms = $loop_freq_rms / $loop_count - $loop_freq * $loop_freq; 171abb0f93cSkardel if ($loop_freq_rms < 0) { 172abb0f93cSkardel warn "loop_freq_rms: $loop_freq_rms < 0"; 173abb0f93cSkardel $loop_freq_rms = 0; 174abb0f93cSkardel } 175abb0f93cSkardel $loop_freq_rms = sqrt($loop_freq_rms); 176abb0f93cSkardel printf OUTPUT 177abb0f93cSkardel ("loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n", 178abb0f93cSkardel $loop_count, ($loop_tmax + $loop_tmin) / 2 * 1e6, 179abb0f93cSkardel ($loop_tmax - $loop_tmin) / 2 * 1e6, $loop_time_rms * 1e6, 180abb0f93cSkardel ($loop_fmax + $loop_fmin) / 2, ($loop_fmax - $loop_fmin) / 2, 181abb0f93cSkardel $loop_freq_rms); 182abb0f93cSkardel } 183abb0f93cSkardel else { 184abb0f93cSkardel warn "no valid lines in $directory/$fname"; 185abb0f93cSkardel } 186abb0f93cSkardel close OUTPUT 187abb0f93cSkardel} 188abb0f93cSkardel 189abb0f93cSkardel# calculate mean, standard deviation, maximum offset, mean dispersion, 190abb0f93cSkardel# and maximum distance for each peer 191abb0f93cSkardelsub do_peer 192abb0f93cSkardel{ 193abb0f93cSkardel my ($directory, $fname, $out_file) = @_; 194abb0f93cSkardel print "$directory/$fname\n"; 195abb0f93cSkardel open INPUT, "$directory/$fname" or warn "can't open $directory/$fname: $!"; 196abb0f93cSkardel open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; 197abb0f93cSkardel print OUTPUT "$fname\n"; 198abb0f93cSkardel# we toss out all distances greater than one second on the assumption the 199abb0f93cSkardel# peer is in initial acquisition 200abb0f93cSkardel my ($n, $MAXDISTANCE) = (0, 1.0); 201abb0f93cSkardel my %peer_time; 202abb0f93cSkardel my %peer_time_rms; 203abb0f93cSkardel my %peer_count; 204abb0f93cSkardel my %peer_delay; 205abb0f93cSkardel my %peer_disp; 206abb0f93cSkardel my %peer_dist; 207abb0f93cSkardel my %peer_ident; 208abb0f93cSkardel my %peer_tmin; 209abb0f93cSkardel my %peer_tmax; 210abb0f93cSkardel my @Fld; 211abb0f93cSkardel my ($i, $j); 212abb0f93cSkardel my ($dist, $offs); 213abb0f93cSkardel while (<INPUT>) { 214abb0f93cSkardel chop; # strip record separator 215abb0f93cSkardel @Fld = split; 216abb0f93cSkardel next if ($#Fld < 6); 217abb0f93cSkardel#NTPv3: 50529 83316.249 127.127.8.1 9674 0.008628 0.00000 0.00700 218abb0f93cSkardel#NTPv3: day, sec.msec, addr, status, offset, delay, dispersion 219abb0f93cSkardel#NTPv4: 51333 56042.037 127.127.8.1 94f5 -0.000014657 0.000000000 0.000000000 0.000013214 220abb0f93cSkardel#NTPv4: day, sec.msec, addr, status, offset, delay, dispersion, skew 221abb0f93cSkardel 222abb0f93cSkardel $dist = $Fld[6] + $Fld[5] / 2; 223abb0f93cSkardel next if ($dist > $MAXDISTANCE); 224abb0f93cSkardel $offs = $Fld[4]; 225abb0f93cSkardel if ($offs > $skip_time_steps || $offs < -$skip_time_steps) { 226abb0f93cSkardel warn "ignoring peer offset $offs (file $fname, line $.)\n"; 227abb0f93cSkardel next 228abb0f93cSkardel } 229abb0f93cSkardel $i = $n; 230abb0f93cSkardel for ($j = 0; $j < $n; $j++) { 231abb0f93cSkardel if ($Fld[2] eq $peer_ident{$j}) { 232abb0f93cSkardel $i = $j; # peer found 233abb0f93cSkardel last; 234abb0f93cSkardel } 235abb0f93cSkardel } 236abb0f93cSkardel if ($i == $n) { # add new peer 237abb0f93cSkardel $peer_ident{$i} = $Fld[2]; 238abb0f93cSkardel $peer_tmax{$i} = $peer_dist{$i} = -1e9; 239abb0f93cSkardel $peer_tmin{$i} = 1e9; 240abb0f93cSkardel $peer_time{$i} = $peer_time_rms{$i} = 0; 241abb0f93cSkardel $peer_delay{$i} = $peer_disp{$i} = 0; 242abb0f93cSkardel $peer_count{$i} = 0; 243abb0f93cSkardel $n++; 244abb0f93cSkardel } 245abb0f93cSkardel $peer_count{$i}++; 246abb0f93cSkardel $peer_tmax{$i} = max($peer_tmax{$i}, $offs); 247abb0f93cSkardel $peer_tmin{$i} = min($peer_tmin{$i}, $offs); 248abb0f93cSkardel $peer_dist{$i} = max($peer_dist{$i}, $dist); 249abb0f93cSkardel $peer_time{$i} += $offs; 250abb0f93cSkardel $peer_time_rms{$i} += $offs * $offs; 251abb0f93cSkardel $peer_delay{$i} += $Fld[5]; 252abb0f93cSkardel $peer_disp{$i} += $Fld[6]; 253abb0f93cSkardel } 254abb0f93cSkardel close INPUT; 255abb0f93cSkardel print OUTPUT 256abb0f93cSkardel" ident cnt mean rms max delay dist disp\n"; 257abb0f93cSkardel print OUTPUT 258abb0f93cSkardel"==========================================================================\n"; 259abb0f93cSkardel my @lines = (); 260abb0f93cSkardel for ($i = 0; $i < $n; $i++) { 261abb0f93cSkardel next if $peer_count{$i} < 2; 262abb0f93cSkardel $peer_time{$i} /= $peer_count{$i}; 263abb0f93cSkardel eval { $peer_time_rms{$i} = sqrt($peer_time_rms{$i} / $peer_count{$i} - 264abb0f93cSkardel $peer_time{$i} * $peer_time{$i}); }; 265abb0f93cSkardel $peer_time_rms{$i} = 0, warn $@ if $@; 266abb0f93cSkardel $peer_delay{$i} /= $peer_count{$i}; 267abb0f93cSkardel $peer_disp{$i} /= $peer_count{$i}; 268abb0f93cSkardel $peer_tmax{$i} = $peer_tmax{$i} - $peer_time{$i}; 269abb0f93cSkardel $peer_tmin{$i} = $peer_time{$i} - $peer_tmin{$i}; 270abb0f93cSkardel if ($peer_tmin{$i} > $peer_tmax{$i}) { # can this happen at all? 271abb0f93cSkardel $peer_tmax{$i} = $peer_tmin{$i}; 272abb0f93cSkardel } 273abb0f93cSkardel push @lines, sprintf 274abb0f93cSkardel "%-15s %4d %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n", 275abb0f93cSkardel $peer_ident{$i}, $peer_count{$i}, $peer_time{$i} * 1e3, 276abb0f93cSkardel $peer_time_rms{$i} * 1e3, $peer_tmax{$i} * 1e3, 277abb0f93cSkardel $peer_delay{$i} * 1e3, $peer_dist{$i} * 1e3, $peer_disp{$i} * 1e3; 278abb0f93cSkardel } 279abb0f93cSkardel print OUTPUT sort @lines; 280abb0f93cSkardel close OUTPUT; 281abb0f93cSkardel} 282abb0f93cSkardel 283abb0f93cSkardelsub do_clock 284abb0f93cSkardel{ 285abb0f93cSkardel my ($directory, $fname, $out_file) = @_; 286abb0f93cSkardel print "$directory/$fname\n"; 287abb0f93cSkardel open INPUT, "$directory/$fname"; 288abb0f93cSkardel open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; 289abb0f93cSkardel print OUTPUT "$fname\n"; 290abb0f93cSkardel close INPUT; 291abb0f93cSkardel close OUTPUT; 292abb0f93cSkardel} 293abb0f93cSkardel 294abb0f93cSkardelsub peer_summary 295abb0f93cSkardel{ 296abb0f93cSkardel my $in_file = shift; 297abb0f93cSkardel my ($i, $j, $n); 298abb0f93cSkardel my (%peer_ident, %peer_count, %peer_mean, %peer_var, %peer_max); 299abb0f93cSkardel my (%peer_1, %peer_2, %peer_3, %peer_4); 300abb0f93cSkardel my $dist; 301abb0f93cSkardel my $max; 302abb0f93cSkardel open INPUT, "<$in_file" or die "can't open $in_file: $!"; 303abb0f93cSkardel my @Fld; 304abb0f93cSkardel $n = 0; 305abb0f93cSkardel while (<INPUT>) { 306abb0f93cSkardel chop; # strip record separator 307abb0f93cSkardel @Fld = split; 308abb0f93cSkardel next if ($#Fld < 7 || $Fld[0] eq 'ident'); 309abb0f93cSkardel $i = $n; 310abb0f93cSkardel for ($j = 0; $j < $n; $j++) { 311abb0f93cSkardel if ($Fld[0] eq $peer_ident{$j}) { 312abb0f93cSkardel $i = $j; 313abb0f93cSkardel last; # peer found 314abb0f93cSkardel } 315abb0f93cSkardel } 316abb0f93cSkardel if ($i == $n) { # add new peer 317abb0f93cSkardel $peer_count{$i} = $peer_mean{$i} = $peer_var{$i} = 0; 318abb0f93cSkardel $peer_max{$i} = 0; 319abb0f93cSkardel $peer_1{$i} = $peer_2{$i} = $peer_3{$i} = $peer_4{$i} = 0; 320abb0f93cSkardel $peer_ident{$i} = $Fld[0]; 321abb0f93cSkardel ++$n; 322abb0f93cSkardel } 323abb0f93cSkardel $dist = $Fld[6] - $Fld[5] / 2; 324abb0f93cSkardel if ($dist < $peer_dist_limit) { 325abb0f93cSkardel $peer_count{$i}++; 326abb0f93cSkardel $peer_mean{$i} += $Fld[2]; 327abb0f93cSkardel $peer_var{$i} += $Fld[3] * $Fld[3]; 328abb0f93cSkardel $max = $Fld[4]; 329abb0f93cSkardel $peer_max{$i} = max($peer_max{$i}, $max); 330abb0f93cSkardel if ($max > 1) { 331abb0f93cSkardel $peer_1{$i}++; 332abb0f93cSkardel if ($max > 5) { 333abb0f93cSkardel $peer_2{$i}++; 334abb0f93cSkardel if ($max > 10) { 335abb0f93cSkardel $peer_3{$i}++; 336abb0f93cSkardel if ($max > 50) { 337abb0f93cSkardel $peer_4{$i}++; 338abb0f93cSkardel } 339abb0f93cSkardel } 340abb0f93cSkardel } 341abb0f93cSkardel } 342abb0f93cSkardel } 343abb0f93cSkardel else { 344abb0f93cSkardel warn "dist exceeds limit: $dist (file $in_file, line $.)\n"; 345abb0f93cSkardel } 346abb0f93cSkardel } 347abb0f93cSkardel close INPUT; 348abb0f93cSkardel my @lines = (); 349abb0f93cSkardel print 350abb0f93cSkardel " host days mean rms max >1 >5 >10 >50\n"; 351abb0f93cSkardel print 352abb0f93cSkardel "==================================================================\n"; 353abb0f93cSkardel for ($i = 0; $i < $n; $i++) { 354abb0f93cSkardel next if ($peer_count{$i} < 2); 355abb0f93cSkardel $peer_mean{$i} /= $peer_count{$i}; 356abb0f93cSkardel eval { $peer_var{$i} = sqrt($peer_var{$i} / $peer_count{$i} - 357abb0f93cSkardel $peer_mean{$i} * $peer_mean{$i}); }; 358abb0f93cSkardel $peer_var{$i} = 0, warn $@ if $@; 359abb0f93cSkardel push @lines, sprintf 360abb0f93cSkardel "%-15s %3d %9.3f% 9.3f %9.3f %3d %3d %3d %3d\n", 361abb0f93cSkardel $peer_ident{$i}, $peer_count{$i}, $peer_mean{$i}, $peer_var{$i}, 362abb0f93cSkardel $peer_max{$i}, $peer_1{$i}, $peer_2{$i}, $peer_3{$i}, $peer_4{$i}; 363abb0f93cSkardel } 364abb0f93cSkardel print sort @lines; 365abb0f93cSkardel} 366abb0f93cSkardel 3678585484eSchristos@summary_opts@ 368abb0f93cSkardel 3698585484eSchristos1; 3708585484eSchristos__END__ 371