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