154359Sroberto#!/usr/bin/perl -w 254359Sroberto;# --*-perl-*-- 354359Sroberto;# 4182007Sroberto;# /src/NTP/ntp4-dev/scripts/monitoring/ntploopwatch,v 4.7 2004/11/14 16:11:05 kardel RELEASE_20050508_A 554359Sroberto;# 654359Sroberto;# process loop filter statistics file and either 754359Sroberto;# - show statistics periodically using gnuplot 854359Sroberto;# - or print a single plot 954359Sroberto;# 1054359Sroberto;# Copyright (c) 1992-1998 1154359Sroberto;# Rainer Pruy, Friedrich-Alexander Universit�t Erlangen-N�rnberg 1254359Sroberto;# 1354359Sroberto;# 1454359Sroberto;############################################################# 1554359Sroberto$0 =~ s!^.*/([^/]+)$!$1!; 1654359Sroberto$F = ' ' x length($0); 1754359Sroberto$|=1; 1854359Sroberto 1954359Sroberto$ENV{'SHELL'} = '/bin/sh'; # use bourne shell 2054359Sroberto 2154359Srobertoundef($config); 2254359Srobertoundef($workdir); 2354359Srobertoundef($PrintIt); 2454359Srobertoundef($samples); 2554359Srobertoundef($StartTime); 2654359Srobertoundef($EndTime); 2754359Sroberto($a,$b) if 0; # keep -w happy 2854359Sroberto$usage = <<"E-O-P"; 2954359Srobertousage: 3054359Sroberto to watch statistics permanently: 3154359Sroberto $0 [-v[<level>]] [-c <config-file>] [-d <working-dir>] 3254359Sroberto $F [-h <hostname>] 3354359Sroberto 3454359Sroberto to get a single print out specify also 3554359Sroberto $F -P[<printer>] [-s<samples>] 3654359Sroberto $F [-S <start-time>] [-E <end-time>] 3754359Sroberto $F [-Y <MaxOffs>] [-y <MinOffs>] 3854359Sroberto 3954359SrobertoIf You like long option names, You can use: 4054359Sroberto -help 4154359Sroberto -c +config 4254359Sroberto -d +directory 4354359Sroberto -h +host 4454359Sroberto -v +verbose[=<level>] 4554359Sroberto -P +printer[=<printer>] 4654359Sroberto -s +samples[=<samples>] 4754359Sroberto -S +starttime 4854359Sroberto -E +endtime 4954359Sroberto -Y +maxy 5054359Sroberto -y +miny 5154359Sroberto 5254359SrobertoIf <printer> contains a '/' (slash character) output is directed to 5354359Srobertoa file of this name instead of delivered to a printer. 5454359SrobertoE-O-P 5554359Sroberto 5654359Sroberto;# add directory to look for lr.pl and timelocal.pl (in front of current list) 57182007Srobertounshift(@INC,"."); 5854359Sroberto 5954359Srobertorequire "lr.pl"; # linear regresion routines 6054359Sroberto 6154359Sroberto$MJD_1970 = 40587; # from ntp.h (V3) 6254359Sroberto$RecordSize = 48; # usually a line fits into 42 bytes 6354359Sroberto$MinClip = 1; # clip Y scales with greater range than this 6454359Sroberto 6554359Sroberto;# largest extension of Y scale from mean value, factor for standart deviation 6654359Sroberto$FuzzLow = 2.2; # for side closer to zero 6754359Sroberto$FuzzBig = 1.8; # for side farther from zero 6854359Sroberto 6954359Srobertorequire "ctime.pl"; 7054359Srobertorequire "timelocal.pl"; 7154359Sroberto;# early distributions of ctime.pl had a bug 7254359Sroberto$ENV{'TZ'} = 'MET' unless defined $ENV{'TZ'} || $[ > 4.010; 7354359Srobertoif (defined(@ctime'MoY)) 7454359Sroberto{ 7554359Sroberto *Month=*ctime'MoY; 7654359Sroberto *Day=*ctime'DoW; 7754359Sroberto} # ' re-sync emacs fontification 7854359Srobertoelse 7954359Sroberto{ 8054359Sroberto @Month = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); 8154359Sroberto @Day = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); 8254359Sroberto} 8354359Srobertoprint @ctime'DoW if 0; # ' re-sync emacs fontification 8454359Sroberto 8554359Sroberto;# max number of days per month 8654359Sroberto@MaxNumDaysPerMonth = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); 8754359Sroberto 8854359Sroberto;# config settable parameters 8954359Sroberto$delay = 60; 9054359Sroberto$srcprefix = "./var\@\$STATHOST/loopstats."; 9154359Sroberto$showoffs = 1; 9254359Sroberto$showfreq = 1; 9354359Sroberto$showcmpl = 0; 9454359Sroberto$showoreg = 0; 9554359Sroberto$showfreg = 0; 9654359Srobertoundef($timebase); 9754359Srobertoundef($freqbase); 9854359Srobertoundef($cmplscale); 9954359Srobertoundef($MaxY); 10054359Srobertoundef($MinY); 10154359Sroberto$deltaT = 512; # indicate sample data gaps greater than $deltaT seconds 10254359Sroberto$verbose = 1; 10354359Sroberto 10454359Srobertowhile($_ = shift(@ARGV)) 10554359Sroberto{ 10654359Sroberto (/^[+-]help$/) && die($usage); 10754359Sroberto 10854359Sroberto (/^-c$/ || /^\+config$/) && 10954359Sroberto (@ARGV || die($usage), $config = shift(@ARGV), next); 11054359Sroberto 11154359Sroberto (/^-d$/ || /^\+directory$/) && 11254359Sroberto (@ARGV || die($usage), $workdir = shift(@ARGV), next); 11354359Sroberto 11454359Sroberto (/^-h$/ || /^\+host$/) && 11554359Sroberto (@ARGV || die($usage), $STATHOST = shift, next); 11654359Sroberto 11754359Sroberto (/^-v(\d*)$/ || /^\+verbose=?(\d*)$/) && 11854359Sroberto ($verbose=($1 eq "") ? 1 : $1, next); 11954359Sroberto 12054359Sroberto (/^-P(\S*)$/ || /^\+[Pp]rinter=?(\S*)$/) && 12154359Sroberto ($PrintIt = $1, $verbose==1 && ($verbose = 0), next); 12254359Sroberto 12354359Sroberto (/^-s(\d*)$/ || /^\+samples=?(\d*)$/) && 12454359Sroberto (($samples = ($1 eq "") ? (shift || die($usage)): $1), next); 12554359Sroberto 12654359Sroberto (/^-S$/ || /^\+[Ss]tart[Tt]ime$/) && 12754359Sroberto (@ARGV || die($usage), $StartTime=&date_time_spec2seconds(shift),next); 12854359Sroberto 12954359Sroberto (/^-E$/ || /^\+[Ee]nd[Tt]ime$/) && 13054359Sroberto (@ARGV || die($usage), $EndTime = &date_time_spec2seconds(shift),next); 13154359Sroberto 13254359Sroberto (/^-Y$/ || /^\+[Mm]ax[Yy]$/) && 13354359Sroberto (@ARGV || die($usage), $MaxY = shift, next); 13454359Sroberto 13554359Sroberto (/^-y$/ || /^\+[Mm]in[Yy]$/) && 13654359Sroberto (@ARGV || die($usage), $MinY = shift, next); 13754359Sroberto 13854359Sroberto die("$0: unexpected argument \"$_\"\n$usage"); 13954359Sroberto} 14054359Sroberto 14154359Srobertoif (defined($workdir)) 14254359Sroberto{ 14354359Sroberto chdir($workdir) || 14454359Sroberto die("$0: failed to change working dir to \"$workdir\": $!\n"); 14554359Sroberto} 14654359Sroberto 14754359Sroberto$PrintIt = "ps" if defined($PrintIt) && $PrintIt eq ""; 14854359Sroberto 14954359Srobertoif (!defined($PrintIt)) 15054359Sroberto{ 15154359Sroberto defined($samples) && 15254359Sroberto print "WARNING: your samples value may be shadowed by config file settings\n"; 15354359Sroberto defined($StartTime) && 15454359Sroberto print "WARNING: your StartTime value may be shadowed by config file settings\n"; 15554359Sroberto defined($EndTime) && 15654359Sroberto print "WARNING: your EndTime value may be shadowed by config file settings\n"; 15754359Sroberto defined($MaxY) && 15854359Sroberto print "WARNING: your MaxY value may be shadowed by config file settings\n"; 15954359Sroberto defined($MinY) && 16054359Sroberto print "WARNING: your MinY value may be shadowed by config file settings\n"; 16154359Sroberto 16254359Sroberto ;# check operating environment 16354359Sroberto ;# 16454359Sroberto ;# gnuplot usually has X support 16554359Sroberto ;# I vaguely remember there was one with sunview support 16654359Sroberto ;# 16754359Sroberto ;# If Your plotcmd can display graphics using some other method 16854359Sroberto ;# (Tek window,..) fix the following test 16954359Sroberto ;# (or may be, just disable it) 17054359Sroberto ;# 17154359Sroberto !(defined($ENV{'DISPLAY'}) || defined($ENV{'WINDOW_PARENT'})) && 17254359Sroberto die("Need window system to monitor statistics\n"); 17354359Sroberto} 17454359Sroberto 17554359Sroberto;# configuration file 17654359Sroberto$config = "loopwatch.config" unless defined($config); 17754359Sroberto($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]*)$!$1! 17854359Sroberto unless defined($STATHOST); 17954359Sroberto($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/$1/; 18054359Sroberto 18154359Sroberto$srcprefix =~ s/\$STATHOST/$STATHOST/g; 18254359Sroberto 18354359Sroberto;# plot command 18454359Sroberto@plotcmd=("gnuplot", 18554359Sroberto '-title', "Ntp loop filter statistics $STATHOST", 18654359Sroberto '-name', "NtpLoopWatch_$STATTAG"); 18754359Sroberto$tmpfile = "/tmp/ntpstat.$$"; 18854359Sroberto 18954359Sroberto;# other variables 19054359Sroberto$doplot = ""; # assembled command for @plotcmd to display plot 19154359Srobertoundef($laststat); 19254359Sroberto 19354359Sroberto;# plot value ranges 19454359Srobertoundef($mintime); 19554359Srobertoundef($maxtime); 19654359Srobertoundef($minoffs); 19754359Srobertoundef($maxoffs); 19854359Srobertoundef($minfreq); 19954359Srobertoundef($maxfreq); 20054359Srobertoundef($mincmpl); 20154359Srobertoundef($maxcmpl); 20254359Srobertoundef($miny); 20354359Srobertoundef($maxy); 20454359Sroberto 20554359Sroberto;# stop operation if plot command dies 20654359Srobertosub sigchld 20754359Sroberto{ 20854359Sroberto local($pid) = wait; 20954359Sroberto unlink($tmpfile); 21054359Sroberto warn(sprintf("%s: %s died: exit status: %d signal %d\n", 21154359Sroberto $0, 21254359Sroberto (defined($Plotpid) && $Plotpid == $pid) 21354359Sroberto ? "plotcmd" : "unknown child $pid", 21454359Sroberto $?>>8,$? & 0xff)) if $?; 21554359Sroberto exit(1) if $? && defined($Plotpid) && $pid == $Plotpid; 21654359Sroberto} 21754359Sroberto&sigchld if 0; 21854359Sroberto$SIG{'CHLD'} = "sigchld"; 21954359Sroberto$SIG{'CLD'} = "sigchld"; 22054359Sroberto 22154359Srobertosub abort 22254359Sroberto{ 22354359Sroberto unlink($tmpfile); 22454359Sroberto defined($Plotpid) && kill('TERM',$Plotpid); 22554359Sroberto die("$0: received signal SIG$_[$[] - exiting\n"); 22654359Sroberto} 22754359Sroberto&abort if 0; # make -w happy - &abort IS used 22854359Sroberto$SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = $SIG{'PIPE'} = "abort"; 22954359Sroberto 23054359Sroberto;# 23154359Srobertosub abs 23254359Sroberto{ 23354359Sroberto ($_[$[] < 0) ? -($_[$[]) : $_[$[]; 23454359Sroberto} 23554359Sroberto 23654359Srobertosub boolval 23754359Sroberto{ 23854359Sroberto local($v) = ($_[$[]); 23954359Sroberto 24054359Sroberto return 1 if ($v eq 'yes') || ($v eq 'y'); 24154359Sroberto return 1 if ($v =~ /^[0-9]*$/) && ($v != 0); 24254359Sroberto return 0; 24354359Sroberto} 24454359Sroberto 24554359Sroberto;##################### 24654359Sroberto;# start of real work 24754359Sroberto 24854359Srobertoprint "starting plot command (" . join(" ",@plotcmd) . ")\n" if $verbose > 1; 24954359Sroberto 25054359Sroberto$Plotpid = open(PLOT,"|-"); 25154359Srobertoselect((select(PLOT),$|=1)[$[]); # make PLOT line bufferd 25254359Sroberto 25354359Srobertodefined($Plotpid) || 25454359Sroberto die("$0: failed to start plot command: $!\n"); 25554359Sroberto 25654359Srobertounless ($Plotpid) 25754359Sroberto{ 25854359Sroberto ;# child == plot command 25954359Sroberto close(STDOUT); 26054359Sroberto open(STDOUT,">&STDERR") || 26154359Sroberto die("$0: failed to redirect STDOUT of plot command: $!\n"); 26254359Sroberto 26354359Sroberto print STDOUT "plot command running as $$\n"; 26454359Sroberto 26554359Sroberto exec @plotcmd; 26654359Sroberto die("$0: failed to exec (@plotcmd): $!\n"); 26754359Sroberto exit(1); # in case ... 26854359Sroberto} 26954359Sroberto 27054359Srobertosub read_config 27154359Sroberto{ 27254359Sroberto local($at) = (stat($config))[$[+9]; 27354359Sroberto local($_,$c,$v); 27454359Sroberto 27554359Sroberto (undef($laststat),(print("stat $config failed: $!\n")),return) if ! defined($at); 27654359Sroberto return if (defined($laststat) && ($laststat == $at)); 27754359Sroberto $laststat = $at; 27854359Sroberto 27954359Sroberto print "reading configuration from \"$config\"\n" if $verbose; 28054359Sroberto 28154359Sroberto open(CF,"<$config") || 28254359Sroberto (warn("$0: failed to read \"$config\" - using old settings ($!)\n"), 28354359Sroberto return); 28454359Sroberto while(<CF>) 28554359Sroberto { 28654359Sroberto chop; 28754359Sroberto s/^([^\#]*[^\#\s]?)\s*\#.*$//; 28854359Sroberto next if /^\s*$/; 28954359Sroberto 29054359Sroberto s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/$1=$2/; 29154359Sroberto 29254359Sroberto ($c,$v) = split(/=/,$_,2); 29354359Sroberto print "processing \"$c=$v\"\n" if $verbose > 3; 29454359Sroberto ($c eq "delay") && ($delay = $v,1) && next; 29554359Sroberto ($c eq 'samples') && (!defined($PrintIt) || !defined($samples)) && 29654359Sroberto ($samples = $v,1) && next; 29754359Sroberto ($c eq 'srcprefix') && (($srcprefix=$v)=~s/\$STATHOST/$STATHOST/g,1) 29854359Sroberto && next; 29954359Sroberto ($c eq 'showoffs') && 30054359Sroberto ($showoffs = boolval($v),1) && next; 30154359Sroberto ($c eq 'showfreq') && 30254359Sroberto ($showfreq = boolval($v),1) && next; 30354359Sroberto ($c eq 'showcmpl') && 30454359Sroberto ($showcmpl = boolval($v),1) && next; 30554359Sroberto ($c eq 'showoreg') && 30654359Sroberto ($showoreg = boolval($v),1) && next; 30754359Sroberto ($c eq 'showfreg') && 30854359Sroberto ($showfreg = boolval($v),1) && next; 30954359Sroberto 31054359Sroberto ($c eq 'exit') && (unlink($tmpfile),die("$0: exit by config request\n")); 31154359Sroberto 31254359Sroberto ($c eq 'freqbase' || 31354359Sroberto $c eq 'cmplscale') && 31454359Sroberto do { 31554359Sroberto if (! defined($v) || $v eq "" || $v eq 'dynamic') 31654359Sroberto { 31754359Sroberto eval "undef(\$$c);"; 31854359Sroberto } 31954359Sroberto else 32054359Sroberto { 32154359Sroberto eval "\$$c = \$v;"; 32254359Sroberto } 32354359Sroberto next; 32454359Sroberto }; 32554359Sroberto ($c eq 'timebase') && 32654359Sroberto do { 32754359Sroberto if (! defined($v) || $v eq "" || $v eq "dynamic") 32854359Sroberto { 32954359Sroberto undef($timebase); 33054359Sroberto } 33154359Sroberto else 33254359Sroberto { 33354359Sroberto $timebase=&date_time_spec2seconds($v); 33454359Sroberto } 33554359Sroberto }; 33654359Sroberto ($c eq 'EndTime') && 33754359Sroberto do { 33854359Sroberto next if defined($EndTime) && defined($PrintIt); 33954359Sroberto if (! defined($v) || $v eq "" || $v eq "none") 34054359Sroberto { 34154359Sroberto undef($EndTime); 34254359Sroberto } 34354359Sroberto else 34454359Sroberto { 34554359Sroberto $EndTime=&date_time_spec2seconds($v); 34654359Sroberto } 34754359Sroberto }; 34854359Sroberto ($c eq 'StartTime') && 34954359Sroberto do { 35054359Sroberto next if defined($StartTime) && defined($PrintIt); 35154359Sroberto if (! defined($v) || $v eq "" || $v eq "none") 35254359Sroberto { 35354359Sroberto undef($StartTime); 35454359Sroberto } 35554359Sroberto else 35654359Sroberto { 35754359Sroberto $StartTime=&date_time_spec2seconds($v); 35854359Sroberto } 35954359Sroberto }; 36054359Sroberto 36154359Sroberto ($c eq 'MaxY') && 36254359Sroberto do { 36354359Sroberto next if defined($MaxY) && defined($PrintIt); 36454359Sroberto if (! defined($v) || $v eq "" || $v eq "none") 36554359Sroberto { 36654359Sroberto undef($MaxY); 36754359Sroberto } 36854359Sroberto else 36954359Sroberto { 37054359Sroberto $MaxY=$v; 37154359Sroberto } 37254359Sroberto }; 37354359Sroberto 37454359Sroberto ($c eq 'MinY') && 37554359Sroberto do { 37654359Sroberto next if defined($MinY) && defined($PrintIt); 37754359Sroberto if (! defined($v) || $v eq "" || $v eq "none") 37854359Sroberto { 37954359Sroberto undef($MinY); 38054359Sroberto } 38154359Sroberto else 38254359Sroberto { 38354359Sroberto $MinY=$v; 38454359Sroberto } 38554359Sroberto }; 38654359Sroberto 38754359Sroberto ($c eq 'deltaT') && 38854359Sroberto do { 38954359Sroberto if (!defined($v) || $v eq "") 39054359Sroberto { 39154359Sroberto undef($deltaT); 39254359Sroberto } 39354359Sroberto else 39454359Sroberto { 39554359Sroberto $deltaT = $v; 39654359Sroberto } 39754359Sroberto next; 39854359Sroberto }; 39954359Sroberto ($c eq 'verbose') && ! defined($PrintIt) && 40054359Sroberto do { 40154359Sroberto if (!defined($v) || $v == 0) 40254359Sroberto { 40354359Sroberto $verbose = 0; 40454359Sroberto } 40554359Sroberto else 40654359Sroberto { 40754359Sroberto $verbose = $v; 40854359Sroberto } 40954359Sroberto next; 41054359Sroberto }; 41154359Sroberto ;# otherwise: silently ignore unrecognized config line 41254359Sroberto } 41354359Sroberto close(CF); 41454359Sroberto ;# set show defaults when nothing selected 41554359Sroberto $showoffs = $showfreq = $showcmpl = 1 41654359Sroberto unless $showoffs || $showfreq || $showcmpl; 41754359Sroberto if ($verbose > 3) 41854359Sroberto { 41954359Sroberto print "new configuration:\n"; 42054359Sroberto print " delay\t= $delay\n"; 42154359Sroberto print " samples\t= $samples\n"; 42254359Sroberto print " srcprefix\t= $srcprefix\n"; 42354359Sroberto print " showoffs\t= $showoffs\n"; 42454359Sroberto print " showfreq\t= $showfreq\n"; 42554359Sroberto print " showcmpl\t= $showcmpl\n"; 42654359Sroberto print " showoreg\t= $showoreg\n"; 42754359Sroberto print " showfreg\t= $showfreg\n"; 42854359Sroberto printf " timebase\t= %s",defined($timebase)?&ctime($timebase):"dynamic\n"; 42954359Sroberto printf " freqbase\t= %s\n",defined($freqbase) ?"$freqbase":"dynamic"; 43054359Sroberto printf " cmplscale\t= %s\n",defined($cmplscale)?"$cmplscale":"dynamic"; 43154359Sroberto printf " StartTime\t= %s",defined($StartTime)?&ctime($StartTime):"none\n"; 43254359Sroberto printf " EndTime\t= %s", defined($EndTime) ? &ctime($EndTime):"none\n"; 43354359Sroberto printf " MaxY\t= %s",defined($MaxY)? $MaxY :"none\n"; 43454359Sroberto printf " MinY\t= %s",defined($MinY)? $MinY :"none\n"; 43554359Sroberto print " verbose\t= $verbose\n"; 43654359Sroberto } 43754359Srobertoprint "configuration file read\n" if $verbose > 2; 43854359Sroberto} 43954359Sroberto 440182007Srobertosub make_doplot($$) 44154359Sroberto{ 442182007Sroberto my($lo, $lf) = @_; 44354359Sroberto local($c) = (""); 44454359Sroberto local($fmt) 44554359Sroberto = ("%s \"%s\" using 1:%d title '%s <%lf %lf> %6s' with lines"); 44654359Sroberto local($regfmt) 44754359Sroberto = ("%s ((%lf * x) + %lf) title 'lin. approx. %s (%f t[h]) %s %f <%f> %6s' with lines"); 44854359Sroberto 44954359Sroberto $doplot = " set title 'NTP loopfilter statistics for $STATHOST " . 45054359Sroberto "(last $LastCnt samples from $srcprefix*)'\n"; 45154359Sroberto 45254359Sroberto local($xts,$xte,$i,$t); 45354359Sroberto 45454359Sroberto local($s,$c) = (""); 45554359Sroberto 45654359Sroberto ;# number of integral seconds to get at least 12 tic marks on x axis 45754359Sroberto $t = int(($maxtime - $mintime) / 12 + 0.5); 45854359Sroberto $t = 1 unless $t; # prevent $t to be zero 45954359Sroberto foreach $i (30, 46054359Sroberto 60,5*60,15*60,30*60, 46154359Sroberto 60*60,2*60*60,6*60*60,12*60*60, 46254359Sroberto 24*60*60,48*60*60) 46354359Sroberto { 46454359Sroberto last if $t < $i; 46554359Sroberto $t = $t - ($t % $i); 46654359Sroberto } 46754359Sroberto print "time label resolution: $t seconds\n" if $verbose > 1; 46854359Sroberto 46954359Sroberto ;# make gnuplot use wall clock time labels instead of NTP seconds 47054359Sroberto for ($c="", $i = $mintime - ($mintime % $t); 47154359Sroberto $i <= $maxtime + $t; 47254359Sroberto $i += $t, $c=",") 47354359Sroberto { 47454359Sroberto $s .= $c; 47554359Sroberto ((int($i / $t) % 2) && 47654359Sroberto ($s .= sprintf("'' %lf",($i - $LastTimeBase)/3600))) || 47754359Sroberto (($t <= 60) && 47854359Sroberto ($s .= sprintf("'%d:%02d:%02d' %lf", 47954359Sroberto (localtime($i))[$[+2,$[+1,$[+0], 48054359Sroberto ($i - $LastTimeBase)/3600))) 48154359Sroberto || (($t <= 2*60*60) && 48254359Sroberto ($s .= sprintf("'%d:%02d' %lf", 48354359Sroberto (localtime($i))[$[+2,$[+1], 48454359Sroberto ($i - $LastTimeBase)/3600))) 48554359Sroberto || (($t <= 12*60*60) && 48654359Sroberto ($s .= sprintf("'%s %d:00' %lf", 48754359Sroberto $Day[(localtime($i))[$[+6]], 48854359Sroberto (localtime($i))[$[+2], 48954359Sroberto ($i - $LastTimeBase)/3600))) 49054359Sroberto || ($s .= sprintf("'%d.%d-%d:00' %lf", 49154359Sroberto (localtime($i))[$[+3,$[+4,$[+2], 49254359Sroberto ($i - $LastTimeBase)/3600)); 49354359Sroberto } 49454359Sroberto $doplot .= "set xtics ($s)\n"; 49554359Sroberto 49654359Sroberto chop($xts = &ctime($mintime)); 49754359Sroberto chop($xte = &ctime($maxtime)); 49854359Sroberto $doplot .= "set xlabel 'Start: $xts -- Time Scale -- End: $xte'\n"; 49954359Sroberto $doplot .= "set yrange [" ; 50054359Sroberto $doplot .= defined($MinY) ? sprintf("%lf", $MinY) : $miny; 50154359Sroberto $doplot .= ':'; 50254359Sroberto $doplot .= defined($MaxY) ? sprintf("%lf", $MaxY) : $maxy; 50354359Sroberto $doplot .= "]\n"; 50454359Sroberto 50554359Sroberto $doplot .= " plot"; 50654359Sroberto $c = ""; 50754359Sroberto $showoffs && 50854359Sroberto ($doplot .= sprintf($fmt,$c,$tmpfile,2, 50954359Sroberto "offset", 51054359Sroberto $minoffs,$maxoffs, 51154359Sroberto "[ms]"), 51254359Sroberto $c = ","); 51354359Sroberto $LastCmplScale = 1 if ! defined($LastCmplScale); 51454359Sroberto $showcmpl && 51554359Sroberto ($doplot .= sprintf($fmt,$c,$tmpfile,4, 51654359Sroberto "compliance" . 51754359Sroberto (&abs($LastCmplScale) > 1 51854359Sroberto ? " / $LastCmplScale" 51954359Sroberto : (&abs($LastCmplScale) == 1 ? "" : " * ".(1/$LastCmplScale))), 52054359Sroberto $mincmpl/$LastCmplScale,$maxcmpl/$LastCmplScale, 52154359Sroberto ""), 52254359Sroberto $c = ","); 52354359Sroberto $LastFreqBase = 0 if ! defined($LastFreqBase); 52454359Sroberto $LastFreqBaseString = "?" if ! defined($LastFreqBaseString); 52554359Sroberto $FreqScale = 1 if ! defined($FreqScale); 52654359Sroberto $FreqScaleInv = 1 if ! defined($FreqScaleInv); 52754359Sroberto $showfreq && 52854359Sroberto ($doplot .= sprintf($fmt,$c,$tmpfile,3, 52954359Sroberto "frequency" . 53054359Sroberto ($LastFreqBase > 0 53154359Sroberto ? " - $LastFreqBaseString" 53254359Sroberto : ($LastFreqBase == 0 ? "" : " + $LastFreqBaseString")), 53354359Sroberto $minfreq * $FreqScale - $LastFreqBase, 53454359Sroberto $maxfreq * $FreqScale - $LastFreqBase, 53554359Sroberto "[${FreqScaleInv}ppm]"), 53654359Sroberto $c = ","); 53754359Sroberto $showoreg && $showoffs && 53854359Sroberto ($doplot .= sprintf($regfmt, $c, 539182007Sroberto $lo->B(),$lo->A(), 54054359Sroberto "offset ", 541182007Sroberto $lo->B(), 542182007Sroberto (($lo->A()) < 0 ? '-' : '+'), 543182007Sroberto &abs($lo->A()), $lo->r(), 54454359Sroberto "[ms]"), 54554359Sroberto $c = ","); 54654359Sroberto $showfreg && $showfreq && 54754359Sroberto ($doplot .= sprintf($regfmt, $c, 548182007Sroberto $lf->B() * $FreqScale, 549182007Sroberto ($lf->A() + $minfreq) * $FreqScale - $LastFreqBase, 55054359Sroberto "frequency", 551182007Sroberto $lf->B() * $FreqScale, 552182007Sroberto (($lf->A() + $minfreq) * $FreqScale - $LastFreqBase) < 0 ? '-' : '+', 553182007Sroberto &abs(($lf->A() + $minfreq) * $FreqScale - $LastFreqBase), 554182007Sroberto $lf->r(), 55554359Sroberto "[${FreqScaleInv}ppm]"), 55654359Sroberto $c = ","); 55754359Sroberto $doplot .= "\n"; 55854359Sroberto} 55954359Sroberto 56054359Sroberto%F_key = (); 56154359Sroberto%F_name = (); 56254359Sroberto%F_size = (); 56354359Sroberto%F_mtime = (); 56454359Sroberto%F_first = (); 56554359Sroberto%F_last = (); 56654359Sroberto 56754359Srobertosub genfile 56854359Sroberto{ 569182007Sroberto local($cnt,$in,$out,$lo,$lf,@fpos) = @_; 57054359Sroberto 57154359Sroberto local(@F,@t,$t,$lastT) = (); 57254359Sroberto local(@break,@time,@offs,@freq,@cmpl,@loffset,@filekey) = (); 57354359Sroberto local($lm,$l,@f); 57454359Sroberto 57554359Sroberto local($sdir,$sname); 57654359Sroberto 57754359Sroberto ;# allocate some storage for the tables 57854359Sroberto ;# otherwise realloc may get into troubles 57954359Sroberto if (defined($StartTime) && defined($EndTime)) 58054359Sroberto { 58154359Sroberto $l = ($EndTime-$StartTime) -$[+1 +1; # worst case: 1 sample per second 58254359Sroberto } 58354359Sroberto else 58454359Sroberto { 58554359Sroberto $l = $cnt + 10; 58654359Sroberto } 58754359Sroberto print "preextending arrays to $l entries\n" if $verbose > 2; 58854359Sroberto $#break = $l; for ($i=$[; $i<=$l;$i++) { $break[$i] = 0; } 58954359Sroberto $#time = $l; for ($i=$[; $i<=$l;$i++) { $time[$i] = 0; } 59054359Sroberto $#offs = $l; for ($i=$[; $i<=$l;$i++) { $offs[$i] = 0; } 59154359Sroberto $#freq = $l; for ($i=$[; $i<=$l;$i++) { $freq[$i] = 0; } 59254359Sroberto $#cmpl = $l; for ($i=$[; $i<=$l;$i++) { $cmpl[$i] = 0; } 59354359Sroberto $#loffset = $l; for ($i=$[; $i<=$l;$i++) { $loffset[$i] = 0; } 59454359Sroberto $#filekey = $l; for ($i=$[; $i<=$l;$i++) { $filekey[$i] = 0; } 59554359Sroberto ;# now reduce size again 59654359Sroberto $#break = $[ - 1; 59754359Sroberto $#time = $[ - 1; 59854359Sroberto $#offs = $[ - 1; 59954359Sroberto $#freq = $[ - 1; 60054359Sroberto $#cmpl = $[ - 1; 60154359Sroberto $#loffset = $[ - 1; 60254359Sroberto $#filekey = $[ - 1; 60354359Sroberto print "memory allocation ready\n" if $verbose > 2; 60454359Sroberto sleep(3) if $verbose > 1; 60554359Sroberto 60654359Sroberto $fpos[$[] = '' if !defined($fpos[$[]); 60754359Sroberto 60854359Sroberto if (index($in,"/") < $[) 60954359Sroberto { 61054359Sroberto $sdir = "."; 61154359Sroberto $sname = $in; 61254359Sroberto } 61354359Sroberto else 61454359Sroberto { 61554359Sroberto ($sdir,$sname) = ($in =~ m!^(.*)/([^/]*)!); 61654359Sroberto $sname = "" unless defined($sname); 61754359Sroberto } 61854359Sroberto 61954359Sroberto $Ltime = -1 if ! defined($Ltime); 62054359Sroberto if (!defined($Lsdir) || $Lsdir ne $sdir || $Ltime != (stat($sdir))[$[+9] || 62154359Sroberto grep($F_mtime{$_} != (stat($F_name{$_}))[$[+9], @F_files)) 62254359Sroberto 62354359Sroberto { 62454359Sroberto print "rescanning directory \"$sdir\" for files \"$sname*\"\n" 62554359Sroberto if $verbose > 1; 62654359Sroberto 62754359Sroberto ;# rescan directory on changes 62854359Sroberto $Lsdir = $sdir; 62954359Sroberto $Ltime = (stat($sdir))[$[+9]; 63054359Sroberto </X{> if 0; # dummy line - calm down my formatter 63154359Sroberto local(@newfiles) = < ${in}*[0-9] >; 63254359Sroberto local($st_dev,$st_ino,$st_mtime,$st_size,$name,$key,$modified); 63354359Sroberto 63454359Sroberto foreach $name (@newfiles) 63554359Sroberto { 63654359Sroberto ($st_dev,$st_ino,$st_size,$st_mtime) = 63754359Sroberto (stat($name))[$[,$[+1,$[+7,$[+9]; 63854359Sroberto $modified = 0; 63954359Sroberto $key = sprintf("%lx|%lu", $st_dev, $st_ino); 64054359Sroberto 64154359Sroberto print "candidate file \"$name\"", 64254359Sroberto (defined($st_dev) ? "" : " failed: $!"),"\n" 64354359Sroberto if $verbose > 2; 64454359Sroberto 64554359Sroberto if (! defined($F_key{$name}) || $F_key{$name} ne $key) 64654359Sroberto { 64754359Sroberto $F_key{$name} = $key; 64854359Sroberto $modified++; 64954359Sroberto } 65054359Sroberto if (!defined($F_name{$key}) || $F_name{$key} ne $name) 65154359Sroberto { 65254359Sroberto $F_name{$key} = $name; 65354359Sroberto $modified++; 65454359Sroberto } 65554359Sroberto if (!defined($F_size{$key}) || $F_size{$key} != $st_size) 65654359Sroberto { 65754359Sroberto $F_size{$key} = $st_size; 65854359Sroberto $modified++; 65954359Sroberto } 66054359Sroberto if (!defined($F_mtime{$key}) || $F_mtime{$key} != $st_mtime) 66154359Sroberto { 66254359Sroberto $F_mtime{$key} = $st_mtime; 66354359Sroberto $modified++; 66454359Sroberto } 66554359Sroberto if ($modified) 66654359Sroberto { 66754359Sroberto print "new data \"$name\" key: $key;\n" if $verbose > 1; 66854359Sroberto print " size: $st_size; mtime: $st_mtime;\n" 66954359Sroberto if $verbose > 1; 67054359Sroberto $F_last{$key} = $F_first{$key} = $st_mtime; 67154359Sroberto $F_first{$key}--; # prevent zero divide later on 67254359Sroberto ;# now compute derivated attributes 67354359Sroberto open(IN, "<$name") || 67454359Sroberto do { 67554359Sroberto warn "$0: failed to open \"$name\": $!"; 67654359Sroberto next; 67754359Sroberto }; 67854359Sroberto 67954359Sroberto while(<IN>) 68054359Sroberto { 68154359Sroberto @F = split; 68254359Sroberto next if @F < 5; 68354359Sroberto next if $F[$[] eq ""; 68454359Sroberto $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; 68554359Sroberto $t += $F[$[+1]; 68654359Sroberto $F_first{$key} = $t; 68754359Sroberto print "\tfound first entry: $t ",&ctime($t) 68854359Sroberto if $verbose > 4; 68954359Sroberto last; 69054359Sroberto } 69154359Sroberto seek(IN, 69254359Sroberto ($st_size > 4*$RecordSize) ? $st_size - 4*$RecordSize : 0, 69354359Sroberto 0); 69454359Sroberto while(<IN>) 69554359Sroberto { 69654359Sroberto @F = split; 69754359Sroberto next if @F < 5; 69854359Sroberto next if $F[$[] eq ""; 69954359Sroberto $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; 70054359Sroberto $t += $F[$[+1]; 70154359Sroberto $F_last{$key} = $t; 70254359Sroberto $_ = <IN>; 70354359Sroberto print "\tfound last entry: $t ", &ctime($t) 70454359Sroberto if $verbose > 4 && ! defined($_); 70554359Sroberto last unless defined($_); 70654359Sroberto redo; 70754359Sroberto ;# Ok, calm down... 70854359Sroberto ;# using $_ = <IN> in conjunction with redo 70954359Sroberto ;# is semantically equivalent to the while loop, but 71054359Sroberto ;# I needed a one line look ahead and this solution 71154359Sroberto ;# was what I thought of first 71254359Sroberto ;# and.. If you do not like it dont look 71354359Sroberto } 71454359Sroberto close(IN); 71554359Sroberto print(" first: ",$F_first{$key}, 71654359Sroberto " last: ",$F_last{$key},"\n") if $verbose > 1; 71754359Sroberto } 71854359Sroberto } 71954359Sroberto ;# now reclaim memory used for files no longer referenced ... 72054359Sroberto local(%Names); 72154359Sroberto grep($Names{$_} = 1,@newfiles); 72254359Sroberto foreach (keys %F_key) 72354359Sroberto { 72454359Sroberto next if defined($Names{$_}); 72554359Sroberto delete $F_key{$_}; 72654359Sroberto $verbose > 2 && print "no longer referenced: \"$_\"\n"; 72754359Sroberto } 72854359Sroberto %Names = (); 72954359Sroberto 73054359Sroberto grep($Names{$_} = 1,values(%F_key)); 73154359Sroberto foreach (keys %F_name) 73254359Sroberto { 73354359Sroberto next if defined($Names{$_}); 73454359Sroberto delete $F_name{$_}; 73554359Sroberto $verbose > 2 && print "unref name($_)= $F_name{$_}\n"; 73654359Sroberto } 73754359Sroberto foreach (keys %F_size) 73854359Sroberto { 73954359Sroberto next if defined($Names{$_}); 74054359Sroberto delete $F_size{$_}; 74154359Sroberto $verbose > 2 && print "unref size($_)\n"; 74254359Sroberto } 74354359Sroberto foreach (keys %F_mtime) 74454359Sroberto { 74554359Sroberto next if defined($Names{$_}); 74654359Sroberto delete $F_mtime{$_}; 74754359Sroberto $verbose > 2 && print "unref mtime($_)\n"; 74854359Sroberto } 74954359Sroberto foreach (keys %F_first) 75054359Sroberto { 75154359Sroberto next if defined($Names{$_}); 75254359Sroberto delete $F_first{$_}; 75354359Sroberto $verbose > 2 && print "unref first($_)\n"; 75454359Sroberto } 75554359Sroberto foreach (keys %F_last) 75654359Sroberto { 75754359Sroberto next if defined($Names{$_}); 75854359Sroberto delete $F_last{$_}; 75954359Sroberto $verbose > 2 && print "unref last($_)\n"; 76054359Sroberto } 76154359Sroberto ;# create list sorted by time 76254359Sroberto @F_files = sort {$F_first{$a} <=> $F_first{$b}; } keys(%F_name); 76354359Sroberto if ($verbose > 1) 76454359Sroberto { 76554359Sroberto print "Resulting file list:\n"; 76654359Sroberto foreach (@F_files) 76754359Sroberto { 76854359Sroberto print "\t$_\t$F_name{$_}\n"; 76954359Sroberto } 77054359Sroberto } 77154359Sroberto } 77254359Sroberto 77354359Sroberto printf("processing %s; output \"$out\" (%d input files)\n", 77454359Sroberto ((defined($StartTime) && defined($EndTime)) 77554359Sroberto ? "time range" 77654359Sroberto : (defined($StartTime) ? "$cnt samples from StartTime" : 77754359Sroberto (defined($EndTime) ? "$cnt samples to EndTime" : 77854359Sroberto "last $cnt samples"))), 77954359Sroberto scalar(@F_files)) 78054359Sroberto if $verbose > 1; 78154359Sroberto 78254359Sroberto ;# open output file - will be input for plotcmd 78354359Sroberto open(OUT,">$out") || 78454359Sroberto do { 78554359Sroberto warn("$0: cannot create \"$out\": $!\n"); 78654359Sroberto }; 78754359Sroberto 78854359Sroberto @f = @F_files; 78954359Sroberto if (defined($StartTime)) 79054359Sroberto { 79154359Sroberto while (@f && ($F_last{$f[$[]} < $StartTime)) 79254359Sroberto { 79354359Sroberto print("shifting ", $F_name{$f[$[]}, 79454359Sroberto " last: ", $F_last{$f[$[]}, 79554359Sroberto " < StartTime: $StartTime\n") 79654359Sroberto if $verbose > 3; 79754359Sroberto shift(@f); 79854359Sroberto } 79954359Sroberto 80054359Sroberto 80154359Sroberto } 80254359Sroberto if (defined($EndTime)) 80354359Sroberto { 80454359Sroberto while (@f && ($F_first{$f[$#f]} > $EndTime)) 80554359Sroberto { 80654359Sroberto print("popping ", $F_name{$f[$#f]}, 80754359Sroberto " first: ", $F_first{$f[$#f]}, 80854359Sroberto " > EndTime: $EndTime\n") 80954359Sroberto if $verbose > 3; 81054359Sroberto pop(@f); 81154359Sroberto } 81254359Sroberto } 81354359Sroberto 81454359Sroberto if (@f) 81554359Sroberto { 81654359Sroberto if (defined($StartTime)) 81754359Sroberto { 81854359Sroberto print "guess start according to StartTime ($StartTime)\n" 81954359Sroberto if $verbose > 3; 82054359Sroberto 82154359Sroberto if ($fpos[$[] eq 'start') 82254359Sroberto { 82354359Sroberto if (grep($_ eq $fpos[$[+1],@f)) 82454359Sroberto { 82554359Sroberto shift(@f) while @f && $f[$[] ne $fpos[$[+1]; 82654359Sroberto } 82754359Sroberto else 82854359Sroberto { 82954359Sroberto @fpos = ('start', $f[$[], undef); 83054359Sroberto } 83154359Sroberto } 83254359Sroberto else 83354359Sroberto { 83454359Sroberto @fpos = ('start' , $f[$[], undef); 83554359Sroberto } 83654359Sroberto 83754359Sroberto if (!defined($fpos[$[+2])) 83854359Sroberto { 83954359Sroberto if ($StartTime <= $F_first{$f[$[]}) 84054359Sroberto { 84154359Sroberto $fpos[$[+2] = 0; 84254359Sroberto } 84354359Sroberto else 84454359Sroberto { 84554359Sroberto $fpos[$[+2] = 84654359Sroberto int($F_size{$f[$[]} * 84754359Sroberto (($StartTime - $F_first{$f[$[]})/ 84854359Sroberto ($F_last{$f[$[]} - $F_first{$f[$[]}))); 84954359Sroberto $fpos[$[+2] = ($fpos[$[+2] <= 2 * $RecordSize) 85054359Sroberto ? 0 : $fpos[$[+2] - 2 * $RecordSize; 85154359Sroberto ;# anyway as the data may contain "time holes" 85254359Sroberto ;# our heuristics may baldly fail 85354359Sroberto ;# so just start at 0 85454359Sroberto $fpos[$[+2] = 0; 85554359Sroberto } 85654359Sroberto } 85754359Sroberto } 85854359Sroberto elsif (defined($EndTime)) 85954359Sroberto { 86054359Sroberto print "guess starting point according to EndTime ($EndTime)\n" 86154359Sroberto if $verbose > 3; 86254359Sroberto 86354359Sroberto if ($fpos[$[] eq 'end') 86454359Sroberto { 86554359Sroberto if (grep($_ eq $fpos[$[+1],@f)) 86654359Sroberto { 86754359Sroberto shift(@f) while @f && $f[$[] ne $fpos[$[+1]; 86854359Sroberto } 86954359Sroberto else 87054359Sroberto { 87154359Sroberto @fpos = ('end', $f[$[], undef); 87254359Sroberto } 87354359Sroberto } 87454359Sroberto else 87554359Sroberto { 87654359Sroberto @fpos = ('end', $f[$[], undef); 87754359Sroberto } 87854359Sroberto 87954359Sroberto if (!defined($fpos[$[+2])) 88054359Sroberto { 88154359Sroberto local(@x) = reverse(@f); 88254359Sroberto local($s,$c) = (0,$cnt); 88354359Sroberto if ($EndTime < $F_last{$x[$[]}) 88454359Sroberto { 88554359Sroberto ;# last file will only be used partially 88654359Sroberto $s = int($F_size{$x[$[]} * 88754359Sroberto (($EndTime - $F_first{$x[$[]}) / 88854359Sroberto ($F_last{$x[$[]} - $F_first{$x[$[]}))); 88954359Sroberto $s = int($s/$RecordSize); 89054359Sroberto $c -= $s - 1; 89154359Sroberto if ($c <= 0) 89254359Sroberto { 89354359Sroberto ;# start is in the same file 89454359Sroberto $fpos[$[+1] = $x[$[]; 89554359Sroberto $fpos[$[+2] = ($c >=-2) ? 0 : (-$c - 2) * $RecordSize; 89654359Sroberto shift(@f) while @f && ($f[$[] ne $x[$[]); 89754359Sroberto } 89854359Sroberto else 89954359Sroberto { 90054359Sroberto shift(@x); 90154359Sroberto } 90254359Sroberto } 90354359Sroberto 90454359Sroberto if (!defined($fpos[$[+2])) 90554359Sroberto { 90654359Sroberto local($_); 90754359Sroberto while($_ = shift(@x)) 90854359Sroberto { 90954359Sroberto $s = int($F_size{$_}/$RecordSize); 91054359Sroberto $c -= $s - 1; 91154359Sroberto if ($c <= 0) 91254359Sroberto { 91354359Sroberto $fpos[$[+1] = $_; 91454359Sroberto $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; 91554359Sroberto shift(@f) while @f && ($f[$[] ne $_); 91654359Sroberto last; 91754359Sroberto } 91854359Sroberto } 91954359Sroberto } 92054359Sroberto } 92154359Sroberto } 92254359Sroberto else 92354359Sroberto { 92454359Sroberto print "guessing starting point according to count ($cnt)\n" 92554359Sroberto if $verbose > 3; 92654359Sroberto ;# guess offset to get last available $cnt samples 92754359Sroberto if ($fpos[$[] eq 'cnt') 92854359Sroberto { 92954359Sroberto if (grep($_ eq $fpos[$[+1],@f)) 93054359Sroberto { 93154359Sroberto print "old positioning applies\n" if $verbose > 3; 93254359Sroberto shift(@f) while @f && $f[$[] ne $fpos[$[+1]; 93354359Sroberto } 93454359Sroberto else 93554359Sroberto { 93654359Sroberto @fpos = ('cnt', $f[$[], undef); 93754359Sroberto } 93854359Sroberto } 93954359Sroberto else 94054359Sroberto { 94154359Sroberto @fpos = ('cnt', $f[$[], undef); 94254359Sroberto } 94354359Sroberto 94454359Sroberto if (!defined($fpos[$[+2])) 94554359Sroberto { 94654359Sroberto local(@x) = reverse(@f); 94754359Sroberto local($s,$c) = (0,$cnt); 94854359Sroberto 94954359Sroberto local($_); 95054359Sroberto while($_ = shift(@x)) 95154359Sroberto { 95254359Sroberto print "examing \"$_\" $c samples still needed\n" 95354359Sroberto if $verbose > 4; 95454359Sroberto $s = int($F_size{$_}/$RecordSize); 95554359Sroberto $c -= $s - 1; 95654359Sroberto if ($c <= 0) 95754359Sroberto { 95854359Sroberto $fpos[$[+1] = $_; 95954359Sroberto $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; 96054359Sroberto shift(@f) while @f && ($f[$[] ne $_); 96154359Sroberto last; 96254359Sroberto } 96354359Sroberto } 96454359Sroberto if (!defined($fpos[$[+2])) 96554359Sroberto { 96654359Sroberto print "no starting point yet - using start of data\n" 96754359Sroberto if $verbose > 2; 96854359Sroberto $fpos[$[+2] = 0; 96954359Sroberto } 97054359Sroberto } 97154359Sroberto } 97254359Sroberto } 97354359Sroberto print "Ooops, no suitable input file ??\n" 97454359Sroberto if $verbose > 1 && @f <= 0; 97554359Sroberto 97654359Sroberto printf("Starting at (%s) \"%s\" offset %ld using %d files\n", 97754359Sroberto $fpos[$[+1], 97854359Sroberto $F_name{$fpos[$[+1]}, 97954359Sroberto $fpos[$[+2], 98054359Sroberto scalar(@f)) 98154359Sroberto if $verbose > 2; 98254359Sroberto 98354359Sroberto $lm = 1; 98454359Sroberto $l = 0; 98554359Sroberto foreach $key (@f) 98654359Sroberto { 98754359Sroberto $file = $F_name{$key}; 98854359Sroberto print "processing file \"$file\"\n" if $verbose > 2; 98954359Sroberto 99054359Sroberto open(IN,"<$file") || 99154359Sroberto (warn("$0: cannot read \"$file\": $!\n"), next); 99254359Sroberto 99354359Sroberto ;# try to seek to a position nearer to the start of the interesting lines 99454359Sroberto ;# should always affect only first item in @f 99554359Sroberto ($key eq $fpos[$[+1]) && 99654359Sroberto (($verbose > 1) && 99754359Sroberto print("Seeking to offset $fpos[$[+2]\n"), 99854359Sroberto seek(IN,$fpos[$[+2],0) || 99954359Sroberto warn("$0: seek(\"$F_name{$key}\" failed: $|\n")); 100054359Sroberto 100154359Sroberto while(<IN>) 100254359Sroberto { 100354359Sroberto $l++; 100454359Sroberto ($verbose > 3) && 100554359Sroberto (($l % $lm) == 0 && print("\t$l lines read\n") && 100654359Sroberto (($l == 2) && ($lm = 10) || 100754359Sroberto ($l == 100) && ($lm = 100) || 100854359Sroberto ($l == 500) && ($lm = 500) || 100954359Sroberto ($l == 1000) && ($lm = 1000) || 101054359Sroberto ($l == 5000) && ($lm = 5000) || 101154359Sroberto ($l == 10000) && ($lm = 10000))); 101254359Sroberto 101354359Sroberto @F = split; 101454359Sroberto 101554359Sroberto next if @F < 6; # no valid input line is this short 101654359Sroberto next if $F[$[] eq ""; 101754359Sroberto next if ($F[$[] !~ /^\d+$/); 101854359Sroberto ($F[$[] !~ /^\d+$/) && # A 'never should have happend' error 101954359Sroberto die("$0: unexpected input line: >$_<\n"); 102054359Sroberto 102154359Sroberto ;# modified Julian to UNIX epoch 102254359Sroberto $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; 102354359Sroberto $t += $F[$[+1]; # add seconds + fraction 102454359Sroberto 102554359Sroberto ;# multiply offset by 1000 to get ms - try to avoid float op 102654359Sroberto (($F[$[+2] =~ s/(\d*)\.(\d{3})(\d*)/$1$2.$3/) && 102754359Sroberto $F[$[+2] =~ s/0+([\d\.])/($1 eq '.') ? '0.' : $1/e) # strip leading zeros 102854359Sroberto || ($F[$[+2] *= 1000); 102954359Sroberto 103054359Sroberto 103154359Sroberto ;# skip samples out of specified time range 103254359Sroberto next if (defined($StartTime) && $StartTime > $t); 103354359Sroberto next if (defined($EndTime) && $EndTime < $t); 103454359Sroberto 103554359Sroberto next if defined($lastT) && $t < $lastT; # backward in time ?? 103654359Sroberto 103754359Sroberto push(@offs,$F[$[+2]); 103854359Sroberto push(@freq,$F[$[+3] * (2**20/10**6)); 103954359Sroberto push(@cmpl,$F[$[+5]); 104054359Sroberto 104154359Sroberto push(@break, (defined($lastT) && ($t - $lastT > $deltaT))); 104254359Sroberto $lastT = $t; 104354359Sroberto push(@time,$t); 104454359Sroberto push(@loffset, tell(IN) - length($_)); 104554359Sroberto push(@filekey, $key); 104654359Sroberto 104754359Sroberto shift(@break),shift(@time),shift(@offs), 104854359Sroberto shift(@freq), shift(@cmpl),shift(@loffset), 104954359Sroberto shift(@filekey) 105054359Sroberto if @time > $cnt && 105154359Sroberto ! (defined($StartTime) && defined($EndTime)); 105254359Sroberto 105354359Sroberto last if @time >= $cnt && defined($StartTime) && !defined($EndTime); 105454359Sroberto } 105554359Sroberto close(IN); 105654359Sroberto last if @time >= $cnt && defined($StartTime) && !defined($EndTime); 105754359Sroberto } 105854359Sroberto print "input scanned ($l lines/",scalar(@time)," samples)\n" 105954359Sroberto if $verbose > 1; 106054359Sroberto 106154359Sroberto if (@time) 106254359Sroberto { 106354359Sroberto local($_,@F); 106454359Sroberto 106554359Sroberto local($timebase) unless defined($timebase); 106654359Sroberto local($freqbase) unless defined($freqbase); 106754359Sroberto local($cmplscale) unless defined($cmplscale); 106854359Sroberto 106954359Sroberto undef $mintime; 107054359Sroberto undef $maxtime; 107154359Sroberto undef $minoffs; 107254359Sroberto undef $maxoffs; 107354359Sroberto undef $minfreq; 107454359Sroberto undef $maxfreq; 107554359Sroberto undef $mincmpl; 107654359Sroberto undef $maxcmpl; 107754359Sroberto undef $miny; 107854359Sroberto undef $maxy ; 107954359Sroberto 108054359Sroberto print "computing ranges\n" if $verbose > 2; 108154359Sroberto 108254359Sroberto $LastCnt = @time; 108354359Sroberto 108454359Sroberto ;# @time is in ascending order (;-) 108554359Sroberto $mintime = $time[$[]; 108654359Sroberto $maxtime = $time[$#time]; 108754359Sroberto unless (defined($timebase)) 108854359Sroberto { 108954359Sroberto local($time,@X) = (time); 109054359Sroberto @X = localtime($time); 109154359Sroberto 109254359Sroberto ;# compute today 00:00:00 109354359Sroberto $timebase = $time - ((($X[$[+2]*60)+$X[$[+1])*60+$X[$[]); 109454359Sroberto 109554359Sroberto } 109654359Sroberto $LastTimeBase = $timebase; 109754359Sroberto 109854359Sroberto if ($showoffs) 109954359Sroberto { 110054359Sroberto local($i,$m,$f); 110154359Sroberto 110254359Sroberto $minoffs = &min(@offs); 110354359Sroberto $maxoffs = &max(@offs); 110454359Sroberto 110554359Sroberto ;# I know, it is not perl style using indices to access arrays, 110654359Sroberto ;# but I have to proccess two arrays in sync, non-destructively 110754359Sroberto ;# (otherwise a (shift(@a1),shift(a2)) would do), 110854359Sroberto ;# I dont like to make copies of these arrays as they may be huge 110954359Sroberto $i = $[; 1110182007Sroberto $lo->sample(($time[$i]-$timebase)/3600,$offs[$i]),$i++ 111154359Sroberto while $i <= $#time; 111254359Sroberto 111354359Sroberto ($minoffs == $maxoffs) && ($minoffs -= 0.1,$maxoffs += 0.1); 111454359Sroberto 1115182007Sroberto $i = $lo->sigma(); 1116182007Sroberto $m = $lo->mean(); 111754359Sroberto 111854359Sroberto print "mean offset: $m sigma: $i\n" if $verbose > 2; 111954359Sroberto 112054359Sroberto if (($maxoffs - $minoffs) > $MinClip) 112154359Sroberto { 112254359Sroberto $f = (&abs($minoffs) < &abs($maxoffs)) ? $FuzzLow : $FuzzBig; 112354359Sroberto $miny = (($m - $minoffs) <= ($f * $i)) 112454359Sroberto ? $minoffs : ($m - $f * $i); 112554359Sroberto $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow; 112654359Sroberto $maxy = (($maxoffs - $m) <= ($f * $i)) 112754359Sroberto ? $maxoffs : ($m + $f * $i); 112854359Sroberto } 112954359Sroberto else 113054359Sroberto { 113154359Sroberto $miny = $minoffs; 113254359Sroberto $maxy = $maxoffs; 113354359Sroberto } 113454359Sroberto ($maxy-$miny) == 0 && 113554359Sroberto (($maxy,$miny) 113654359Sroberto = (($maxoffs - $minoffs) > 0) 113754359Sroberto ? ($maxoffs,$minoffs) : ($MinClip,-$MinClip)); 113854359Sroberto 113954359Sroberto $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy; 114054359Sroberto $miny = $MinY if defined($MinY) && $MinY > $miny; 114154359Sroberto 114254359Sroberto print "offset min clipped from $minoffs to $miny\n" 114354359Sroberto if $verbose > 2 && $minoffs != $miny; 114454359Sroberto print "offset max clipped from $maxoffs to $maxy\n" 114554359Sroberto if $verbose > 2 && $maxoffs != $maxy; 114654359Sroberto } 114754359Sroberto 114854359Sroberto if ($showfreq) 114954359Sroberto { 115054359Sroberto local($i,$m); 115154359Sroberto 115254359Sroberto $minfreq = &min(@freq); 115354359Sroberto $maxfreq = &max(@freq); 115454359Sroberto 115554359Sroberto $i = $[; 1156182007Sroberto $lf->sample(($time[$i]-$timebase)/3600,$freq[$i]-$minfreq), 115754359Sroberto $i++ 115854359Sroberto while $i <= $#time; 115954359Sroberto 1160182007Sroberto $i = $lf->sigma(); 1161182007Sroberto $m = $lf->mean() + $minfreq; 116254359Sroberto 116354359Sroberto print "mean frequency: $m sigma: $i\n" if $verbose > 2; 116454359Sroberto 116554359Sroberto if (defined($maxy)) 116654359Sroberto { 116754359Sroberto local($s) = 116854359Sroberto ($maxfreq - $minfreq) 116954359Sroberto ? ($maxy - $miny) / ($maxfreq - $minfreq) : 1; 117054359Sroberto 117154359Sroberto if (defined($freqbase)) 117254359Sroberto { 117354359Sroberto $FreqScale = 1; 117454359Sroberto $FreqScaleInv = ""; 117554359Sroberto } 117654359Sroberto else 117754359Sroberto { 117854359Sroberto $FreqScale = 1; 117954359Sroberto $FreqScale = 10 ** int(log($s)/log(10) - 0.9999); 118054359Sroberto $FreqScaleInv = 118154359Sroberto ("$FreqScale" =~ /^10(0*)$/) ? "0.${1}1" : 118254359Sroberto ($FreqScale == 1 ? "" : (1/$FreqScale)); 118354359Sroberto 118454359Sroberto $freqbase = ($maxfreq + $minfreq)/ 2 * $FreqScale; #$m * $FreqScale; 1185182007Sroberto $freqbase -= ($maxy + $miny) / 2; #$lf->mean(); 118654359Sroberto 118754359Sroberto ;# round resulting freqbase 118854359Sroberto ;# to precision of min max difference 118954359Sroberto $s = -12; 119054359Sroberto $s = int(log(($maxfreq-$minfreq)*$FreqScale)/log(10))-1 119154359Sroberto unless ($maxfreq-$minfreq) < 1e-12; 119254359Sroberto $s = 10 ** $s; 119354359Sroberto $freqbase = int($freqbase / $s) * $s; 119454359Sroberto } 119554359Sroberto } 119654359Sroberto else 119754359Sroberto { 119854359Sroberto $FreqScale = 1; 119954359Sroberto $FreqScaleInv = ""; 120054359Sroberto $freqbase = $m unless defined($freqbase); 120154359Sroberto if (($maxfreq - $minfreq) > $MinClip) 120254359Sroberto { 120354359Sroberto $f = (&abs($minfreq) < &abs($maxfreq)) 120454359Sroberto ? $FuzzLow : $FuzzBig; 120554359Sroberto $miny = (($freqbase - $minfreq) <= ($f * $i)) 120654359Sroberto ? ($minfreq-$freqbase) : (- $f * $i); 120754359Sroberto $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow; 120854359Sroberto $maxy = (($maxfreq - $freqbase) <= ($f * $i)) 120954359Sroberto ? ($maxfreq-$freqbase) : ($f * $i); 121054359Sroberto } 121154359Sroberto else 121254359Sroberto { 121354359Sroberto $miny = $minfreq - $freqbase; 121454359Sroberto $maxy = $maxfreq - $freqbase; 121554359Sroberto } 121654359Sroberto ($maxy - $miny) == 0 && 121754359Sroberto (($maxy,$miny) = 121854359Sroberto (($maxfreq - $minfreq) > 0) 121954359Sroberto ? ($maxfreq-$freqbase,$minfreq-$freqbase) : (0.5,-0.5)); 122054359Sroberto 122154359Sroberto $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy; 122254359Sroberto $miny = $MinY if defined($MinY) && $MinY > $miny; 122354359Sroberto 122454359Sroberto print("frequency min clipped from ",$minfreq-$freqbase, 122554359Sroberto " to $miny\n") 122654359Sroberto if $verbose > 2 && $miny != ($minfreq - $freqbase); 122754359Sroberto print("frequency max clipped from ",$maxfreq-$freqbase, 122854359Sroberto " to $maxy\n") 122954359Sroberto if $verbose > 2 && $maxy != ($maxfreq - $freqbase); 123054359Sroberto } 123154359Sroberto $LastFreqBaseString = 123254359Sroberto sprintf("%g",$freqbase >= 0 ? $freqbase : -$freqbase); 123354359Sroberto $LastFreqBase = $freqbase; 123454359Sroberto print "LastFreqBaseString now \"$LastFreqBaseString\"\n" 123554359Sroberto if $verbose > 5; 123654359Sroberto } 123754359Sroberto else 123854359Sroberto { 123954359Sroberto $FreqScale = 1; 124054359Sroberto $FreqScaleInv = ""; 124154359Sroberto $LastFreqBase = 0; 124254359Sroberto $LastFreqBaseString = ""; 124354359Sroberto } 124454359Sroberto 124554359Sroberto if ($showcmpl) 124654359Sroberto { 124754359Sroberto $mincmpl = &min(@cmpl); 124854359Sroberto $maxcmpl = &max(@cmpl); 124954359Sroberto 125054359Sroberto if (!defined($cmplscale)) 125154359Sroberto { 125254359Sroberto if (defined($maxy)) 125354359Sroberto { 125454359Sroberto local($cmp) 125554359Sroberto = (&abs($miny) > &abs($maxy)) ? &abs($miny) : $maxy; 125654359Sroberto $cmplscale = $cmp == $maxy ? 1 : -1; 125754359Sroberto 125854359Sroberto foreach (0.01, 0.02, 0.05, 125954359Sroberto 0.1, 0.2, 0.25, 0.4, 0.5, 126054359Sroberto 1, 2, 4, 5, 126154359Sroberto 10, 20, 25, 50, 126254359Sroberto 100, 200, 250, 500, 1000) 126354359Sroberto { 126454359Sroberto $cmplscale *= $_, last if $maxcmpl/$_ <= $cmp; 126554359Sroberto } 126654359Sroberto } 126754359Sroberto else 126854359Sroberto { 126954359Sroberto $cmplscale = 1; 127054359Sroberto $miny = $mincmpl ? 0 : -$MinClip; 127154359Sroberto $maxy = $maxcmpl+$MinClip; 127254359Sroberto } 127354359Sroberto } 127454359Sroberto $LastCmplScale = $cmplscale; 127554359Sroberto } 127654359Sroberto else 127754359Sroberto { 127854359Sroberto $LastCmplScale = 1; 127954359Sroberto } 128054359Sroberto 128154359Sroberto print "creating plot command input file\n" if $verbose > 2; 128254359Sroberto 128354359Sroberto 128454359Sroberto print OUT ("# preprocessed NTP statistics file for $STATHOST\n"); 128554359Sroberto print OUT ("# timebase is: ",&ctime($LastTimeBase)) 128654359Sroberto if defined($LastTimeBase); 128754359Sroberto print OUT ("# frequency is offset by ", 128854359Sroberto ($LastFreqBase >= 0 ? "+" : "-"), 128954359Sroberto "$LastFreqBaseString [${FreqScaleInv}ppm]\n"); 129054359Sroberto print OUT ("# compliance is scaled by $LastCmplScale\n"); 129154359Sroberto print OUT ("# time [h]\toffset [ms]\tfrequency [${FreqScaleInv}ppm]\tcompliance\n"); 129254359Sroberto 129354359Sroberto printf OUT ("%s%lf\t%lf\t%lf\t%lf\n", 129454359Sroberto (shift(@break) ? "\n" : ""), 129554359Sroberto (shift(@time) - $LastTimeBase)/3600, 129654359Sroberto shift(@offs), 129754359Sroberto shift(@freq) * $FreqScale - $LastFreqBase, 129854359Sroberto shift(@cmpl) / $LastCmplScale) 129954359Sroberto while(@time); 130054359Sroberto } 130154359Sroberto else 130254359Sroberto { 130354359Sroberto ;# prevent plotcmd from processing empty file 130454359Sroberto print "Creating plot command dummy...\n" if $verbose > 2; 130554359Sroberto print OUT "# dummy samples\n0 1 2 3\n1 1 2 3\n"; 1306182007Sroberto $lo->sample(0,1); 1307182007Sroberto $lo->sample(1,1); 1308182007Sroberto $lf->sample(0,2); 1309182007Sroberto $lf->sample(1,2); 131054359Sroberto @time = (0, 1); $maxtime = 1; $mintime = 0; 131154359Sroberto @offs = (1, 1); $maxoffs = 1; $minoffs = 1; 131254359Sroberto @freq = (2, 2); $maxfreq = 2; $minfreq = 2; 131354359Sroberto @cmpl = (3, 3); $maxcmpl = 3; $mincmpl = 3; 131454359Sroberto $LastCnt = 2; 131554359Sroberto $LastFreqBase = 0; 131654359Sroberto $LastCmplScale = 1; 131754359Sroberto $LastTimeBase = 0; 131854359Sroberto $miny = -$MinClip; 131954359Sroberto $maxy = 3 + $MinClip; 132054359Sroberto } 132154359Sroberto close(OUT); 132254359Sroberto 132354359Sroberto print "plot command input file created\n" 132454359Sroberto if $verbose > 2; 132554359Sroberto 132654359Sroberto 132754359Sroberto if (($fpos[$[] eq 'cnt' && scalar(@loffset) >= $cnt) || 132854359Sroberto ($fpos[$[] eq 'start' && $mintime <= $StartTime) || 132954359Sroberto ($fpos[$[] eq 'end')) 133054359Sroberto { 133154359Sroberto return ($fpos[$[],$filekey[$[],$loffset[$[]); 133254359Sroberto } 133354359Sroberto else # found to few lines - next time start search earlier in file 133454359Sroberto { 133554359Sroberto if ($fpos[$[] eq 'start') 133654359Sroberto { 133754359Sroberto ;# the timestamps we got for F_first and F_last guaranteed 133854359Sroberto ;# that no file is left out 133954359Sroberto ;# the only thing that could happen is: 134054359Sroberto ;# we guessed the starting point wrong 134154359Sroberto ;# compute a new guess from the first record found 134254359Sroberto ;# if this equals our last guess use data of first record 134354359Sroberto ;# otherwise try new guess 134454359Sroberto 134554359Sroberto if ($fpos[$[+1] eq $filekey[$[] && $loffset[$[] > $fpos[$[+2]) 134654359Sroberto { 134754359Sroberto local($noff); 134854359Sroberto $noff = $loffset[$[] - ($cnt - @loffset + 1) * $RecordSize; 134954359Sroberto $noff = 0 if $noff < 0; 135054359Sroberto 135154359Sroberto return (@fpos[$[,$[+1], ($noff == $fpos[$[+2]) ? $loffset[$[] : $noff); 135254359Sroberto } 135354359Sroberto return ($fpos[$[],$filekey[$[],$loffset[$[]); 135454359Sroberto } 135554359Sroberto elsif ($fpos[$[] eq 'end' || $fpos[$[] eq 'cnt') 135654359Sroberto { 135754359Sroberto ;# try to start earlier in file 135854359Sroberto ;# if we already started at the beginning 135954359Sroberto ;# try to use previous file 136054359Sroberto ;# this assumes distance to better starting point is at most one file 136154359Sroberto ;# the primary guess at top of genfile() should usually allow this 136254359Sroberto ;# assumption 136354359Sroberto ;# if the offset of the first sample used is within 136454359Sroberto ;# a different file than we guessed it must have occurred later 136554359Sroberto ;# in the sequence of files 136654359Sroberto ;# this only can happen if our starting file did not contain 136754359Sroberto ;# a valid sample from the starting point we guessed 136854359Sroberto ;# however this does not invalidate our assumption, no check needed 136954359Sroberto local($noff,$key); 137054359Sroberto if ($fpos[$[+2] > 0) 137154359Sroberto { 137254359Sroberto $noff = $fpos[$[+2] - $RecordSize * ($cnt - @loffset + 1); 137354359Sroberto $noff = 0 if $noff < 0; 137454359Sroberto return (@fpos[$[,$[+1],$noff); 137554359Sroberto } 137654359Sroberto else 137754359Sroberto { 137854359Sroberto if ($fpos[$[+1] eq $F_files[$[]) 137954359Sroberto { 138054359Sroberto ;# first file - and not enough samples 138154359Sroberto ;# use data of first sample 138254359Sroberto return ($fpos[$[], $filekey[$[], $loffset[$[]); 138354359Sroberto } 138454359Sroberto else 138554359Sroberto { 138654359Sroberto ;# search key of previous file 138754359Sroberto $key = $F_files[$[]; 138854359Sroberto @F = reverse(@F_files); 138954359Sroberto while ($_ = shift(@F)) 139054359Sroberto { 139154359Sroberto if ($_ eq $fpos[$[+1]) 139254359Sroberto { 139354359Sroberto $key = shift(@F) if @F; 139454359Sroberto last; 139554359Sroberto } 139654359Sroberto } 139754359Sroberto $noff = int($F_size{$key} / $RecordSize); 139854359Sroberto $noff -= $cnt - @loffset; 139954359Sroberto $noff = 0 if $noff < 0; 140054359Sroberto $noff *= $RecordSize; 140154359Sroberto return ($fpos[$[], $key, $noff); 140254359Sroberto } 140354359Sroberto } 140454359Sroberto } 140554359Sroberto else 140654359Sroberto { 140754359Sroberto return (); 140854359Sroberto } 140954359Sroberto 141054359Sroberto return 0 if @loffset <= 1 || ($loffset[$#loffset] - $loffset[$[]) <= 1; 141154359Sroberto 141254359Sroberto ;# EOF - 1.1 * avg(line) * $cnt 141354359Sroberto local($val) = $loffset[$#loffset] 141454359Sroberto - $cnt * 11 * (($loffset[$#loffset] - $loffset[$[]) / @loffset) / 10; 141554359Sroberto return ($val < 0) ? 0 : $val; 141654359Sroberto } 141754359Sroberto} 141854359Sroberto 141954359Sroberto$Ltime = -1 if ! defined($Ltime); 142054359Sroberto$LastFreqBase = 0; 142154359Sroberto$LastFreqBaseString = "??"; 142254359Sroberto 142354359Sroberto;# initial setup of plot 142454359Srobertoprint "initialize plotting\n" if $verbose; 142554359Srobertoif (defined($PrintIt)) 142654359Sroberto{ 142754359Sroberto if ($PrintIt =~ m,/,) 142854359Sroberto { 142954359Sroberto print "Saving plot to file $PrintIt\n"; 143054359Sroberto print PLOT "set output '$PrintIt'\n"; 143154359Sroberto } 143254359Sroberto else 143354359Sroberto { 143454359Sroberto print "Printing plot on printer $PrintIt\n"; 143554359Sroberto print PLOT "set output '| lpr -P$PrintIt -h'\n"; 143654359Sroberto } 143754359Sroberto print PLOT "set terminal postscript landscape color solid 'Helvetica' 10\n"; 143854359Sroberto} 143954359Srobertoprint PLOT "set grid\n"; 144054359Srobertoprint PLOT "set tics out\n"; 144154359Srobertoprint PLOT "set format y '%g '\n"; 144254359Srobertoprintf PLOT "set time 47\n" unless defined($PrintIt); 144354359Sroberto 144454359Sroberto@filepos =(); 144554359Srobertowhile(1) 144654359Sroberto{ 144754359Sroberto print &ctime(time) if $verbose; 144854359Sroberto 144954359Sroberto ;# update diplay characteristics 145054359Sroberto &read_config;# unless defined($PrintIt); 145154359Sroberto 145254359Sroberto unlink($tmpfile); 1453182007Sroberto my $lo = lr->new(); 1454182007Sroberto my $lf = lr->new(); 1455182007Sroberto 1456182007Sroberto @filepos = &genfile($samples,$srcprefix,$tmpfile,$lo,$lf,@filepos); 145754359Sroberto 145854359Sroberto ;# make plotcmd display samples 1459182007Sroberto make_doplot($lo, $lf); 146054359Sroberto print "Displaying plot...\n" if $verbose > 1; 146154359Sroberto print "command for plot sub process:\n$doplot----\n" if $verbose > 3; 146254359Sroberto print PLOT $doplot; 146354359Sroberto} 146454359Srobertocontinue 146554359Sroberto{ 146654359Sroberto if (defined($PrintIt)) 146754359Sroberto { 146854359Sroberto delete $SIG{'CHLD'}; 146954359Sroberto print PLOT "quit\n"; 147054359Sroberto close(PLOT); 147154359Sroberto if ($PrintIt =~ m,/,) 147254359Sroberto { 147354359Sroberto print "Plot saved to file $PrintIt\n"; 147454359Sroberto } 147554359Sroberto else 147654359Sroberto { 147754359Sroberto print "Plot spooled to printer $PrintIt\n"; 147854359Sroberto } 147954359Sroberto unlink($tmpfile); 148054359Sroberto exit(0); 148154359Sroberto } 148254359Sroberto ;# wait $delay seconds 148354359Sroberto print "waiting $delay seconds ..." if $verbose > 2; 148454359Sroberto sleep($delay); 148554359Sroberto print " continuing\n" if $verbose > 2; 148654359Sroberto undef($LastFreqBaseString); 148754359Sroberto} 148854359Sroberto 148954359Sroberto 149054359Srobertosub date_time_spec2seconds 149154359Sroberto{ 149254359Sroberto local($_) = @_; 149354359Sroberto ;# a date_time_spec consistes of: 149454359Sroberto ;# YYYY-MM-DD_HH:MM:SS.ms 149554359Sroberto ;# values can be omitted from the beginning and default than to 149654359Sroberto ;# values of current date 149754359Sroberto ;# values omitted from the end default to lowest possible values 149854359Sroberto 149954359Sroberto local($time) = time; 150054359Sroberto local($sec,$min,$hour,$mday,$mon,$year) 150154359Sroberto = localtime($time); 150254359Sroberto 150354359Sroberto local($last) = (); 150454359Sroberto 150554359Sroberto s/^\D*(.*\d)\D*/$1/; # strip off garbage 150654359Sroberto 150754359Sroberto PARSE: 150854359Sroberto { 150954359Sroberto if (s/^(\d{4})(-|$)//) 151054359Sroberto { 151154359Sroberto if ($1 < 1970) 151254359Sroberto { 151354359Sroberto warn("$0: can not handle years before 1970 - year $1 ignored\n"); 151454359Sroberto return undef; 151554359Sroberto } 151654359Sroberto elsif ( $1 >= 2070) 151754359Sroberto { 151854359Sroberto warn("$0: can not handle years past 2070 - year $1 ignored\n"); 151954359Sroberto return undef; 152054359Sroberto } 152154359Sroberto else 152254359Sroberto { 152354359Sroberto $year = $1 % 100; # 0<= $year < 100 152454359Sroberto ;# - interpreted 70 .. 99,00 .. 69 152554359Sroberto } 152654359Sroberto $last = $[ + 5; 152754359Sroberto last PARSE if $_ eq ''; 152854359Sroberto warn("$0: bad date_time_spec: \"$_\" found after YEAR\n"), 152954359Sroberto return(undef) 153054359Sroberto if $2 eq ''; 153154359Sroberto } 153254359Sroberto 153354359Sroberto if (s/^(\d{1,2})(-|$)//) 153454359Sroberto { 153554359Sroberto warn("$0: implausible month $1\n"),return(undef) 153654359Sroberto if $1 < 1 || $1 > 12; 153754359Sroberto $mon = $1 - 1; 153854359Sroberto $last = $[ + 4; 153954359Sroberto last PARSE if $_ eq ''; 154054359Sroberto warn("$0: bad date_time_spec: \"$_\" found after MONTH\n"), 154154359Sroberto return(undef) 154254359Sroberto if $2 eq ''; 154354359Sroberto } 154454359Sroberto else 154554359Sroberto { 154654359Sroberto warn("$0: bad date_time_spec \"$_\"\n"),return(undef) 154754359Sroberto if defined($last); 154854359Sroberto 154954359Sroberto } 155054359Sroberto 155154359Sroberto if (s/^(\d{1,2})([_ ]|$)//) 155254359Sroberto { 155354359Sroberto warn("$0: implausible month day $1 for month ".($mon+1)." (". 155454359Sroberto $MaxNumDaysPerMonth[$mon].")$mon\n"), 155554359Sroberto return(undef) 155654359Sroberto if $1 < 1 || $1 > $MaxNumDaysPerMonth[$mon]; 155754359Sroberto $mday = $1; 155854359Sroberto $last = $[ + 3; 155954359Sroberto last PARSE if $_ eq ''; 156054359Sroberto warn("$0: bad date_time_spec \"$_\" found after MDAY\n"), 156154359Sroberto return(undef) 156254359Sroberto if $2 eq ''; 156354359Sroberto } 156454359Sroberto else 156554359Sroberto { 156654359Sroberto warn("$0: bad date_time_spec \"$_\"\n"), return undef 156754359Sroberto if defined($last); 156854359Sroberto } 156954359Sroberto 157054359Sroberto ;# now we face a problem: 157154359Sroberto ;# if ! defined($last) a prefix of "07:" 157254359Sroberto ;# can be either 07:MM or 07:ss 157354359Sroberto ;# to get the second interpretation make the user add 157454359Sroberto ;# a msec fraction part and check for this special case 157554359Sroberto if (! defined($last) && s/^(\d{1,2}):(\d{1,2}\.\d+)//) 157654359Sroberto { 157754359Sroberto warn("$0: implausible minute $1\n"), return undef 157854359Sroberto if $1 < 0 || $1 >= 60; 157954359Sroberto warn("$0: implausible second $1\n"), return undef 158054359Sroberto if $2 < 0 || $2 >= 60; 158154359Sroberto $min = $1; 158254359Sroberto $sec = $2; 158354359Sroberto $last = $[ + 1; 158454359Sroberto last PARSE if $_ eq ''; 158554359Sroberto warn("$0: bad date_time_spec \"$_\" after SECONDS\n"); 158654359Sroberto return undef; 158754359Sroberto } 158854359Sroberto 158954359Sroberto if (s/^(\d{1,2})(:|$)//) 159054359Sroberto { 159154359Sroberto warn("$0: implausible hour $1\n"), return undef 159254359Sroberto if $1 < 0 || $1 > 24; 159354359Sroberto $hour = $1; 159454359Sroberto $last = $[ + 2; 159554359Sroberto last PARSE if $_ eq ''; 159654359Sroberto warn("$0: bad date_time_spec found \"$_\" after HOUR\n"), 159754359Sroberto return undef 159854359Sroberto if $2 eq ''; 159954359Sroberto } 160054359Sroberto else 160154359Sroberto { 160254359Sroberto warn("$0: bad date_time_spec \"$_\"\n"), return undef 160354359Sroberto if defined($last); 160454359Sroberto } 160554359Sroberto 160654359Sroberto if (s/^(\d{1,2})(:|$)//) 160754359Sroberto { 160854359Sroberto warn("$0: implausible minute $1\n"), return undef 160954359Sroberto if $1 < 0 || $1 >=60; 161054359Sroberto $min = $1; 161154359Sroberto $last = $[ + 1; 161254359Sroberto last PARSE if $_ eq ''; 161354359Sroberto warn("$0: bad date_time_spec found \"$_\" after MINUTE\n"), 161454359Sroberto return undef 161554359Sroberto if $2 eq ''; 161654359Sroberto } 161754359Sroberto else 161854359Sroberto { 161954359Sroberto warn("$0: bad date_time_spec \"$_\"\n"), return undef 162054359Sroberto if defined($last); 162154359Sroberto } 162254359Sroberto 162354359Sroberto if (s/^(\d{1,2}(\.\d+)?)//) 162454359Sroberto { 162554359Sroberto warn("$0: implausible second $1\n"), return undef 162654359Sroberto if $1 < 0 || $1 >=60; 162754359Sroberto $sec = $1; 162854359Sroberto $last = $[; 162954359Sroberto last PARSE if $_ eq ''; 163054359Sroberto warn("$0: bad date_time_spec found \"$_\" after SECOND\n"); 163154359Sroberto return undef; 163254359Sroberto } 163354359Sroberto } 163454359Sroberto 163554359Sroberto return $time unless defined($last); 163654359Sroberto 163754359Sroberto $sec = 0 if $last > $[; 163854359Sroberto $min = 0 if $last > $[ + 1; 163954359Sroberto $hour = 0 if $last > $[ + 2; 164054359Sroberto $mday = 1 if $last > $[ + 3; 164154359Sroberto $mon = 0 if $last > $[ + 4; 164254359Sroberto local($rtime) = &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 0); 164354359Sroberto 164454359Sroberto ;# $rtime may be off if daylight savings time is in effect at given date 164554359Sroberto return $rtime + ($sec - int($sec)) 164654359Sroberto if $hour == (localtime($rtime))[$[+2]; 164754359Sroberto return 164854359Sroberto &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 1) 164954359Sroberto + ($sec - int($sec)); 165054359Sroberto} 165154359Sroberto 165254359Sroberto 165354359Srobertosub min 165454359Sroberto{ 165554359Sroberto local($m) = shift; 165654359Sroberto 165754359Sroberto grep((($m > $_) && ($m = $_),0),@_); 165854359Sroberto $m; 165954359Sroberto} 166054359Sroberto 166154359Srobertosub max 166254359Sroberto{ 166354359Sroberto local($m) = shift; 166454359Sroberto 166554359Sroberto grep((($m < $_) && ($m = $_),0),@_); 166654359Sroberto $m; 166754359Sroberto} 1668