Annotation of embedaddon/ntp/scripts/monitoring/ntploopwatch, revision 1.1
1.1 ! misho 1: #!/usr/bin/perl -w
! 2: ;# --*-perl-*--
! 3: ;#
! 4: ;# /src/NTP/ntp4-dev/scripts/monitoring/ntploopwatch,v 4.7 2004/11/14 16:11:05 kardel RELEASE_20050508_A
! 5: ;#
! 6: ;# process loop filter statistics file and either
! 7: ;# - show statistics periodically using gnuplot
! 8: ;# - or print a single plot
! 9: ;#
! 10: ;# Copyright (c) 1992-1998
! 11: ;# Rainer Pruy, Friedrich-Alexander Universität Erlangen-Nürnberg
! 12: ;#
! 13: ;#
! 14: ;#############################################################
! 15: $0 =~ s!^.*/([^/]+)$!$1!;
! 16: $F = ' ' x length($0);
! 17: $|=1;
! 18:
! 19: $ENV{'SHELL'} = '/bin/sh'; # use bourne shell
! 20:
! 21: undef($config);
! 22: undef($workdir);
! 23: undef($PrintIt);
! 24: undef($samples);
! 25: undef($StartTime);
! 26: undef($EndTime);
! 27: ($a,$b) if 0; # keep -w happy
! 28: $usage = <<"E-O-P";
! 29: usage:
! 30: to watch statistics permanently:
! 31: $0 [-v[<level>]] [-c <config-file>] [-d <working-dir>]
! 32: $F [-h <hostname>]
! 33:
! 34: to get a single print out specify also
! 35: $F -P[<printer>] [-s<samples>]
! 36: $F [-S <start-time>] [-E <end-time>]
! 37: $F [-Y <MaxOffs>] [-y <MinOffs>]
! 38:
! 39: If You like long option names, You can use:
! 40: -help
! 41: -c +config
! 42: -d +directory
! 43: -h +host
! 44: -v +verbose[=<level>]
! 45: -P +printer[=<printer>]
! 46: -s +samples[=<samples>]
! 47: -S +starttime
! 48: -E +endtime
! 49: -Y +maxy
! 50: -y +miny
! 51:
! 52: If <printer> contains a '/' (slash character) output is directed to
! 53: a file of this name instead of delivered to a printer.
! 54: E-O-P
! 55:
! 56: ;# add directory to look for lr.pl and timelocal.pl (in front of current list)
! 57: unshift(@INC,".");
! 58:
! 59: require "lr.pl"; # linear regresion routines
! 60:
! 61: $MJD_1970 = 40587; # from ntp.h (V3)
! 62: $RecordSize = 48; # usually a line fits into 42 bytes
! 63: $MinClip = 1; # clip Y scales with greater range than this
! 64:
! 65: ;# largest extension of Y scale from mean value, factor for standart deviation
! 66: $FuzzLow = 2.2; # for side closer to zero
! 67: $FuzzBig = 1.8; # for side farther from zero
! 68:
! 69: require "ctime.pl";
! 70: require "timelocal.pl";
! 71: ;# early distributions of ctime.pl had a bug
! 72: $ENV{'TZ'} = 'MET' unless defined $ENV{'TZ'} || $[ > 4.010;
! 73: if (defined(@ctime'MoY))
! 74: {
! 75: *Month=*ctime'MoY;
! 76: *Day=*ctime'DoW;
! 77: } # ' re-sync emacs fontification
! 78: else
! 79: {
! 80: @Month = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
! 81: @Day = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
! 82: }
! 83: print @ctime'DoW if 0; # ' re-sync emacs fontification
! 84:
! 85: ;# max number of days per month
! 86: @MaxNumDaysPerMonth = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
! 87:
! 88: ;# config settable parameters
! 89: $delay = 60;
! 90: $srcprefix = "./var\@\$STATHOST/loopstats.";
! 91: $showoffs = 1;
! 92: $showfreq = 1;
! 93: $showcmpl = 0;
! 94: $showoreg = 0;
! 95: $showfreg = 0;
! 96: undef($timebase);
! 97: undef($freqbase);
! 98: undef($cmplscale);
! 99: undef($MaxY);
! 100: undef($MinY);
! 101: $deltaT = 512; # indicate sample data gaps greater than $deltaT seconds
! 102: $verbose = 1;
! 103:
! 104: while($_ = shift(@ARGV))
! 105: {
! 106: (/^[+-]help$/) && die($usage);
! 107:
! 108: (/^-c$/ || /^\+config$/) &&
! 109: (@ARGV || die($usage), $config = shift(@ARGV), next);
! 110:
! 111: (/^-d$/ || /^\+directory$/) &&
! 112: (@ARGV || die($usage), $workdir = shift(@ARGV), next);
! 113:
! 114: (/^-h$/ || /^\+host$/) &&
! 115: (@ARGV || die($usage), $STATHOST = shift, next);
! 116:
! 117: (/^-v(\d*)$/ || /^\+verbose=?(\d*)$/) &&
! 118: ($verbose=($1 eq "") ? 1 : $1, next);
! 119:
! 120: (/^-P(\S*)$/ || /^\+[Pp]rinter=?(\S*)$/) &&
! 121: ($PrintIt = $1, $verbose==1 && ($verbose = 0), next);
! 122:
! 123: (/^-s(\d*)$/ || /^\+samples=?(\d*)$/) &&
! 124: (($samples = ($1 eq "") ? (shift || die($usage)): $1), next);
! 125:
! 126: (/^-S$/ || /^\+[Ss]tart[Tt]ime$/) &&
! 127: (@ARGV || die($usage), $StartTime=&date_time_spec2seconds(shift),next);
! 128:
! 129: (/^-E$/ || /^\+[Ee]nd[Tt]ime$/) &&
! 130: (@ARGV || die($usage), $EndTime = &date_time_spec2seconds(shift),next);
! 131:
! 132: (/^-Y$/ || /^\+[Mm]ax[Yy]$/) &&
! 133: (@ARGV || die($usage), $MaxY = shift, next);
! 134:
! 135: (/^-y$/ || /^\+[Mm]in[Yy]$/) &&
! 136: (@ARGV || die($usage), $MinY = shift, next);
! 137:
! 138: die("$0: unexpected argument \"$_\"\n$usage");
! 139: }
! 140:
! 141: if (defined($workdir))
! 142: {
! 143: chdir($workdir) ||
! 144: die("$0: failed to change working dir to \"$workdir\": $!\n");
! 145: }
! 146:
! 147: $PrintIt = "ps" if defined($PrintIt) && $PrintIt eq "";
! 148:
! 149: if (!defined($PrintIt))
! 150: {
! 151: defined($samples) &&
! 152: print "WARNING: your samples value may be shadowed by config file settings\n";
! 153: defined($StartTime) &&
! 154: print "WARNING: your StartTime value may be shadowed by config file settings\n";
! 155: defined($EndTime) &&
! 156: print "WARNING: your EndTime value may be shadowed by config file settings\n";
! 157: defined($MaxY) &&
! 158: print "WARNING: your MaxY value may be shadowed by config file settings\n";
! 159: defined($MinY) &&
! 160: print "WARNING: your MinY value may be shadowed by config file settings\n";
! 161:
! 162: ;# check operating environment
! 163: ;#
! 164: ;# gnuplot usually has X support
! 165: ;# I vaguely remember there was one with sunview support
! 166: ;#
! 167: ;# If Your plotcmd can display graphics using some other method
! 168: ;# (Tek window,..) fix the following test
! 169: ;# (or may be, just disable it)
! 170: ;#
! 171: !(defined($ENV{'DISPLAY'}) || defined($ENV{'WINDOW_PARENT'})) &&
! 172: die("Need window system to monitor statistics\n");
! 173: }
! 174:
! 175: ;# configuration file
! 176: $config = "loopwatch.config" unless defined($config);
! 177: ($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]*)$!$1!
! 178: unless defined($STATHOST);
! 179: ($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/$1/;
! 180:
! 181: $srcprefix =~ s/\$STATHOST/$STATHOST/g;
! 182:
! 183: ;# plot command
! 184: @plotcmd=("gnuplot",
! 185: '-title', "Ntp loop filter statistics $STATHOST",
! 186: '-name', "NtpLoopWatch_$STATTAG");
! 187: $tmpfile = "/tmp/ntpstat.$$";
! 188:
! 189: ;# other variables
! 190: $doplot = ""; # assembled command for @plotcmd to display plot
! 191: undef($laststat);
! 192:
! 193: ;# plot value ranges
! 194: undef($mintime);
! 195: undef($maxtime);
! 196: undef($minoffs);
! 197: undef($maxoffs);
! 198: undef($minfreq);
! 199: undef($maxfreq);
! 200: undef($mincmpl);
! 201: undef($maxcmpl);
! 202: undef($miny);
! 203: undef($maxy);
! 204:
! 205: ;# stop operation if plot command dies
! 206: sub sigchld
! 207: {
! 208: local($pid) = wait;
! 209: unlink($tmpfile);
! 210: warn(sprintf("%s: %s died: exit status: %d signal %d\n",
! 211: $0,
! 212: (defined($Plotpid) && $Plotpid == $pid)
! 213: ? "plotcmd" : "unknown child $pid",
! 214: $?>>8,$? & 0xff)) if $?;
! 215: exit(1) if $? && defined($Plotpid) && $pid == $Plotpid;
! 216: }
! 217: &sigchld if 0;
! 218: $SIG{'CHLD'} = "sigchld";
! 219: $SIG{'CLD'} = "sigchld";
! 220:
! 221: sub abort
! 222: {
! 223: unlink($tmpfile);
! 224: defined($Plotpid) && kill('TERM',$Plotpid);
! 225: die("$0: received signal SIG$_[$[] - exiting\n");
! 226: }
! 227: &abort if 0; # make -w happy - &abort IS used
! 228: $SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = $SIG{'PIPE'} = "abort";
! 229:
! 230: ;#
! 231: sub abs
! 232: {
! 233: ($_[$[] < 0) ? -($_[$[]) : $_[$[];
! 234: }
! 235:
! 236: sub boolval
! 237: {
! 238: local($v) = ($_[$[]);
! 239:
! 240: return 1 if ($v eq 'yes') || ($v eq 'y');
! 241: return 1 if ($v =~ /^[0-9]*$/) && ($v != 0);
! 242: return 0;
! 243: }
! 244:
! 245: ;#####################
! 246: ;# start of real work
! 247:
! 248: print "starting plot command (" . join(" ",@plotcmd) . ")\n" if $verbose > 1;
! 249:
! 250: $Plotpid = open(PLOT,"|-");
! 251: select((select(PLOT),$|=1)[$[]); # make PLOT line bufferd
! 252:
! 253: defined($Plotpid) ||
! 254: die("$0: failed to start plot command: $!\n");
! 255:
! 256: unless ($Plotpid)
! 257: {
! 258: ;# child == plot command
! 259: close(STDOUT);
! 260: open(STDOUT,">&STDERR") ||
! 261: die("$0: failed to redirect STDOUT of plot command: $!\n");
! 262:
! 263: print STDOUT "plot command running as $$\n";
! 264:
! 265: exec @plotcmd;
! 266: die("$0: failed to exec (@plotcmd): $!\n");
! 267: exit(1); # in case ...
! 268: }
! 269:
! 270: sub read_config
! 271: {
! 272: local($at) = (stat($config))[$[+9];
! 273: local($_,$c,$v);
! 274:
! 275: (undef($laststat),(print("stat $config failed: $!\n")),return) if ! defined($at);
! 276: return if (defined($laststat) && ($laststat == $at));
! 277: $laststat = $at;
! 278:
! 279: print "reading configuration from \"$config\"\n" if $verbose;
! 280:
! 281: open(CF,"<$config") ||
! 282: (warn("$0: failed to read \"$config\" - using old settings ($!)\n"),
! 283: return);
! 284: while(<CF>)
! 285: {
! 286: chop;
! 287: s/^([^\#]*[^\#\s]?)\s*\#.*$//;
! 288: next if /^\s*$/;
! 289:
! 290: s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/$1=$2/;
! 291:
! 292: ($c,$v) = split(/=/,$_,2);
! 293: print "processing \"$c=$v\"\n" if $verbose > 3;
! 294: ($c eq "delay") && ($delay = $v,1) && next;
! 295: ($c eq 'samples') && (!defined($PrintIt) || !defined($samples)) &&
! 296: ($samples = $v,1) && next;
! 297: ($c eq 'srcprefix') && (($srcprefix=$v)=~s/\$STATHOST/$STATHOST/g,1)
! 298: && next;
! 299: ($c eq 'showoffs') &&
! 300: ($showoffs = boolval($v),1) && next;
! 301: ($c eq 'showfreq') &&
! 302: ($showfreq = boolval($v),1) && next;
! 303: ($c eq 'showcmpl') &&
! 304: ($showcmpl = boolval($v),1) && next;
! 305: ($c eq 'showoreg') &&
! 306: ($showoreg = boolval($v),1) && next;
! 307: ($c eq 'showfreg') &&
! 308: ($showfreg = boolval($v),1) && next;
! 309:
! 310: ($c eq 'exit') && (unlink($tmpfile),die("$0: exit by config request\n"));
! 311:
! 312: ($c eq 'freqbase' ||
! 313: $c eq 'cmplscale') &&
! 314: do {
! 315: if (! defined($v) || $v eq "" || $v eq 'dynamic')
! 316: {
! 317: eval "undef(\$$c);";
! 318: }
! 319: else
! 320: {
! 321: eval "\$$c = \$v;";
! 322: }
! 323: next;
! 324: };
! 325: ($c eq 'timebase') &&
! 326: do {
! 327: if (! defined($v) || $v eq "" || $v eq "dynamic")
! 328: {
! 329: undef($timebase);
! 330: }
! 331: else
! 332: {
! 333: $timebase=&date_time_spec2seconds($v);
! 334: }
! 335: };
! 336: ($c eq 'EndTime') &&
! 337: do {
! 338: next if defined($EndTime) && defined($PrintIt);
! 339: if (! defined($v) || $v eq "" || $v eq "none")
! 340: {
! 341: undef($EndTime);
! 342: }
! 343: else
! 344: {
! 345: $EndTime=&date_time_spec2seconds($v);
! 346: }
! 347: };
! 348: ($c eq 'StartTime') &&
! 349: do {
! 350: next if defined($StartTime) && defined($PrintIt);
! 351: if (! defined($v) || $v eq "" || $v eq "none")
! 352: {
! 353: undef($StartTime);
! 354: }
! 355: else
! 356: {
! 357: $StartTime=&date_time_spec2seconds($v);
! 358: }
! 359: };
! 360:
! 361: ($c eq 'MaxY') &&
! 362: do {
! 363: next if defined($MaxY) && defined($PrintIt);
! 364: if (! defined($v) || $v eq "" || $v eq "none")
! 365: {
! 366: undef($MaxY);
! 367: }
! 368: else
! 369: {
! 370: $MaxY=$v;
! 371: }
! 372: };
! 373:
! 374: ($c eq 'MinY') &&
! 375: do {
! 376: next if defined($MinY) && defined($PrintIt);
! 377: if (! defined($v) || $v eq "" || $v eq "none")
! 378: {
! 379: undef($MinY);
! 380: }
! 381: else
! 382: {
! 383: $MinY=$v;
! 384: }
! 385: };
! 386:
! 387: ($c eq 'deltaT') &&
! 388: do {
! 389: if (!defined($v) || $v eq "")
! 390: {
! 391: undef($deltaT);
! 392: }
! 393: else
! 394: {
! 395: $deltaT = $v;
! 396: }
! 397: next;
! 398: };
! 399: ($c eq 'verbose') && ! defined($PrintIt) &&
! 400: do {
! 401: if (!defined($v) || $v == 0)
! 402: {
! 403: $verbose = 0;
! 404: }
! 405: else
! 406: {
! 407: $verbose = $v;
! 408: }
! 409: next;
! 410: };
! 411: ;# otherwise: silently ignore unrecognized config line
! 412: }
! 413: close(CF);
! 414: ;# set show defaults when nothing selected
! 415: $showoffs = $showfreq = $showcmpl = 1
! 416: unless $showoffs || $showfreq || $showcmpl;
! 417: if ($verbose > 3)
! 418: {
! 419: print "new configuration:\n";
! 420: print " delay\t= $delay\n";
! 421: print " samples\t= $samples\n";
! 422: print " srcprefix\t= $srcprefix\n";
! 423: print " showoffs\t= $showoffs\n";
! 424: print " showfreq\t= $showfreq\n";
! 425: print " showcmpl\t= $showcmpl\n";
! 426: print " showoreg\t= $showoreg\n";
! 427: print " showfreg\t= $showfreg\n";
! 428: printf " timebase\t= %s",defined($timebase)?&ctime($timebase):"dynamic\n";
! 429: printf " freqbase\t= %s\n",defined($freqbase) ?"$freqbase":"dynamic";
! 430: printf " cmplscale\t= %s\n",defined($cmplscale)?"$cmplscale":"dynamic";
! 431: printf " StartTime\t= %s",defined($StartTime)?&ctime($StartTime):"none\n";
! 432: printf " EndTime\t= %s", defined($EndTime) ? &ctime($EndTime):"none\n";
! 433: printf " MaxY\t= %s",defined($MaxY)? $MaxY :"none\n";
! 434: printf " MinY\t= %s",defined($MinY)? $MinY :"none\n";
! 435: print " verbose\t= $verbose\n";
! 436: }
! 437: print "configuration file read\n" if $verbose > 2;
! 438: }
! 439:
! 440: sub make_doplot($$)
! 441: {
! 442: my($lo, $lf) = @_;
! 443: local($c) = ("");
! 444: local($fmt)
! 445: = ("%s \"%s\" using 1:%d title '%s <%lf %lf> %6s' with lines");
! 446: local($regfmt)
! 447: = ("%s ((%lf * x) + %lf) title 'lin. approx. %s (%f t[h]) %s %f <%f> %6s' with lines");
! 448:
! 449: $doplot = " set title 'NTP loopfilter statistics for $STATHOST " .
! 450: "(last $LastCnt samples from $srcprefix*)'\n";
! 451:
! 452: local($xts,$xte,$i,$t);
! 453:
! 454: local($s,$c) = ("");
! 455:
! 456: ;# number of integral seconds to get at least 12 tic marks on x axis
! 457: $t = int(($maxtime - $mintime) / 12 + 0.5);
! 458: $t = 1 unless $t; # prevent $t to be zero
! 459: foreach $i (30,
! 460: 60,5*60,15*60,30*60,
! 461: 60*60,2*60*60,6*60*60,12*60*60,
! 462: 24*60*60,48*60*60)
! 463: {
! 464: last if $t < $i;
! 465: $t = $t - ($t % $i);
! 466: }
! 467: print "time label resolution: $t seconds\n" if $verbose > 1;
! 468:
! 469: ;# make gnuplot use wall clock time labels instead of NTP seconds
! 470: for ($c="", $i = $mintime - ($mintime % $t);
! 471: $i <= $maxtime + $t;
! 472: $i += $t, $c=",")
! 473: {
! 474: $s .= $c;
! 475: ((int($i / $t) % 2) &&
! 476: ($s .= sprintf("'' %lf",($i - $LastTimeBase)/3600))) ||
! 477: (($t <= 60) &&
! 478: ($s .= sprintf("'%d:%02d:%02d' %lf",
! 479: (localtime($i))[$[+2,$[+1,$[+0],
! 480: ($i - $LastTimeBase)/3600)))
! 481: || (($t <= 2*60*60) &&
! 482: ($s .= sprintf("'%d:%02d' %lf",
! 483: (localtime($i))[$[+2,$[+1],
! 484: ($i - $LastTimeBase)/3600)))
! 485: || (($t <= 12*60*60) &&
! 486: ($s .= sprintf("'%s %d:00' %lf",
! 487: $Day[(localtime($i))[$[+6]],
! 488: (localtime($i))[$[+2],
! 489: ($i - $LastTimeBase)/3600)))
! 490: || ($s .= sprintf("'%d.%d-%d:00' %lf",
! 491: (localtime($i))[$[+3,$[+4,$[+2],
! 492: ($i - $LastTimeBase)/3600));
! 493: }
! 494: $doplot .= "set xtics ($s)\n";
! 495:
! 496: chop($xts = &ctime($mintime));
! 497: chop($xte = &ctime($maxtime));
! 498: $doplot .= "set xlabel 'Start: $xts -- Time Scale -- End: $xte'\n";
! 499: $doplot .= "set yrange [" ;
! 500: $doplot .= defined($MinY) ? sprintf("%lf", $MinY) : $miny;
! 501: $doplot .= ':';
! 502: $doplot .= defined($MaxY) ? sprintf("%lf", $MaxY) : $maxy;
! 503: $doplot .= "]\n";
! 504:
! 505: $doplot .= " plot";
! 506: $c = "";
! 507: $showoffs &&
! 508: ($doplot .= sprintf($fmt,$c,$tmpfile,2,
! 509: "offset",
! 510: $minoffs,$maxoffs,
! 511: "[ms]"),
! 512: $c = ",");
! 513: $LastCmplScale = 1 if ! defined($LastCmplScale);
! 514: $showcmpl &&
! 515: ($doplot .= sprintf($fmt,$c,$tmpfile,4,
! 516: "compliance" .
! 517: (&abs($LastCmplScale) > 1
! 518: ? " / $LastCmplScale"
! 519: : (&abs($LastCmplScale) == 1 ? "" : " * ".(1/$LastCmplScale))),
! 520: $mincmpl/$LastCmplScale,$maxcmpl/$LastCmplScale,
! 521: ""),
! 522: $c = ",");
! 523: $LastFreqBase = 0 if ! defined($LastFreqBase);
! 524: $LastFreqBaseString = "?" if ! defined($LastFreqBaseString);
! 525: $FreqScale = 1 if ! defined($FreqScale);
! 526: $FreqScaleInv = 1 if ! defined($FreqScaleInv);
! 527: $showfreq &&
! 528: ($doplot .= sprintf($fmt,$c,$tmpfile,3,
! 529: "frequency" .
! 530: ($LastFreqBase > 0
! 531: ? " - $LastFreqBaseString"
! 532: : ($LastFreqBase == 0 ? "" : " + $LastFreqBaseString")),
! 533: $minfreq * $FreqScale - $LastFreqBase,
! 534: $maxfreq * $FreqScale - $LastFreqBase,
! 535: "[${FreqScaleInv}ppm]"),
! 536: $c = ",");
! 537: $showoreg && $showoffs &&
! 538: ($doplot .= sprintf($regfmt, $c,
! 539: $lo->B(),$lo->A(),
! 540: "offset ",
! 541: $lo->B(),
! 542: (($lo->A()) < 0 ? '-' : '+'),
! 543: &abs($lo->A()), $lo->r(),
! 544: "[ms]"),
! 545: $c = ",");
! 546: $showfreg && $showfreq &&
! 547: ($doplot .= sprintf($regfmt, $c,
! 548: $lf->B() * $FreqScale,
! 549: ($lf->A() + $minfreq) * $FreqScale - $LastFreqBase,
! 550: "frequency",
! 551: $lf->B() * $FreqScale,
! 552: (($lf->A() + $minfreq) * $FreqScale - $LastFreqBase) < 0 ? '-' : '+',
! 553: &abs(($lf->A() + $minfreq) * $FreqScale - $LastFreqBase),
! 554: $lf->r(),
! 555: "[${FreqScaleInv}ppm]"),
! 556: $c = ",");
! 557: $doplot .= "\n";
! 558: }
! 559:
! 560: %F_key = ();
! 561: %F_name = ();
! 562: %F_size = ();
! 563: %F_mtime = ();
! 564: %F_first = ();
! 565: %F_last = ();
! 566:
! 567: sub genfile
! 568: {
! 569: local($cnt,$in,$out,$lo,$lf,@fpos) = @_;
! 570:
! 571: local(@F,@t,$t,$lastT) = ();
! 572: local(@break,@time,@offs,@freq,@cmpl,@loffset,@filekey) = ();
! 573: local($lm,$l,@f);
! 574:
! 575: local($sdir,$sname);
! 576:
! 577: ;# allocate some storage for the tables
! 578: ;# otherwise realloc may get into troubles
! 579: if (defined($StartTime) && defined($EndTime))
! 580: {
! 581: $l = ($EndTime-$StartTime) -$[+1 +1; # worst case: 1 sample per second
! 582: }
! 583: else
! 584: {
! 585: $l = $cnt + 10;
! 586: }
! 587: print "preextending arrays to $l entries\n" if $verbose > 2;
! 588: $#break = $l; for ($i=$[; $i<=$l;$i++) { $break[$i] = 0; }
! 589: $#time = $l; for ($i=$[; $i<=$l;$i++) { $time[$i] = 0; }
! 590: $#offs = $l; for ($i=$[; $i<=$l;$i++) { $offs[$i] = 0; }
! 591: $#freq = $l; for ($i=$[; $i<=$l;$i++) { $freq[$i] = 0; }
! 592: $#cmpl = $l; for ($i=$[; $i<=$l;$i++) { $cmpl[$i] = 0; }
! 593: $#loffset = $l; for ($i=$[; $i<=$l;$i++) { $loffset[$i] = 0; }
! 594: $#filekey = $l; for ($i=$[; $i<=$l;$i++) { $filekey[$i] = 0; }
! 595: ;# now reduce size again
! 596: $#break = $[ - 1;
! 597: $#time = $[ - 1;
! 598: $#offs = $[ - 1;
! 599: $#freq = $[ - 1;
! 600: $#cmpl = $[ - 1;
! 601: $#loffset = $[ - 1;
! 602: $#filekey = $[ - 1;
! 603: print "memory allocation ready\n" if $verbose > 2;
! 604: sleep(3) if $verbose > 1;
! 605:
! 606: $fpos[$[] = '' if !defined($fpos[$[]);
! 607:
! 608: if (index($in,"/") < $[)
! 609: {
! 610: $sdir = ".";
! 611: $sname = $in;
! 612: }
! 613: else
! 614: {
! 615: ($sdir,$sname) = ($in =~ m!^(.*)/([^/]*)!);
! 616: $sname = "" unless defined($sname);
! 617: }
! 618:
! 619: $Ltime = -1 if ! defined($Ltime);
! 620: if (!defined($Lsdir) || $Lsdir ne $sdir || $Ltime != (stat($sdir))[$[+9] ||
! 621: grep($F_mtime{$_} != (stat($F_name{$_}))[$[+9], @F_files))
! 622:
! 623: {
! 624: print "rescanning directory \"$sdir\" for files \"$sname*\"\n"
! 625: if $verbose > 1;
! 626:
! 627: ;# rescan directory on changes
! 628: $Lsdir = $sdir;
! 629: $Ltime = (stat($sdir))[$[+9];
! 630: </X{> if 0; # dummy line - calm down my formatter
! 631: local(@newfiles) = < ${in}*[0-9] >;
! 632: local($st_dev,$st_ino,$st_mtime,$st_size,$name,$key,$modified);
! 633:
! 634: foreach $name (@newfiles)
! 635: {
! 636: ($st_dev,$st_ino,$st_size,$st_mtime) =
! 637: (stat($name))[$[,$[+1,$[+7,$[+9];
! 638: $modified = 0;
! 639: $key = sprintf("%lx|%lu", $st_dev, $st_ino);
! 640:
! 641: print "candidate file \"$name\"",
! 642: (defined($st_dev) ? "" : " failed: $!"),"\n"
! 643: if $verbose > 2;
! 644:
! 645: if (! defined($F_key{$name}) || $F_key{$name} ne $key)
! 646: {
! 647: $F_key{$name} = $key;
! 648: $modified++;
! 649: }
! 650: if (!defined($F_name{$key}) || $F_name{$key} ne $name)
! 651: {
! 652: $F_name{$key} = $name;
! 653: $modified++;
! 654: }
! 655: if (!defined($F_size{$key}) || $F_size{$key} != $st_size)
! 656: {
! 657: $F_size{$key} = $st_size;
! 658: $modified++;
! 659: }
! 660: if (!defined($F_mtime{$key}) || $F_mtime{$key} != $st_mtime)
! 661: {
! 662: $F_mtime{$key} = $st_mtime;
! 663: $modified++;
! 664: }
! 665: if ($modified)
! 666: {
! 667: print "new data \"$name\" key: $key;\n" if $verbose > 1;
! 668: print " size: $st_size; mtime: $st_mtime;\n"
! 669: if $verbose > 1;
! 670: $F_last{$key} = $F_first{$key} = $st_mtime;
! 671: $F_first{$key}--; # prevent zero divide later on
! 672: ;# now compute derivated attributes
! 673: open(IN, "<$name") ||
! 674: do {
! 675: warn "$0: failed to open \"$name\": $!";
! 676: next;
! 677: };
! 678:
! 679: while(<IN>)
! 680: {
! 681: @F = split;
! 682: next if @F < 5;
! 683: next if $F[$[] eq "";
! 684: $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60;
! 685: $t += $F[$[+1];
! 686: $F_first{$key} = $t;
! 687: print "\tfound first entry: $t ",&ctime($t)
! 688: if $verbose > 4;
! 689: last;
! 690: }
! 691: seek(IN,
! 692: ($st_size > 4*$RecordSize) ? $st_size - 4*$RecordSize : 0,
! 693: 0);
! 694: while(<IN>)
! 695: {
! 696: @F = split;
! 697: next if @F < 5;
! 698: next if $F[$[] eq "";
! 699: $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60;
! 700: $t += $F[$[+1];
! 701: $F_last{$key} = $t;
! 702: $_ = <IN>;
! 703: print "\tfound last entry: $t ", &ctime($t)
! 704: if $verbose > 4 && ! defined($_);
! 705: last unless defined($_);
! 706: redo;
! 707: ;# Ok, calm down...
! 708: ;# using $_ = <IN> in conjunction with redo
! 709: ;# is semantically equivalent to the while loop, but
! 710: ;# I needed a one line look ahead and this solution
! 711: ;# was what I thought of first
! 712: ;# and.. If you do not like it dont look
! 713: }
! 714: close(IN);
! 715: print(" first: ",$F_first{$key},
! 716: " last: ",$F_last{$key},"\n") if $verbose > 1;
! 717: }
! 718: }
! 719: ;# now reclaim memory used for files no longer referenced ...
! 720: local(%Names);
! 721: grep($Names{$_} = 1,@newfiles);
! 722: foreach (keys %F_key)
! 723: {
! 724: next if defined($Names{$_});
! 725: delete $F_key{$_};
! 726: $verbose > 2 && print "no longer referenced: \"$_\"\n";
! 727: }
! 728: %Names = ();
! 729:
! 730: grep($Names{$_} = 1,values(%F_key));
! 731: foreach (keys %F_name)
! 732: {
! 733: next if defined($Names{$_});
! 734: delete $F_name{$_};
! 735: $verbose > 2 && print "unref name($_)= $F_name{$_}\n";
! 736: }
! 737: foreach (keys %F_size)
! 738: {
! 739: next if defined($Names{$_});
! 740: delete $F_size{$_};
! 741: $verbose > 2 && print "unref size($_)\n";
! 742: }
! 743: foreach (keys %F_mtime)
! 744: {
! 745: next if defined($Names{$_});
! 746: delete $F_mtime{$_};
! 747: $verbose > 2 && print "unref mtime($_)\n";
! 748: }
! 749: foreach (keys %F_first)
! 750: {
! 751: next if defined($Names{$_});
! 752: delete $F_first{$_};
! 753: $verbose > 2 && print "unref first($_)\n";
! 754: }
! 755: foreach (keys %F_last)
! 756: {
! 757: next if defined($Names{$_});
! 758: delete $F_last{$_};
! 759: $verbose > 2 && print "unref last($_)\n";
! 760: }
! 761: ;# create list sorted by time
! 762: @F_files = sort {$F_first{$a} <=> $F_first{$b}; } keys(%F_name);
! 763: if ($verbose > 1)
! 764: {
! 765: print "Resulting file list:\n";
! 766: foreach (@F_files)
! 767: {
! 768: print "\t$_\t$F_name{$_}\n";
! 769: }
! 770: }
! 771: }
! 772:
! 773: printf("processing %s; output \"$out\" (%d input files)\n",
! 774: ((defined($StartTime) && defined($EndTime))
! 775: ? "time range"
! 776: : (defined($StartTime) ? "$cnt samples from StartTime" :
! 777: (defined($EndTime) ? "$cnt samples to EndTime" :
! 778: "last $cnt samples"))),
! 779: scalar(@F_files))
! 780: if $verbose > 1;
! 781:
! 782: ;# open output file - will be input for plotcmd
! 783: open(OUT,">$out") ||
! 784: do {
! 785: warn("$0: cannot create \"$out\": $!\n");
! 786: };
! 787:
! 788: @f = @F_files;
! 789: if (defined($StartTime))
! 790: {
! 791: while (@f && ($F_last{$f[$[]} < $StartTime))
! 792: {
! 793: print("shifting ", $F_name{$f[$[]},
! 794: " last: ", $F_last{$f[$[]},
! 795: " < StartTime: $StartTime\n")
! 796: if $verbose > 3;
! 797: shift(@f);
! 798: }
! 799:
! 800:
! 801: }
! 802: if (defined($EndTime))
! 803: {
! 804: while (@f && ($F_first{$f[$#f]} > $EndTime))
! 805: {
! 806: print("popping ", $F_name{$f[$#f]},
! 807: " first: ", $F_first{$f[$#f]},
! 808: " > EndTime: $EndTime\n")
! 809: if $verbose > 3;
! 810: pop(@f);
! 811: }
! 812: }
! 813:
! 814: if (@f)
! 815: {
! 816: if (defined($StartTime))
! 817: {
! 818: print "guess start according to StartTime ($StartTime)\n"
! 819: if $verbose > 3;
! 820:
! 821: if ($fpos[$[] eq 'start')
! 822: {
! 823: if (grep($_ eq $fpos[$[+1],@f))
! 824: {
! 825: shift(@f) while @f && $f[$[] ne $fpos[$[+1];
! 826: }
! 827: else
! 828: {
! 829: @fpos = ('start', $f[$[], undef);
! 830: }
! 831: }
! 832: else
! 833: {
! 834: @fpos = ('start' , $f[$[], undef);
! 835: }
! 836:
! 837: if (!defined($fpos[$[+2]))
! 838: {
! 839: if ($StartTime <= $F_first{$f[$[]})
! 840: {
! 841: $fpos[$[+2] = 0;
! 842: }
! 843: else
! 844: {
! 845: $fpos[$[+2] =
! 846: int($F_size{$f[$[]} *
! 847: (($StartTime - $F_first{$f[$[]})/
! 848: ($F_last{$f[$[]} - $F_first{$f[$[]})));
! 849: $fpos[$[+2] = ($fpos[$[+2] <= 2 * $RecordSize)
! 850: ? 0 : $fpos[$[+2] - 2 * $RecordSize;
! 851: ;# anyway as the data may contain "time holes"
! 852: ;# our heuristics may baldly fail
! 853: ;# so just start at 0
! 854: $fpos[$[+2] = 0;
! 855: }
! 856: }
! 857: }
! 858: elsif (defined($EndTime))
! 859: {
! 860: print "guess starting point according to EndTime ($EndTime)\n"
! 861: if $verbose > 3;
! 862:
! 863: if ($fpos[$[] eq 'end')
! 864: {
! 865: if (grep($_ eq $fpos[$[+1],@f))
! 866: {
! 867: shift(@f) while @f && $f[$[] ne $fpos[$[+1];
! 868: }
! 869: else
! 870: {
! 871: @fpos = ('end', $f[$[], undef);
! 872: }
! 873: }
! 874: else
! 875: {
! 876: @fpos = ('end', $f[$[], undef);
! 877: }
! 878:
! 879: if (!defined($fpos[$[+2]))
! 880: {
! 881: local(@x) = reverse(@f);
! 882: local($s,$c) = (0,$cnt);
! 883: if ($EndTime < $F_last{$x[$[]})
! 884: {
! 885: ;# last file will only be used partially
! 886: $s = int($F_size{$x[$[]} *
! 887: (($EndTime - $F_first{$x[$[]}) /
! 888: ($F_last{$x[$[]} - $F_first{$x[$[]})));
! 889: $s = int($s/$RecordSize);
! 890: $c -= $s - 1;
! 891: if ($c <= 0)
! 892: {
! 893: ;# start is in the same file
! 894: $fpos[$[+1] = $x[$[];
! 895: $fpos[$[+2] = ($c >=-2) ? 0 : (-$c - 2) * $RecordSize;
! 896: shift(@f) while @f && ($f[$[] ne $x[$[]);
! 897: }
! 898: else
! 899: {
! 900: shift(@x);
! 901: }
! 902: }
! 903:
! 904: if (!defined($fpos[$[+2]))
! 905: {
! 906: local($_);
! 907: while($_ = shift(@x))
! 908: {
! 909: $s = int($F_size{$_}/$RecordSize);
! 910: $c -= $s - 1;
! 911: if ($c <= 0)
! 912: {
! 913: $fpos[$[+1] = $_;
! 914: $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize;
! 915: shift(@f) while @f && ($f[$[] ne $_);
! 916: last;
! 917: }
! 918: }
! 919: }
! 920: }
! 921: }
! 922: else
! 923: {
! 924: print "guessing starting point according to count ($cnt)\n"
! 925: if $verbose > 3;
! 926: ;# guess offset to get last available $cnt samples
! 927: if ($fpos[$[] eq 'cnt')
! 928: {
! 929: if (grep($_ eq $fpos[$[+1],@f))
! 930: {
! 931: print "old positioning applies\n" if $verbose > 3;
! 932: shift(@f) while @f && $f[$[] ne $fpos[$[+1];
! 933: }
! 934: else
! 935: {
! 936: @fpos = ('cnt', $f[$[], undef);
! 937: }
! 938: }
! 939: else
! 940: {
! 941: @fpos = ('cnt', $f[$[], undef);
! 942: }
! 943:
! 944: if (!defined($fpos[$[+2]))
! 945: {
! 946: local(@x) = reverse(@f);
! 947: local($s,$c) = (0,$cnt);
! 948:
! 949: local($_);
! 950: while($_ = shift(@x))
! 951: {
! 952: print "examing \"$_\" $c samples still needed\n"
! 953: if $verbose > 4;
! 954: $s = int($F_size{$_}/$RecordSize);
! 955: $c -= $s - 1;
! 956: if ($c <= 0)
! 957: {
! 958: $fpos[$[+1] = $_;
! 959: $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize;
! 960: shift(@f) while @f && ($f[$[] ne $_);
! 961: last;
! 962: }
! 963: }
! 964: if (!defined($fpos[$[+2]))
! 965: {
! 966: print "no starting point yet - using start of data\n"
! 967: if $verbose > 2;
! 968: $fpos[$[+2] = 0;
! 969: }
! 970: }
! 971: }
! 972: }
! 973: print "Ooops, no suitable input file ??\n"
! 974: if $verbose > 1 && @f <= 0;
! 975:
! 976: printf("Starting at (%s) \"%s\" offset %ld using %d files\n",
! 977: $fpos[$[+1],
! 978: $F_name{$fpos[$[+1]},
! 979: $fpos[$[+2],
! 980: scalar(@f))
! 981: if $verbose > 2;
! 982:
! 983: $lm = 1;
! 984: $l = 0;
! 985: foreach $key (@f)
! 986: {
! 987: $file = $F_name{$key};
! 988: print "processing file \"$file\"\n" if $verbose > 2;
! 989:
! 990: open(IN,"<$file") ||
! 991: (warn("$0: cannot read \"$file\": $!\n"), next);
! 992:
! 993: ;# try to seek to a position nearer to the start of the interesting lines
! 994: ;# should always affect only first item in @f
! 995: ($key eq $fpos[$[+1]) &&
! 996: (($verbose > 1) &&
! 997: print("Seeking to offset $fpos[$[+2]\n"),
! 998: seek(IN,$fpos[$[+2],0) ||
! 999: warn("$0: seek(\"$F_name{$key}\" failed: $|\n"));
! 1000:
! 1001: while(<IN>)
! 1002: {
! 1003: $l++;
! 1004: ($verbose > 3) &&
! 1005: (($l % $lm) == 0 && print("\t$l lines read\n") &&
! 1006: (($l == 2) && ($lm = 10) ||
! 1007: ($l == 100) && ($lm = 100) ||
! 1008: ($l == 500) && ($lm = 500) ||
! 1009: ($l == 1000) && ($lm = 1000) ||
! 1010: ($l == 5000) && ($lm = 5000) ||
! 1011: ($l == 10000) && ($lm = 10000)));
! 1012:
! 1013: @F = split;
! 1014:
! 1015: next if @F < 6; # no valid input line is this short
! 1016: next if $F[$[] eq "";
! 1017: next if ($F[$[] !~ /^\d+$/);
! 1018: ($F[$[] !~ /^\d+$/) && # A 'never should have happend' error
! 1019: die("$0: unexpected input line: >$_<\n");
! 1020:
! 1021: ;# modified Julian to UNIX epoch
! 1022: $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60;
! 1023: $t += $F[$[+1]; # add seconds + fraction
! 1024:
! 1025: ;# multiply offset by 1000 to get ms - try to avoid float op
! 1026: (($F[$[+2] =~ s/(\d*)\.(\d{3})(\d*)/$1$2.$3/) &&
! 1027: $F[$[+2] =~ s/0+([\d\.])/($1 eq '.') ? '0.' : $1/e) # strip leading zeros
! 1028: || ($F[$[+2] *= 1000);
! 1029:
! 1030:
! 1031: ;# skip samples out of specified time range
! 1032: next if (defined($StartTime) && $StartTime > $t);
! 1033: next if (defined($EndTime) && $EndTime < $t);
! 1034:
! 1035: next if defined($lastT) && $t < $lastT; # backward in time ??
! 1036:
! 1037: push(@offs,$F[$[+2]);
! 1038: push(@freq,$F[$[+3] * (2**20/10**6));
! 1039: push(@cmpl,$F[$[+5]);
! 1040:
! 1041: push(@break, (defined($lastT) && ($t - $lastT > $deltaT)));
! 1042: $lastT = $t;
! 1043: push(@time,$t);
! 1044: push(@loffset, tell(IN) - length($_));
! 1045: push(@filekey, $key);
! 1046:
! 1047: shift(@break),shift(@time),shift(@offs),
! 1048: shift(@freq), shift(@cmpl),shift(@loffset),
! 1049: shift(@filekey)
! 1050: if @time > $cnt &&
! 1051: ! (defined($StartTime) && defined($EndTime));
! 1052:
! 1053: last if @time >= $cnt && defined($StartTime) && !defined($EndTime);
! 1054: }
! 1055: close(IN);
! 1056: last if @time >= $cnt && defined($StartTime) && !defined($EndTime);
! 1057: }
! 1058: print "input scanned ($l lines/",scalar(@time)," samples)\n"
! 1059: if $verbose > 1;
! 1060:
! 1061: if (@time)
! 1062: {
! 1063: local($_,@F);
! 1064:
! 1065: local($timebase) unless defined($timebase);
! 1066: local($freqbase) unless defined($freqbase);
! 1067: local($cmplscale) unless defined($cmplscale);
! 1068:
! 1069: undef $mintime;
! 1070: undef $maxtime;
! 1071: undef $minoffs;
! 1072: undef $maxoffs;
! 1073: undef $minfreq;
! 1074: undef $maxfreq;
! 1075: undef $mincmpl;
! 1076: undef $maxcmpl;
! 1077: undef $miny;
! 1078: undef $maxy ;
! 1079:
! 1080: print "computing ranges\n" if $verbose > 2;
! 1081:
! 1082: $LastCnt = @time;
! 1083:
! 1084: ;# @time is in ascending order (;-)
! 1085: $mintime = $time[$[];
! 1086: $maxtime = $time[$#time];
! 1087: unless (defined($timebase))
! 1088: {
! 1089: local($time,@X) = (time);
! 1090: @X = localtime($time);
! 1091:
! 1092: ;# compute today 00:00:00
! 1093: $timebase = $time - ((($X[$[+2]*60)+$X[$[+1])*60+$X[$[]);
! 1094:
! 1095: }
! 1096: $LastTimeBase = $timebase;
! 1097:
! 1098: if ($showoffs)
! 1099: {
! 1100: local($i,$m,$f);
! 1101:
! 1102: $minoffs = &min(@offs);
! 1103: $maxoffs = &max(@offs);
! 1104:
! 1105: ;# I know, it is not perl style using indices to access arrays,
! 1106: ;# but I have to proccess two arrays in sync, non-destructively
! 1107: ;# (otherwise a (shift(@a1),shift(a2)) would do),
! 1108: ;# I dont like to make copies of these arrays as they may be huge
! 1109: $i = $[;
! 1110: $lo->sample(($time[$i]-$timebase)/3600,$offs[$i]),$i++
! 1111: while $i <= $#time;
! 1112:
! 1113: ($minoffs == $maxoffs) && ($minoffs -= 0.1,$maxoffs += 0.1);
! 1114:
! 1115: $i = $lo->sigma();
! 1116: $m = $lo->mean();
! 1117:
! 1118: print "mean offset: $m sigma: $i\n" if $verbose > 2;
! 1119:
! 1120: if (($maxoffs - $minoffs) > $MinClip)
! 1121: {
! 1122: $f = (&abs($minoffs) < &abs($maxoffs)) ? $FuzzLow : $FuzzBig;
! 1123: $miny = (($m - $minoffs) <= ($f * $i))
! 1124: ? $minoffs : ($m - $f * $i);
! 1125: $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow;
! 1126: $maxy = (($maxoffs - $m) <= ($f * $i))
! 1127: ? $maxoffs : ($m + $f * $i);
! 1128: }
! 1129: else
! 1130: {
! 1131: $miny = $minoffs;
! 1132: $maxy = $maxoffs;
! 1133: }
! 1134: ($maxy-$miny) == 0 &&
! 1135: (($maxy,$miny)
! 1136: = (($maxoffs - $minoffs) > 0)
! 1137: ? ($maxoffs,$minoffs) : ($MinClip,-$MinClip));
! 1138:
! 1139: $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy;
! 1140: $miny = $MinY if defined($MinY) && $MinY > $miny;
! 1141:
! 1142: print "offset min clipped from $minoffs to $miny\n"
! 1143: if $verbose > 2 && $minoffs != $miny;
! 1144: print "offset max clipped from $maxoffs to $maxy\n"
! 1145: if $verbose > 2 && $maxoffs != $maxy;
! 1146: }
! 1147:
! 1148: if ($showfreq)
! 1149: {
! 1150: local($i,$m);
! 1151:
! 1152: $minfreq = &min(@freq);
! 1153: $maxfreq = &max(@freq);
! 1154:
! 1155: $i = $[;
! 1156: $lf->sample(($time[$i]-$timebase)/3600,$freq[$i]-$minfreq),
! 1157: $i++
! 1158: while $i <= $#time;
! 1159:
! 1160: $i = $lf->sigma();
! 1161: $m = $lf->mean() + $minfreq;
! 1162:
! 1163: print "mean frequency: $m sigma: $i\n" if $verbose > 2;
! 1164:
! 1165: if (defined($maxy))
! 1166: {
! 1167: local($s) =
! 1168: ($maxfreq - $minfreq)
! 1169: ? ($maxy - $miny) / ($maxfreq - $minfreq) : 1;
! 1170:
! 1171: if (defined($freqbase))
! 1172: {
! 1173: $FreqScale = 1;
! 1174: $FreqScaleInv = "";
! 1175: }
! 1176: else
! 1177: {
! 1178: $FreqScale = 1;
! 1179: $FreqScale = 10 ** int(log($s)/log(10) - 0.9999);
! 1180: $FreqScaleInv =
! 1181: ("$FreqScale" =~ /^10(0*)$/) ? "0.${1}1" :
! 1182: ($FreqScale == 1 ? "" : (1/$FreqScale));
! 1183:
! 1184: $freqbase = ($maxfreq + $minfreq)/ 2 * $FreqScale; #$m * $FreqScale;
! 1185: $freqbase -= ($maxy + $miny) / 2; #$lf->mean();
! 1186:
! 1187: ;# round resulting freqbase
! 1188: ;# to precision of min max difference
! 1189: $s = -12;
! 1190: $s = int(log(($maxfreq-$minfreq)*$FreqScale)/log(10))-1
! 1191: unless ($maxfreq-$minfreq) < 1e-12;
! 1192: $s = 10 ** $s;
! 1193: $freqbase = int($freqbase / $s) * $s;
! 1194: }
! 1195: }
! 1196: else
! 1197: {
! 1198: $FreqScale = 1;
! 1199: $FreqScaleInv = "";
! 1200: $freqbase = $m unless defined($freqbase);
! 1201: if (($maxfreq - $minfreq) > $MinClip)
! 1202: {
! 1203: $f = (&abs($minfreq) < &abs($maxfreq))
! 1204: ? $FuzzLow : $FuzzBig;
! 1205: $miny = (($freqbase - $minfreq) <= ($f * $i))
! 1206: ? ($minfreq-$freqbase) : (- $f * $i);
! 1207: $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow;
! 1208: $maxy = (($maxfreq - $freqbase) <= ($f * $i))
! 1209: ? ($maxfreq-$freqbase) : ($f * $i);
! 1210: }
! 1211: else
! 1212: {
! 1213: $miny = $minfreq - $freqbase;
! 1214: $maxy = $maxfreq - $freqbase;
! 1215: }
! 1216: ($maxy - $miny) == 0 &&
! 1217: (($maxy,$miny) =
! 1218: (($maxfreq - $minfreq) > 0)
! 1219: ? ($maxfreq-$freqbase,$minfreq-$freqbase) : (0.5,-0.5));
! 1220:
! 1221: $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy;
! 1222: $miny = $MinY if defined($MinY) && $MinY > $miny;
! 1223:
! 1224: print("frequency min clipped from ",$minfreq-$freqbase,
! 1225: " to $miny\n")
! 1226: if $verbose > 2 && $miny != ($minfreq - $freqbase);
! 1227: print("frequency max clipped from ",$maxfreq-$freqbase,
! 1228: " to $maxy\n")
! 1229: if $verbose > 2 && $maxy != ($maxfreq - $freqbase);
! 1230: }
! 1231: $LastFreqBaseString =
! 1232: sprintf("%g",$freqbase >= 0 ? $freqbase : -$freqbase);
! 1233: $LastFreqBase = $freqbase;
! 1234: print "LastFreqBaseString now \"$LastFreqBaseString\"\n"
! 1235: if $verbose > 5;
! 1236: }
! 1237: else
! 1238: {
! 1239: $FreqScale = 1;
! 1240: $FreqScaleInv = "";
! 1241: $LastFreqBase = 0;
! 1242: $LastFreqBaseString = "";
! 1243: }
! 1244:
! 1245: if ($showcmpl)
! 1246: {
! 1247: $mincmpl = &min(@cmpl);
! 1248: $maxcmpl = &max(@cmpl);
! 1249:
! 1250: if (!defined($cmplscale))
! 1251: {
! 1252: if (defined($maxy))
! 1253: {
! 1254: local($cmp)
! 1255: = (&abs($miny) > &abs($maxy)) ? &abs($miny) : $maxy;
! 1256: $cmplscale = $cmp == $maxy ? 1 : -1;
! 1257:
! 1258: foreach (0.01, 0.02, 0.05,
! 1259: 0.1, 0.2, 0.25, 0.4, 0.5,
! 1260: 1, 2, 4, 5,
! 1261: 10, 20, 25, 50,
! 1262: 100, 200, 250, 500, 1000)
! 1263: {
! 1264: $cmplscale *= $_, last if $maxcmpl/$_ <= $cmp;
! 1265: }
! 1266: }
! 1267: else
! 1268: {
! 1269: $cmplscale = 1;
! 1270: $miny = $mincmpl ? 0 : -$MinClip;
! 1271: $maxy = $maxcmpl+$MinClip;
! 1272: }
! 1273: }
! 1274: $LastCmplScale = $cmplscale;
! 1275: }
! 1276: else
! 1277: {
! 1278: $LastCmplScale = 1;
! 1279: }
! 1280:
! 1281: print "creating plot command input file\n" if $verbose > 2;
! 1282:
! 1283:
! 1284: print OUT ("# preprocessed NTP statistics file for $STATHOST\n");
! 1285: print OUT ("# timebase is: ",&ctime($LastTimeBase))
! 1286: if defined($LastTimeBase);
! 1287: print OUT ("# frequency is offset by ",
! 1288: ($LastFreqBase >= 0 ? "+" : "-"),
! 1289: "$LastFreqBaseString [${FreqScaleInv}ppm]\n");
! 1290: print OUT ("# compliance is scaled by $LastCmplScale\n");
! 1291: print OUT ("# time [h]\toffset [ms]\tfrequency [${FreqScaleInv}ppm]\tcompliance\n");
! 1292:
! 1293: printf OUT ("%s%lf\t%lf\t%lf\t%lf\n",
! 1294: (shift(@break) ? "\n" : ""),
! 1295: (shift(@time) - $LastTimeBase)/3600,
! 1296: shift(@offs),
! 1297: shift(@freq) * $FreqScale - $LastFreqBase,
! 1298: shift(@cmpl) / $LastCmplScale)
! 1299: while(@time);
! 1300: }
! 1301: else
! 1302: {
! 1303: ;# prevent plotcmd from processing empty file
! 1304: print "Creating plot command dummy...\n" if $verbose > 2;
! 1305: print OUT "# dummy samples\n0 1 2 3\n1 1 2 3\n";
! 1306: $lo->sample(0,1);
! 1307: $lo->sample(1,1);
! 1308: $lf->sample(0,2);
! 1309: $lf->sample(1,2);
! 1310: @time = (0, 1); $maxtime = 1; $mintime = 0;
! 1311: @offs = (1, 1); $maxoffs = 1; $minoffs = 1;
! 1312: @freq = (2, 2); $maxfreq = 2; $minfreq = 2;
! 1313: @cmpl = (3, 3); $maxcmpl = 3; $mincmpl = 3;
! 1314: $LastCnt = 2;
! 1315: $LastFreqBase = 0;
! 1316: $LastCmplScale = 1;
! 1317: $LastTimeBase = 0;
! 1318: $miny = -$MinClip;
! 1319: $maxy = 3 + $MinClip;
! 1320: }
! 1321: close(OUT);
! 1322:
! 1323: print "plot command input file created\n"
! 1324: if $verbose > 2;
! 1325:
! 1326:
! 1327: if (($fpos[$[] eq 'cnt' && scalar(@loffset) >= $cnt) ||
! 1328: ($fpos[$[] eq 'start' && $mintime <= $StartTime) ||
! 1329: ($fpos[$[] eq 'end'))
! 1330: {
! 1331: return ($fpos[$[],$filekey[$[],$loffset[$[]);
! 1332: }
! 1333: else # found to few lines - next time start search earlier in file
! 1334: {
! 1335: if ($fpos[$[] eq 'start')
! 1336: {
! 1337: ;# the timestamps we got for F_first and F_last guaranteed
! 1338: ;# that no file is left out
! 1339: ;# the only thing that could happen is:
! 1340: ;# we guessed the starting point wrong
! 1341: ;# compute a new guess from the first record found
! 1342: ;# if this equals our last guess use data of first record
! 1343: ;# otherwise try new guess
! 1344:
! 1345: if ($fpos[$[+1] eq $filekey[$[] && $loffset[$[] > $fpos[$[+2])
! 1346: {
! 1347: local($noff);
! 1348: $noff = $loffset[$[] - ($cnt - @loffset + 1) * $RecordSize;
! 1349: $noff = 0 if $noff < 0;
! 1350:
! 1351: return (@fpos[$[,$[+1], ($noff == $fpos[$[+2]) ? $loffset[$[] : $noff);
! 1352: }
! 1353: return ($fpos[$[],$filekey[$[],$loffset[$[]);
! 1354: }
! 1355: elsif ($fpos[$[] eq 'end' || $fpos[$[] eq 'cnt')
! 1356: {
! 1357: ;# try to start earlier in file
! 1358: ;# if we already started at the beginning
! 1359: ;# try to use previous file
! 1360: ;# this assumes distance to better starting point is at most one file
! 1361: ;# the primary guess at top of genfile() should usually allow this
! 1362: ;# assumption
! 1363: ;# if the offset of the first sample used is within
! 1364: ;# a different file than we guessed it must have occurred later
! 1365: ;# in the sequence of files
! 1366: ;# this only can happen if our starting file did not contain
! 1367: ;# a valid sample from the starting point we guessed
! 1368: ;# however this does not invalidate our assumption, no check needed
! 1369: local($noff,$key);
! 1370: if ($fpos[$[+2] > 0)
! 1371: {
! 1372: $noff = $fpos[$[+2] - $RecordSize * ($cnt - @loffset + 1);
! 1373: $noff = 0 if $noff < 0;
! 1374: return (@fpos[$[,$[+1],$noff);
! 1375: }
! 1376: else
! 1377: {
! 1378: if ($fpos[$[+1] eq $F_files[$[])
! 1379: {
! 1380: ;# first file - and not enough samples
! 1381: ;# use data of first sample
! 1382: return ($fpos[$[], $filekey[$[], $loffset[$[]);
! 1383: }
! 1384: else
! 1385: {
! 1386: ;# search key of previous file
! 1387: $key = $F_files[$[];
! 1388: @F = reverse(@F_files);
! 1389: while ($_ = shift(@F))
! 1390: {
! 1391: if ($_ eq $fpos[$[+1])
! 1392: {
! 1393: $key = shift(@F) if @F;
! 1394: last;
! 1395: }
! 1396: }
! 1397: $noff = int($F_size{$key} / $RecordSize);
! 1398: $noff -= $cnt - @loffset;
! 1399: $noff = 0 if $noff < 0;
! 1400: $noff *= $RecordSize;
! 1401: return ($fpos[$[], $key, $noff);
! 1402: }
! 1403: }
! 1404: }
! 1405: else
! 1406: {
! 1407: return ();
! 1408: }
! 1409:
! 1410: return 0 if @loffset <= 1 || ($loffset[$#loffset] - $loffset[$[]) <= 1;
! 1411:
! 1412: ;# EOF - 1.1 * avg(line) * $cnt
! 1413: local($val) = $loffset[$#loffset]
! 1414: - $cnt * 11 * (($loffset[$#loffset] - $loffset[$[]) / @loffset) / 10;
! 1415: return ($val < 0) ? 0 : $val;
! 1416: }
! 1417: }
! 1418:
! 1419: $Ltime = -1 if ! defined($Ltime);
! 1420: $LastFreqBase = 0;
! 1421: $LastFreqBaseString = "??";
! 1422:
! 1423: ;# initial setup of plot
! 1424: print "initialize plotting\n" if $verbose;
! 1425: if (defined($PrintIt))
! 1426: {
! 1427: if ($PrintIt =~ m,/,)
! 1428: {
! 1429: print "Saving plot to file $PrintIt\n";
! 1430: print PLOT "set output '$PrintIt'\n";
! 1431: }
! 1432: else
! 1433: {
! 1434: print "Printing plot on printer $PrintIt\n";
! 1435: print PLOT "set output '| lpr -P$PrintIt -h'\n";
! 1436: }
! 1437: print PLOT "set terminal postscript landscape color solid 'Helvetica' 10\n";
! 1438: }
! 1439: print PLOT "set grid\n";
! 1440: print PLOT "set tics out\n";
! 1441: print PLOT "set format y '%g '\n";
! 1442: printf PLOT "set time 47\n" unless defined($PrintIt);
! 1443:
! 1444: @filepos =();
! 1445: while(1)
! 1446: {
! 1447: print &ctime(time) if $verbose;
! 1448:
! 1449: ;# update diplay characteristics
! 1450: &read_config;# unless defined($PrintIt);
! 1451:
! 1452: unlink($tmpfile);
! 1453: my $lo = lr->new();
! 1454: my $lf = lr->new();
! 1455:
! 1456: @filepos = &genfile($samples,$srcprefix,$tmpfile,$lo,$lf,@filepos);
! 1457:
! 1458: ;# make plotcmd display samples
! 1459: make_doplot($lo, $lf);
! 1460: print "Displaying plot...\n" if $verbose > 1;
! 1461: print "command for plot sub process:\n$doplot----\n" if $verbose > 3;
! 1462: print PLOT $doplot;
! 1463: }
! 1464: continue
! 1465: {
! 1466: if (defined($PrintIt))
! 1467: {
! 1468: delete $SIG{'CHLD'};
! 1469: print PLOT "quit\n";
! 1470: close(PLOT);
! 1471: if ($PrintIt =~ m,/,)
! 1472: {
! 1473: print "Plot saved to file $PrintIt\n";
! 1474: }
! 1475: else
! 1476: {
! 1477: print "Plot spooled to printer $PrintIt\n";
! 1478: }
! 1479: unlink($tmpfile);
! 1480: exit(0);
! 1481: }
! 1482: ;# wait $delay seconds
! 1483: print "waiting $delay seconds ..." if $verbose > 2;
! 1484: sleep($delay);
! 1485: print " continuing\n" if $verbose > 2;
! 1486: undef($LastFreqBaseString);
! 1487: }
! 1488:
! 1489:
! 1490: sub date_time_spec2seconds
! 1491: {
! 1492: local($_) = @_;
! 1493: ;# a date_time_spec consistes of:
! 1494: ;# YYYY-MM-DD_HH:MM:SS.ms
! 1495: ;# values can be omitted from the beginning and default than to
! 1496: ;# values of current date
! 1497: ;# values omitted from the end default to lowest possible values
! 1498:
! 1499: local($time) = time;
! 1500: local($sec,$min,$hour,$mday,$mon,$year)
! 1501: = localtime($time);
! 1502:
! 1503: local($last) = ();
! 1504:
! 1505: s/^\D*(.*\d)\D*/$1/; # strip off garbage
! 1506:
! 1507: PARSE:
! 1508: {
! 1509: if (s/^(\d{4})(-|$)//)
! 1510: {
! 1511: if ($1 < 1970)
! 1512: {
! 1513: warn("$0: can not handle years before 1970 - year $1 ignored\n");
! 1514: return undef;
! 1515: }
! 1516: elsif ( $1 >= 2070)
! 1517: {
! 1518: warn("$0: can not handle years past 2070 - year $1 ignored\n");
! 1519: return undef;
! 1520: }
! 1521: else
! 1522: {
! 1523: $year = $1 % 100; # 0<= $year < 100
! 1524: ;# - interpreted 70 .. 99,00 .. 69
! 1525: }
! 1526: $last = $[ + 5;
! 1527: last PARSE if $_ eq '';
! 1528: warn("$0: bad date_time_spec: \"$_\" found after YEAR\n"),
! 1529: return(undef)
! 1530: if $2 eq '';
! 1531: }
! 1532:
! 1533: if (s/^(\d{1,2})(-|$)//)
! 1534: {
! 1535: warn("$0: implausible month $1\n"),return(undef)
! 1536: if $1 < 1 || $1 > 12;
! 1537: $mon = $1 - 1;
! 1538: $last = $[ + 4;
! 1539: last PARSE if $_ eq '';
! 1540: warn("$0: bad date_time_spec: \"$_\" found after MONTH\n"),
! 1541: return(undef)
! 1542: if $2 eq '';
! 1543: }
! 1544: else
! 1545: {
! 1546: warn("$0: bad date_time_spec \"$_\"\n"),return(undef)
! 1547: if defined($last);
! 1548:
! 1549: }
! 1550:
! 1551: if (s/^(\d{1,2})([_ ]|$)//)
! 1552: {
! 1553: warn("$0: implausible month day $1 for month ".($mon+1)." (".
! 1554: $MaxNumDaysPerMonth[$mon].")$mon\n"),
! 1555: return(undef)
! 1556: if $1 < 1 || $1 > $MaxNumDaysPerMonth[$mon];
! 1557: $mday = $1;
! 1558: $last = $[ + 3;
! 1559: last PARSE if $_ eq '';
! 1560: warn("$0: bad date_time_spec \"$_\" found after MDAY\n"),
! 1561: return(undef)
! 1562: if $2 eq '';
! 1563: }
! 1564: else
! 1565: {
! 1566: warn("$0: bad date_time_spec \"$_\"\n"), return undef
! 1567: if defined($last);
! 1568: }
! 1569:
! 1570: ;# now we face a problem:
! 1571: ;# if ! defined($last) a prefix of "07:"
! 1572: ;# can be either 07:MM or 07:ss
! 1573: ;# to get the second interpretation make the user add
! 1574: ;# a msec fraction part and check for this special case
! 1575: if (! defined($last) && s/^(\d{1,2}):(\d{1,2}\.\d+)//)
! 1576: {
! 1577: warn("$0: implausible minute $1\n"), return undef
! 1578: if $1 < 0 || $1 >= 60;
! 1579: warn("$0: implausible second $1\n"), return undef
! 1580: if $2 < 0 || $2 >= 60;
! 1581: $min = $1;
! 1582: $sec = $2;
! 1583: $last = $[ + 1;
! 1584: last PARSE if $_ eq '';
! 1585: warn("$0: bad date_time_spec \"$_\" after SECONDS\n");
! 1586: return undef;
! 1587: }
! 1588:
! 1589: if (s/^(\d{1,2})(:|$)//)
! 1590: {
! 1591: warn("$0: implausible hour $1\n"), return undef
! 1592: if $1 < 0 || $1 > 24;
! 1593: $hour = $1;
! 1594: $last = $[ + 2;
! 1595: last PARSE if $_ eq '';
! 1596: warn("$0: bad date_time_spec found \"$_\" after HOUR\n"),
! 1597: return undef
! 1598: if $2 eq '';
! 1599: }
! 1600: else
! 1601: {
! 1602: warn("$0: bad date_time_spec \"$_\"\n"), return undef
! 1603: if defined($last);
! 1604: }
! 1605:
! 1606: if (s/^(\d{1,2})(:|$)//)
! 1607: {
! 1608: warn("$0: implausible minute $1\n"), return undef
! 1609: if $1 < 0 || $1 >=60;
! 1610: $min = $1;
! 1611: $last = $[ + 1;
! 1612: last PARSE if $_ eq '';
! 1613: warn("$0: bad date_time_spec found \"$_\" after MINUTE\n"),
! 1614: return undef
! 1615: if $2 eq '';
! 1616: }
! 1617: else
! 1618: {
! 1619: warn("$0: bad date_time_spec \"$_\"\n"), return undef
! 1620: if defined($last);
! 1621: }
! 1622:
! 1623: if (s/^(\d{1,2}(\.\d+)?)//)
! 1624: {
! 1625: warn("$0: implausible second $1\n"), return undef
! 1626: if $1 < 0 || $1 >=60;
! 1627: $sec = $1;
! 1628: $last = $[;
! 1629: last PARSE if $_ eq '';
! 1630: warn("$0: bad date_time_spec found \"$_\" after SECOND\n");
! 1631: return undef;
! 1632: }
! 1633: }
! 1634:
! 1635: return $time unless defined($last);
! 1636:
! 1637: $sec = 0 if $last > $[;
! 1638: $min = 0 if $last > $[ + 1;
! 1639: $hour = 0 if $last > $[ + 2;
! 1640: $mday = 1 if $last > $[ + 3;
! 1641: $mon = 0 if $last > $[ + 4;
! 1642: local($rtime) = &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 0);
! 1643:
! 1644: ;# $rtime may be off if daylight savings time is in effect at given date
! 1645: return $rtime + ($sec - int($sec))
! 1646: if $hour == (localtime($rtime))[$[+2];
! 1647: return
! 1648: &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 1)
! 1649: + ($sec - int($sec));
! 1650: }
! 1651:
! 1652:
! 1653: sub min
! 1654: {
! 1655: local($m) = shift;
! 1656:
! 1657: grep((($m > $_) && ($m = $_),0),@_);
! 1658: $m;
! 1659: }
! 1660:
! 1661: sub max
! 1662: {
! 1663: local($m) = shift;
! 1664:
! 1665: grep((($m < $_) && ($m = $_),0),@_);
! 1666: $m;
! 1667: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>