scriptroute 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/sr-ally +21 -0
- data/bin/sr-liveness +11 -0
- data/bin/sr-ping-T +69 -0
- data/bin/sr-rockettrace +51 -0
- data/bin/sr-traceroute +35 -0
- data/bin/tulip +183 -0
- data/lib/scriptroute.rb +327 -0
- data/lib/scriptroute/ally.rb +449 -0
- data/lib/scriptroute/commando.rb +228 -0
- data/lib/scriptroute/fixclock +1260 -0
- data/lib/scriptroute/liveness.rb +129 -0
- data/lib/scriptroute/nameify.rb +127 -0
- data/lib/scriptroute/packets.rb +800 -0
- data/lib/scriptroute/rockettrace.rb +181 -0
- data/lib/scriptroute/tulip/helper.rb +730 -0
- data/lib/scriptroute/tulip/loss.rb +145 -0
- data/lib/scriptroute/tulip/queuing.rb +248 -0
- data/lib/scriptroute/tulip/reordering.rb +129 -0
- data/test/test_bins.rb +20 -0
- data/test/test_scriptroute.rb +155 -0
- metadata +71 -0
@@ -0,0 +1,1260 @@
|
|
1
|
+
#!/usr/bin/awk -f
|
2
|
+
|
3
|
+
# "FIXCLOCK" COPYRIGHT NOTICE, LICENSE AND DISCLAIMER.
|
4
|
+
#
|
5
|
+
# Copyright 2002 by Raphael S. Ryger, Dept. of Computer Science, Yale University
|
6
|
+
#
|
7
|
+
# Permission to use, copy, modify, and distribute this software and its
|
8
|
+
# documentation for any purpose and without fee is hereby granted, provided
|
9
|
+
# that the above copyright notice appear in all copies and that both the
|
10
|
+
# copyright notice and this permission notice and warranty disclaimer appear
|
11
|
+
# in supporting documentation, and that the name of the author not be used
|
12
|
+
# in advertising or publicity pertaining to distribution of the software
|
13
|
+
# without specific, written prior permission.
|
14
|
+
#
|
15
|
+
# The author disclaims all warranties with regard to this software, including
|
16
|
+
# all implied warranties of merchantability and fitness. In no event shall he
|
17
|
+
# be liable for any special, indirect or consequential damages or any damages
|
18
|
+
# whatsoever resulting from loss of use, data or profits, whether in an action
|
19
|
+
# of contract, negligence or other tortious action, arising out of or in
|
20
|
+
# connection with the use or performance of this software.
|
21
|
+
|
22
|
+
# Usage: fixclock <datafile>
|
23
|
+
#
|
24
|
+
# The behavior of this script is modulated by parameters derived from the
|
25
|
+
# command line, else from the environment, else from the defaults following.
|
26
|
+
# (In sh and ksh, environment variable settings may be prepended in the command
|
27
|
+
# line to the invocation of the script, to apply only to that invocation.)
|
28
|
+
# parameter default
|
29
|
+
# --------- -------
|
30
|
+
# parsing group:
|
31
|
+
# datalinepattern null (effectively, all lines)
|
32
|
+
# pastdatapattern null (effectively, no such line)
|
33
|
+
# fieldseparator null (effectively, whitespace)
|
34
|
+
# hostfieldnum null (effectively, all data lines)
|
35
|
+
# sentfieldnum *must* be specified
|
36
|
+
# receivedfieldnum *must* be specified
|
37
|
+
# bouncedfieldnum *must* be specified
|
38
|
+
# target extracted from (the string) <datafile>
|
39
|
+
#
|
40
|
+
# tuning group:
|
41
|
+
# segmentsecs 12
|
42
|
+
# intrastretchmaxerr 2
|
43
|
+
# interstretchmaxerr 10
|
44
|
+
# sourceskew 0
|
45
|
+
#
|
46
|
+
# verbosity group (binary values: null or 0 is false; else true):
|
47
|
+
# showall null
|
48
|
+
# showtarget null
|
49
|
+
# showreadings null
|
50
|
+
# showminima null
|
51
|
+
# showintrastretchtests null
|
52
|
+
# showonewaystretches null
|
53
|
+
# showstdroundtrips null
|
54
|
+
# showquality null
|
55
|
+
# showcompositestretches null
|
56
|
+
# showregions null
|
57
|
+
# showcoverage null
|
58
|
+
#
|
59
|
+
# data file side effects:
|
60
|
+
# writefixeddir null
|
61
|
+
# writeorigfixedplotdir null
|
62
|
+
#
|
63
|
+
# Notes on parameters:
|
64
|
+
# datalinepattern AWK pattern picking out the data lines. The data lines
|
65
|
+
# need not be successive.
|
66
|
+
# pastdatapattern AWK pattern recognizing a line which is past the relevent
|
67
|
+
# data, upon which the script may wind up and exit. (This
|
68
|
+
# pattern will only be consulted if a line does not match
|
69
|
+
# datalinepattern.)
|
70
|
+
# target Any IP address for which there are readings in the file
|
71
|
+
# may have its timing data analyzed and revised, not only the
|
72
|
+
# nominal "target" of the data.
|
73
|
+
# segmentsecs Segments should be long enough to make it likely (not
|
74
|
+
# necessarily definite) that segment minima for one-way (not
|
75
|
+
# necessarily round-trip) transit times are the ideal,
|
76
|
+
# congestion-less, times;
|
77
|
+
# but, on the other hand, short enough to allow four consecutive
|
78
|
+
# jump-less segments, in absence of congestion, even for target
|
79
|
+
# clocks that are reset by jumps on a very frequent schedule.
|
80
|
+
# The default, 12 seconds, allows for jump resets as frequent
|
81
|
+
# as once per minute.
|
82
|
+
# intrastretchmaxerr The maximum absolute millisecond difference between an
|
83
|
+
# actual segment minimum one-way transit time and a linearly
|
84
|
+
# interpolated transit time for that timepoint, in a stretch of
|
85
|
+
# segments to be considered adjustment-less.
|
86
|
+
# interstretchmaxerr The maximum absolute millisecond difference between an
|
87
|
+
# actual segment minimum one-way transit time and a linearly
|
88
|
+
# interpolated transit time for that timepoint, in considering
|
89
|
+
# a pair of "adjustment-less" stretches for coalescing.
|
90
|
+
# sourceskew A guess at the skew of the source machine's clock with respect
|
91
|
+
# to standard time. If the guess is good, considerations of
|
92
|
+
# the sign of apparent target skew can become meaningful after
|
93
|
+
# compensation for the guessed source skew. But we avoid them
|
94
|
+
# anyway! We do innocuously do the compensation.
|
95
|
+
# showall Turns on all the following "show" parameters, displaying all
|
96
|
+
# available information -- unless explicitly overridden for
|
97
|
+
# individual "show" parameters by setting them to 0.
|
98
|
+
# showtarget Shows the target IP address at the top of the output.
|
99
|
+
# showreadings Displays preliminarily-normalized data data for the target:
|
100
|
+
# "there" time, "back" time, round-trip time.
|
101
|
+
# showminima Displays the segment minima of the transit times, as well as
|
102
|
+
# the global minima of these times.
|
103
|
+
# showintrastretchtests Displays the skews and errors involved in the
|
104
|
+
# collinearity tests for adding segments to stretches.
|
105
|
+
# showonewaystretches Displays the jump-less stretches, with their skews,
|
106
|
+
# for each direction, as determined without regard to the other
|
107
|
+
# direction.
|
108
|
+
# showstdroundtrips Displays the data and conclusions for the individual
|
109
|
+
# local inferences of "standard round-trip time". (The average
|
110
|
+
# is what we finally use.)
|
111
|
+
# showquality Displays the ratio of the inferred "standard" round-trip
|
112
|
+
# time to the measured global minimum round-trip time. This
|
113
|
+
# is around 1.0 with "good" data, and drops with persistent
|
114
|
+
# congestion and, especially, clock craziness.
|
115
|
+
# showcompositestretches Displays the final stretch information, after the
|
116
|
+
# one-way stretch information from the two directions has been
|
117
|
+
# synthesized into a single coherent picture.
|
118
|
+
# showregions Displays the final map that will drive the correction pass.
|
119
|
+
# The segment artifice is gone. Regions are defined by source
|
120
|
+
# "sent" timestamps.
|
121
|
+
# showcoverage Displays the total time coverage of the identified regions,
|
122
|
+
# hence of the fixed data (if requested), relative to the
|
123
|
+
# duration of the probing run.
|
124
|
+
# writefixeddir The value is taken as the name of the directory to which to
|
125
|
+
# write the fixed file as <datafile>.fix, and the rejected
|
126
|
+
# (unfixable) record file as <datafile>.rej .
|
127
|
+
# (A command-line setting of "//" may be used to override an
|
128
|
+
# environment setting and will be interpreted as null.)
|
129
|
+
# writeorigfixedplotdir The value is taken as the name of the directory
|
130
|
+
# to which to write three space-delimited data files -- one
|
131
|
+
# isolating the (relevant target) triples of the original
|
132
|
+
# data file, another containing the fixed triples, and a
|
133
|
+
# third containing the rejected triples, those that could not
|
134
|
+
# be fixed -- named, respectively, <datafile>.plot,
|
135
|
+
# <datafile>.fix.plot, and <datafile>.rej.plot . The shifting
|
136
|
+
# and scaling of the data in these .plot files is chosen for
|
137
|
+
# effectiveness of resulting graphs, and for compatibility
|
138
|
+
# with the analytical text output.
|
139
|
+
# (A command-line setting of "//" may be used to override an
|
140
|
+
# environment setting and will be interpreted as null.)
|
141
|
+
|
142
|
+
# Assumptions in the analysis:
|
143
|
+
# - There is no change in the routing to the target, or in the networking
|
144
|
+
# infrastructure along the path, during the course of the data.
|
145
|
+
# - *Regular* clock jumps do not happen more frequently than once per
|
146
|
+
# 5 * segmentsecs.
|
147
|
+
# - Congestion-free one-way transits occur often, so that maximal runs of
|
148
|
+
# at least 4 consecutive segments with congestion-free transit times in
|
149
|
+
# the same direction bracket most of each adjustment-free portion of the
|
150
|
+
# data.
|
151
|
+
# - There is at least one overlap of stretches of collinear-min-OTT
|
152
|
+
# segments for the two directions;
|
153
|
+
# else, there is at least one (reasonably) congestion-free round trip
|
154
|
+
# in the data.
|
155
|
+
# Adjustments by high-absolute-value temporary skew require low congestion as
|
156
|
+
# they occur for proper analysis by the present method.
|
157
|
+
|
158
|
+
function setparameters( default) {
|
159
|
+
# default["datalinepattern"] = null
|
160
|
+
# default["pastdatapattern"] = null
|
161
|
+
# default["fieldseparator"] = null
|
162
|
+
# default["hostfieldnum"] = null
|
163
|
+
# default["sentfieldnum"] = *must* be specified
|
164
|
+
# default["receivedfieldnum"] = *must* be specified
|
165
|
+
# default["bouncedfieldnum"] = *must* be specified
|
166
|
+
# default["target"] = targetfromfilename()
|
167
|
+
default["segmentsecs"] = 12
|
168
|
+
default["intrastretchmaxerr"] = 2
|
169
|
+
default["interstretchmaxerr"] = 10
|
170
|
+
default["sourceskew"] = 0
|
171
|
+
# default["showall"] = null
|
172
|
+
# default["showtarget"] = null
|
173
|
+
# default["showreadings"] = null
|
174
|
+
# default["showminima"] = null
|
175
|
+
# default["showintrastretchtests"] = null
|
176
|
+
# default["showonewaystretches"] = null
|
177
|
+
# default["showstdroundtrips"] = null
|
178
|
+
# default["showstdquality"] = null
|
179
|
+
# default["showcompositestretches"] = null
|
180
|
+
# default["showregions"] = null
|
181
|
+
# default["showcoverage"] = null
|
182
|
+
# default["writefixeddir"] = null
|
183
|
+
# default["writeorigfixedplotdir"] = null
|
184
|
+
|
185
|
+
(datalinepattern != "") \
|
186
|
+
|| datalinepattern = ENVIRON["datalinepattern"]
|
187
|
+
(pastdatapattern != "") \
|
188
|
+
|| pastdatapattern = ENVIRON["pastdatapattern"]
|
189
|
+
(fieldseparator != "") \
|
190
|
+
|| fieldseparator = ENVIRON["fieldseparator"]
|
191
|
+
(hostfieldnum != "") \
|
192
|
+
|| hostfieldnum = ENVIRON["hostfieldnum"]
|
193
|
+
(sentfieldnum != "") \
|
194
|
+
|| sentfieldnum = ENVIRON["sentfieldnum"]
|
195
|
+
(receivedfieldnum != "") \
|
196
|
+
|| receivedfieldnum = ENVIRON["receivedfieldnum"]
|
197
|
+
(bouncedfieldnum != "") \
|
198
|
+
|| bouncedfieldnum = ENVIRON["bouncedfieldnum"]
|
199
|
+
(target != "") \
|
200
|
+
|| target = ENVIRON["target"]
|
201
|
+
(segmentsecs != "") \
|
202
|
+
|| ((segmentsecs = ENVIRON["segmentsecs"]) != "") \
|
203
|
+
|| segmentsecs = default["segmentsecs"]
|
204
|
+
(intrastretchmaxerr != "") \
|
205
|
+
|| ((intrastretchmaxerr = ENVIRON["intrastretchmaxerr"]) != "") \
|
206
|
+
|| intrastretchmaxerr = default["intrastretchmaxerr"]
|
207
|
+
(interstretchmaxerr != "") \
|
208
|
+
|| ((interstretchmaxerr = ENVIRON["interstretchmaxerr"]) != "") \
|
209
|
+
|| interstretchmaxerr = default["interstretchmaxerr"]
|
210
|
+
(sourceskew != "") \
|
211
|
+
|| ((sourceskew = ENVIRON["sourceskew"]) != "") \
|
212
|
+
|| sourceskew = default["sourceskew"]
|
213
|
+
(showall != "") \
|
214
|
+
|| showall = ENVIRON["showall"]
|
215
|
+
(showtarget != "") \
|
216
|
+
|| ((showtarget = ENVIRON["showtarget"]) != "") \
|
217
|
+
|| showtarget = showall
|
218
|
+
(showreadings != "") \
|
219
|
+
|| ((showreadings = ENVIRON["showreadings"]) != "") \
|
220
|
+
|| showreadings = showall
|
221
|
+
(showminima != "") \
|
222
|
+
|| ((showminima = ENVIRON["showminima"]) != "") \
|
223
|
+
|| showminima = showall
|
224
|
+
(showintrastretchtests != "") \
|
225
|
+
|| ((showintrastretchtests = ENVIRON["showintrastretchtests"]) \
|
226
|
+
!= "") \
|
227
|
+
|| showintrastretchtests = showall
|
228
|
+
(showonewaystretches != "") \
|
229
|
+
|| ((showonewaystretches = ENVIRON["showonewaystretches"]) \
|
230
|
+
!= "") \
|
231
|
+
|| showonewaystretches = showall
|
232
|
+
(showstdroundtrips != "") \
|
233
|
+
|| ((showstdroundtrips = ENVIRON["showstdroundtrips"]) \
|
234
|
+
!= "") \
|
235
|
+
|| showstdroundtrips = showall
|
236
|
+
(showquality != "") \
|
237
|
+
|| ((showquality = ENVIRON["showquality"]) \
|
238
|
+
!= "") \
|
239
|
+
|| ((showstdroundtrips || showcompositestretches) &&
|
240
|
+
showquality = 1) \
|
241
|
+
|| showquality = showall
|
242
|
+
(showcompositestretches != "") \
|
243
|
+
|| ((showcompositestretches = ENVIRON["showcompositestretches"]) \
|
244
|
+
!= "") \
|
245
|
+
|| showcompositestretches = showall
|
246
|
+
(showregions != "") \
|
247
|
+
|| ((showregions = ENVIRON["showregions"]) != "") \
|
248
|
+
|| showregions = showall
|
249
|
+
(showcoverage != "") \
|
250
|
+
|| ((showcoverage = ENVIRON["showcoverage"]) != "") \
|
251
|
+
|| showcoverage = showall
|
252
|
+
(writefixeddir != "" && writefixeddir != "//") \
|
253
|
+
|| writefixeddir = ENVIRON["writefixeddir"]
|
254
|
+
(writeorigfixedplotdir != "" && writeorigfixedplotdir != "//") \
|
255
|
+
|| writeorigfixedplotdir = ENVIRON["writeorigfixedplotdir"]
|
256
|
+
}
|
257
|
+
|
258
|
+
function targetfromfilename( fromfilename) {
|
259
|
+
fromfilename = FILENAME
|
260
|
+
sub(/^.*\//, "", fromfilename)
|
261
|
+
sub(/^[^0-9.]*/, "", fromfilename)
|
262
|
+
sub(/[^0-9.].*/, "", fromfilename)
|
263
|
+
sub(/^\./, "", fromfilename)
|
264
|
+
sub(/\.$/, "", fromfilename)
|
265
|
+
return fromfilename
|
266
|
+
}
|
267
|
+
|
268
|
+
function abs(number) {
|
269
|
+
return (number < 0) ? -number : number
|
270
|
+
}
|
271
|
+
|
272
|
+
function fixbyteorder (integer, revinteger, byte, ii) {
|
273
|
+
if (!needs_bytes_reversed) return integer
|
274
|
+
revinteger = 0
|
275
|
+
for (ii = 0; ii < 4; ++ii) {
|
276
|
+
byte = integer % 256
|
277
|
+
revinteger = revinteger*256 + byte
|
278
|
+
integer = (integer - byte) / 256
|
279
|
+
}
|
280
|
+
return revinteger
|
281
|
+
}
|
282
|
+
|
283
|
+
# Note: the variable tb holds the "there or back" direction code:
|
284
|
+
# 0 is "there" (outbound), 1 is "back" (inbound).
|
285
|
+
|
286
|
+
function segmentboundary() {
|
287
|
+
if (showminima)
|
288
|
+
print "Segment", segments \
|
289
|
+
": minthere", min[0,segments] \
|
290
|
+
"; minback", min[1,segments] \
|
291
|
+
"; minroundtrip, fictive",
|
292
|
+
(min[0,segments] + min[1,segments]) \
|
293
|
+
", actual", min[2,segments]
|
294
|
+
if (min[0,segments] < globalminthere)
|
295
|
+
globalminthere = min[0,segments]
|
296
|
+
if (min[1,segments] < globalminback)
|
297
|
+
globalminback = min[1,segments]
|
298
|
+
if (min[2,segments] < globalminroundtrip)
|
299
|
+
globalminroundtrip = min[2,segments]
|
300
|
+
|
301
|
+
# For each of the "there" and "back" directions, examine the
|
302
|
+
# collinearity of the following four points:
|
303
|
+
# the respective minimum of the respective candidate/extended
|
304
|
+
# stretch's startseg;
|
305
|
+
# the respective minimum of the mid-stretch segment;
|
306
|
+
# the respective minimum of the immediate predecessor of the
|
307
|
+
# present (old) segment; and
|
308
|
+
# the respective minimum of the present (old) segment.
|
309
|
+
# Note that in testing the first foursome for a (potential) stretch,
|
310
|
+
# it could be that the first two and last two minima immediately
|
311
|
+
# straddle segment boundaries, in which case this instance of the
|
312
|
+
# test establishes almost nothing; but if so, the minima collinearity
|
313
|
+
# test for the next segment minimum will be all the more stringent.
|
314
|
+
for (tb = 0; tb < 2; ++tb) {
|
315
|
+
if (segments - this_stretch_startseg[tb] < 3) continue
|
316
|
+
seg1 = this_stretch_startseg[tb]
|
317
|
+
seg2 = int((seg1 + segments) / 2)
|
318
|
+
seg3 = segments - 1
|
319
|
+
# for "there", we use the "sent" timestamps;
|
320
|
+
# for "back", we use the "bounced" timestamps;
|
321
|
+
if (tb == 0) {
|
322
|
+
if (min[tb,segments] > min[tb,seg1]) {
|
323
|
+
use_sent1 = min_sent_late[tb,seg1]
|
324
|
+
use_sent2 = min_sent_late[tb,seg2]
|
325
|
+
use_sent3 = min_sent_late[tb,seg3]
|
326
|
+
use_sent = min_sent_late[tb,segments]
|
327
|
+
}
|
328
|
+
else {
|
329
|
+
use_sent1 = min_sent[tb,seg1]
|
330
|
+
use_sent2 = min_sent[tb,seg2]
|
331
|
+
use_sent3 = min_sent[tb,seg3]
|
332
|
+
use_sent = min_sent[tb,segments]
|
333
|
+
}
|
334
|
+
min2shouldbe = ((use_sent - use_sent2) * min[tb,seg1] + \
|
335
|
+
(use_sent2 - use_sent1) * min[tb,segments]) / \
|
336
|
+
(use_sent - use_sent1)
|
337
|
+
min3shouldbe = ((use_sent - use_sent3) * min[tb,seg1] + \
|
338
|
+
(use_sent3 - use_sent1) * min[tb,segments]) / \
|
339
|
+
(use_sent - use_sent1)
|
340
|
+
this_skew = (min[tb,segments] - min[tb,seg1]) / \
|
341
|
+
(use_sent - use_sent1)
|
342
|
+
}
|
343
|
+
else {
|
344
|
+
if (min[tb,segments] > min[tb,seg1]) {
|
345
|
+
use_bounced1 = min_bounced_late[tb,seg1]
|
346
|
+
use_bounced2 = min_bounced_late[tb,seg2]
|
347
|
+
use_bounced3 = min_bounced_late[tb,seg3]
|
348
|
+
use_bounced = min_bounced_late[tb,segments]
|
349
|
+
}
|
350
|
+
else {
|
351
|
+
use_bounced1 = min_bounced[tb,seg1]
|
352
|
+
use_bounced2 = min_bounced[tb,seg2]
|
353
|
+
use_bounced3 = min_bounced[tb,seg3]
|
354
|
+
use_bounced = min_bounced[tb,segments]
|
355
|
+
}
|
356
|
+
min2shouldbe = \
|
357
|
+
((use_bounced - use_bounced2) * min[tb,seg1] + \
|
358
|
+
(use_bounced2 - use_bounced1) * min[tb,segments]) / \
|
359
|
+
(use_bounced - use_bounced1)
|
360
|
+
min3shouldbe = \
|
361
|
+
((use_bounced - use_bounced3) * min[tb,seg1] + \
|
362
|
+
(use_bounced3 - use_bounced1) * min[tb,segments]) / \
|
363
|
+
(use_bounced - use_bounced1)
|
364
|
+
this_skew = (min[tb,segments] - min[tb,seg1]) / \
|
365
|
+
(use_bounced - use_bounced1)
|
366
|
+
}
|
367
|
+
min2error = min[tb,seg2] - min2shouldbe
|
368
|
+
min3error = min[tb,seg3] - min3shouldbe
|
369
|
+
if (showintrastretchtests) {
|
370
|
+
print " segment", seg2, "min" thereback[tb], "off by",
|
371
|
+
min2error ",",
|
372
|
+
"segment", seg3, "min" thereback[tb], "off by",
|
373
|
+
min3error
|
374
|
+
print " " thereback[tb], "skew from segment", seg1 ": ",
|
375
|
+
this_skew
|
376
|
+
}
|
377
|
+
# act on the collinearity test results
|
378
|
+
if (abs(min2error) <= intrastretchmaxerr &&
|
379
|
+
abs(min3error) <= intrastretchmaxerr) {
|
380
|
+
# collinearity test good
|
381
|
+
if (in_stretch[tb]) {
|
382
|
+
# extend existing (confirmed) stretch with present
|
383
|
+
# (old) segment
|
384
|
+
stretch_index[tb,segments] = stretches[tb]
|
385
|
+
stretch_endseg[tb,stretches[tb]] = segments
|
386
|
+
}
|
387
|
+
else {
|
388
|
+
# confirm candidate stretch
|
389
|
+
in_stretch[tb] = 1
|
390
|
+
++stretches[tb]
|
391
|
+
stretch_index[tb,segments-3] = \
|
392
|
+
stretch_index[tb,segments-2] = \
|
393
|
+
stretch_index[tb,segments-1] = \
|
394
|
+
stretch_index[tb,segments] = stretches[tb]
|
395
|
+
stretch_startseg[tb,stretches[tb]] = segments - 3
|
396
|
+
stretch_endseg[tb,stretches[tb]] = segments
|
397
|
+
}
|
398
|
+
stretch_skew[tb,stretches[tb]] = this_skew
|
399
|
+
if (in_data == 2)
|
400
|
+
# no more readings: adjust choices of minimum times ...
|
401
|
+
if (min[tb,segments] > min[tb,seg1])
|
402
|
+
if (tb == 0)
|
403
|
+
for (ii = seg1; ii <= segments; ++ii)
|
404
|
+
min_sent[tb,ii] = min_sent_late[tb,ii]
|
405
|
+
else
|
406
|
+
for (ii = seg1; ii <= segments; ++ii)
|
407
|
+
min_bounced[tb,ii] = min_bounced_late[tb,ii]
|
408
|
+
}
|
409
|
+
else {
|
410
|
+
# collinearity test bad
|
411
|
+
if (in_stretch[tb]) {
|
412
|
+
# existing (confirmed) stretch cannot be extended:
|
413
|
+
# adjust choices of minimum times ...
|
414
|
+
if (min[tb,segments] > min[tb,seg1])
|
415
|
+
if (tb == 0)
|
416
|
+
for (ii = seg1; ii <= segments - 1; ++ii)
|
417
|
+
min_sent[tb,ii] = min_sent_late[tb,ii]
|
418
|
+
else
|
419
|
+
for (ii = seg1; ii <= segments - 1; ++ii)
|
420
|
+
min_bounced[tb,ii] = min_bounced_late[tb,ii]
|
421
|
+
# ... and start a new candidate stretch
|
422
|
+
in_stretch[tb] = 0
|
423
|
+
this_stretch_startseg[tb] = segments
|
424
|
+
}
|
425
|
+
else
|
426
|
+
# shift candidate stretch start segment
|
427
|
+
++this_stretch_startseg[tb]
|
428
|
+
}
|
429
|
+
}
|
430
|
+
}
|
431
|
+
|
432
|
+
function compatiblecounterskews(there_skew, back_skew) {
|
433
|
+
# Test: is average of the two skews off from 0 no more than
|
434
|
+
# intrastretchmaxerr / (2 * segmentsec * 1000)
|
435
|
+
# In the collinearity tests we are essentially allowing for an error
|
436
|
+
# no greater than this in the individual skews, hence in their average.
|
437
|
+
return (abs(there_skew + back_skew) <= \
|
438
|
+
intrastretchmaxerr / (segmentsecs * 1000))
|
439
|
+
}
|
440
|
+
|
441
|
+
function continuation(first_tb, first_seg, second_tb, second_seg,
|
442
|
+
ii, x, y, zz) {
|
443
|
+
if (showcompositestretches)
|
444
|
+
print "continuation:", thereback[first_tb], "seg", first_seg ",",
|
445
|
+
thereback[second_tb], "seg", second_seg
|
446
|
+
first_stretch_startseg = \
|
447
|
+
stretch_startseg[first_tb,stretch_index[first_tb,first_seg]]
|
448
|
+
first_stretch_endseg = \
|
449
|
+
stretch_endseg[first_tb,stretch_index[first_tb,first_seg]]
|
450
|
+
second_stretch_startseg = \
|
451
|
+
stretch_startseg[second_tb,stretch_index[second_tb,second_seg]]
|
452
|
+
second_stretch_endseg = \
|
453
|
+
stretch_endseg[second_tb,stretch_index[second_tb,second_seg]]
|
454
|
+
if (first_tb == 0) {
|
455
|
+
x[1] = min_sent[0,first_stretch_startseg]
|
456
|
+
y[1] = min[0,first_stretch_startseg]
|
457
|
+
x[2] = min_sent[0,first_stretch_endseg]
|
458
|
+
y[2] = min[0,first_stretch_endseg]
|
459
|
+
}
|
460
|
+
else {
|
461
|
+
x[1] = min_bounced[1,first_stretch_startseg] - stdroundtrip
|
462
|
+
y[1] = stdroundtrip - min[1,first_stretch_startseg]
|
463
|
+
x[2] = min_bounced[1,first_stretch_endseg] - stdroundtrip
|
464
|
+
y[2] = stdroundtrip - min[1,first_stretch_endseg]
|
465
|
+
}
|
466
|
+
if (second_tb == 0) {
|
467
|
+
x[3] = min_sent[0,second_stretch_startseg]
|
468
|
+
y[3] = min[0,second_stretch_startseg]
|
469
|
+
x[4] = min_sent[0,second_stretch_endseg]
|
470
|
+
y[4] = min[0,second_stretch_endseg]
|
471
|
+
}
|
472
|
+
else {
|
473
|
+
x[3] = min_bounced[1,second_stretch_startseg] - stdroundtrip
|
474
|
+
y[3] = stdroundtrip - min[1,second_stretch_startseg]
|
475
|
+
x[4] = min_bounced[1,second_stretch_endseg] - stdroundtrip
|
476
|
+
y[4] = stdroundtrip - min[1,second_stretch_endseg]
|
477
|
+
}
|
478
|
+
if (showcompositestretches) {
|
479
|
+
print " y[1]", y[1], "y[2]", y[2], "y[3]", y[3], "y[4]", y[4]
|
480
|
+
print " x[1]", x[1], "x[2]", x[2], "x[3]", x[3], "x[4]", x[4]
|
481
|
+
}
|
482
|
+
|
483
|
+
# take the "x" extrema as endpoints
|
484
|
+
reordered = 0
|
485
|
+
for (ii = 1; ii <= 4; ++ii) {
|
486
|
+
if (x[ii] < x[1]) {
|
487
|
+
zz = x[1]; x[1] = x[ii]; x[ii] = zz
|
488
|
+
zz = y[1]; y[1] = y[ii]; y[ii] = zz
|
489
|
+
reordered = 1
|
490
|
+
}
|
491
|
+
if (x[ii] > x[4]) {
|
492
|
+
zz = x[4]; x[4] = x[ii]; x[ii] = zz
|
493
|
+
zz = y[4]; y[4] = y[ii]; y[ii] = zz
|
494
|
+
reordered = 1
|
495
|
+
}
|
496
|
+
}
|
497
|
+
if (showcompositestretches)
|
498
|
+
if (reordered) {
|
499
|
+
print " reordered ..."
|
500
|
+
print " y[1]", y[1], "y[2]", y[2], "y[3]", y[3], "y[4]", y[4]
|
501
|
+
print " x[1]", x[1], "x[2]", x[2], "x[3]", x[3], "x[4]", x[4]
|
502
|
+
}
|
503
|
+
min2shouldbe = ((x[4] - x[2]) * y[1] + (x[2] - x[1]) * y[4]) \
|
504
|
+
/ (x[4] - x[1])
|
505
|
+
min3shouldbe = ((x[4] - x[3]) * y[1] + (x[3] - x[1]) * y[4]) \
|
506
|
+
/ (x[4] - x[1])
|
507
|
+
min2error = y[2] - min2shouldbe
|
508
|
+
min3error = y[3] - min3shouldbe
|
509
|
+
if (showcompositestretches)
|
510
|
+
print " min2error", min2error, "min3error", min3error
|
511
|
+
|
512
|
+
return (abs(min2error) <= interstretchmaxerr && \
|
513
|
+
abs(min3error) <= interstretchmaxerr)
|
514
|
+
}
|
515
|
+
|
516
|
+
function inferstdroundtrip(seg) {
|
517
|
+
# We assume that segment seg is in both "there" and "back" stretches.
|
518
|
+
# We work with the "there" minima for the two end-segments of seg's
|
519
|
+
# "there" stretch, as well as with the "back" minimum for seg iteself...
|
520
|
+
#
|
521
|
+
# there_1(sent_3 - (bounced_2 - RT)) +
|
522
|
+
# there_3((bounced_2 - RT) - sent_1)
|
523
|
+
# RT - back_2 = -------------------------------------
|
524
|
+
# sent_3 - sent_1
|
525
|
+
#
|
526
|
+
seg_1 = stretch_startseg[0,stretch_index[0,seg]] # use its "there" min
|
527
|
+
seg_2 = seg # use its "back" min
|
528
|
+
seg_3 = stretch_endseg[0,stretch_index[0,seg]] # use its "there" min
|
529
|
+
tmpstdroundtrip_a = \
|
530
|
+
(min[0,seg_1] * (min_sent[0,seg_3] - min_bounced[1,seg_2]) + \
|
531
|
+
min[1,seg_2] * (min_sent[0,seg_3] - min_sent[0,seg_1]) + \
|
532
|
+
min[0,seg_3] * (min_bounced[1,seg_2] - min_sent[0,seg_1])) \
|
533
|
+
/ ((min_sent[0,seg_3] + min[0,seg_3]) - \
|
534
|
+
(min_sent[0,seg_1] + min[0,seg_1]))
|
535
|
+
if (showstdroundtrips)
|
536
|
+
print "segments", seg_1, "there,", seg_2, "back,", seg_3, "there:",
|
537
|
+
"ROUNDTRIP", tmpstdroundtrip_a
|
538
|
+
# ... and vice versa,
|
539
|
+
# using "back" stretch end-segment "back" data, and seg "there" data
|
540
|
+
seg_1 = stretch_startseg[1,stretch_index[1,seg]] # use its "back" min
|
541
|
+
seg_2 = seg # use its "there" min
|
542
|
+
seg_3 = stretch_endseg[1,stretch_index[1,seg]] # use its "back" min
|
543
|
+
tmpstdroundtrip_b = \
|
544
|
+
(min[1,seg_1] * (min_bounced[1,seg_3] - min_sent[0,seg_2]) +\
|
545
|
+
min[0,seg_2] * (min_bounced[1,seg_3] - min_bounced[1,seg_1])+\
|
546
|
+
min[1,seg_3] * (min_sent[0,seg_2] - min_bounced[1,seg_1])) \
|
547
|
+
/ ((min_bounced[1,seg_3] - min[1,seg_3]) - \
|
548
|
+
(min_bounced[1,seg_1] - min[1,seg_1]))
|
549
|
+
if (showstdroundtrips)
|
550
|
+
print "segments", seg_1, "back,", seg_2, "there,", seg_3, "back:",
|
551
|
+
"ROUNDTRIP", tmpstdroundtrip_b
|
552
|
+
return (tmpstdroundtrip_a + tmpstdroundtrip_b) / 2
|
553
|
+
}
|
554
|
+
|
555
|
+
function stretch_length(tb, str) {
|
556
|
+
return stretch_endseg[tb, str] - stretch_startseg[tb, str] + 1
|
557
|
+
}
|
558
|
+
|
559
|
+
function set_region_start(tb, seg, reg) {
|
560
|
+
region_first_seg[reg] = seg
|
561
|
+
$0 = data[min_index[tb,seg]]
|
562
|
+
region_first_tb[reg] = tb
|
563
|
+
region_first_orig_sent[reg] = $sentfieldnum
|
564
|
+
region_first_sent[reg] = min_sent[tb,seg]
|
565
|
+
region_first_orig_received[reg] = fixbyteorder($receivedfieldnum)
|
566
|
+
region_first_received[reg] = min_received[tb,seg]
|
567
|
+
region_first_orig_bounced[reg] = $bouncedfieldnum
|
568
|
+
region_first_bounced[reg] = min_bounced[tb,seg]
|
569
|
+
|
570
|
+
region_first_received_shouldbe[reg] = \
|
571
|
+
(tb == 0) ? region_first_orig_sent[reg] + stdroundtrip / 2 \
|
572
|
+
: region_first_orig_bounced[reg] - stdroundtrip / 2
|
573
|
+
}
|
574
|
+
|
575
|
+
function set_region_end(tb, seg, reg) {
|
576
|
+
region_last_seg[reg] = seg
|
577
|
+
$0 = data[min_index[tb,seg]]
|
578
|
+
region_last_tb[reg] = tb
|
579
|
+
region_last_orig_sent[reg] = $sentfieldnum
|
580
|
+
region_last_sent[reg] = min_sent[tb,seg]
|
581
|
+
region_last_orig_received[reg] = fixbyteorder($receivedfieldnum)
|
582
|
+
region_last_received[reg] = min_received[tb,seg]
|
583
|
+
region_last_orig_bounced[reg] = $bouncedfieldnum
|
584
|
+
region_last_bounced[reg] = min_bounced[tb,seg]
|
585
|
+
|
586
|
+
region_last_received_shouldbe[reg] = \
|
587
|
+
(tb == 0) ? region_last_orig_sent[reg] + stdroundtrip / 2 \
|
588
|
+
: region_last_orig_bounced[reg] - stdroundtrip / 2
|
589
|
+
}
|
590
|
+
|
591
|
+
BEGIN {
|
592
|
+
setparameters()
|
593
|
+
if (fieldseparator != "") FS = fieldseparator # must be set here
|
594
|
+
init = 1
|
595
|
+
}
|
596
|
+
|
597
|
+
init {
|
598
|
+
init = 0
|
599
|
+
error = 0
|
600
|
+
|
601
|
+
# Note: FILENAME for targetfromfilename() was not available in BEGIN
|
602
|
+
if (target == "")
|
603
|
+
target = targetfromfilename()
|
604
|
+
if (hostfieldnum != "" &&
|
605
|
+
(!(hostfieldnum > 0) || target == "")) {
|
606
|
+
printf "Initialization:",
|
607
|
+
"hostfieldnum and/or target not properly set.\n" \
|
608
|
+
> "/dev/stderr"
|
609
|
+
error = 1
|
610
|
+
exit
|
611
|
+
}
|
612
|
+
if ( ! (sentfieldnum > 0 &&
|
613
|
+
receivedfieldnum > 0 &&
|
614
|
+
bouncedfieldnum > 0 &&
|
615
|
+
sentfieldnum != receivedfieldnum &&
|
616
|
+
receivedfieldnum != bouncedfieldnum &&
|
617
|
+
bouncedfieldnum != sentfieldnum) ) {
|
618
|
+
printf "Initialization: data field numbers not properly set.\n" \
|
619
|
+
> "/dev/stderr"
|
620
|
+
error = 2
|
621
|
+
exit
|
622
|
+
}
|
623
|
+
sourcescale = 1 / (1 + sourceskew)
|
624
|
+
if (writefixeddir == "//") writefixeddir = ""
|
625
|
+
if (writeorigfixedplotdir == "//") writeorigfixedplotdir = ""
|
626
|
+
|
627
|
+
if (showtarget) print "Target:", target
|
628
|
+
if (writefixeddir) {
|
629
|
+
no_dir_filename = FILENAME
|
630
|
+
sub(/^.*\//, "", no_dir_filename)
|
631
|
+
fixedfilename = writefixeddir "/" no_dir_filename ".fix"
|
632
|
+
printf "" > fixedfilename
|
633
|
+
rejectedfilename = writefixeddir "/" no_dir_filename ".rej"
|
634
|
+
printf "" > rejectedfilename
|
635
|
+
}
|
636
|
+
if (writeorigfixedplotdir) {
|
637
|
+
no_dir_filename = FILENAME
|
638
|
+
sub(/^.*\//, "", no_dir_filename)
|
639
|
+
plotfilename = writeorigfixedplotdir "/" no_dir_filename ".plot"
|
640
|
+
printf "" > plotfilename
|
641
|
+
fixedplotfilename = \
|
642
|
+
writeorigfixedplotdir "/" no_dir_filename ".fix.plot"
|
643
|
+
printf "" > fixedplotfilename
|
644
|
+
rejectedplotfilename = \
|
645
|
+
writeorigfixedplotdir "/" no_dir_filename ".rej.plot"
|
646
|
+
printf "" > rejectedplotfilename
|
647
|
+
}
|
648
|
+
intpattern = "^[ \t]*-*[0-9][0-9]*[ \t]*$"
|
649
|
+
datalines = 0
|
650
|
+
in_data = 0 # before "data" (portion possibly containing readings)
|
651
|
+
readings = 0
|
652
|
+
segments = 0
|
653
|
+
thereback[0] = "there" # word for "there" direction code 0
|
654
|
+
thereback[1] = "back" # word for "back" direction code 1
|
655
|
+
# variable "tb" ranges over "there" and "back" direction codes
|
656
|
+
for (tb = 0; tb < 2; ++tb) {
|
657
|
+
stretches[tb] = 0
|
658
|
+
in_stretch[tb] = 0
|
659
|
+
}
|
660
|
+
needs_bytes_reversed = 0
|
661
|
+
}
|
662
|
+
|
663
|
+
in_data == 2 {
|
664
|
+
# will have exited if not intending to write fixed file
|
665
|
+
print >> fixedfilename
|
666
|
+
next
|
667
|
+
}
|
668
|
+
|
669
|
+
$0 ~ datalinepattern {
|
670
|
+
in_data = 1
|
671
|
+
++datalines
|
672
|
+
data[datalines] = $0
|
673
|
+
if (hostfieldnum && $hostfieldnum != target) next
|
674
|
+
if ($sentfieldnum !~ intpattern || $receivedfieldnum !~ intpattern ||
|
675
|
+
$bouncedfieldnum !~ intpattern)
|
676
|
+
next
|
677
|
+
if (readings == 0) {
|
678
|
+
first_NR = NR
|
679
|
+
first_index = datalines
|
680
|
+
first_sent = $sentfieldnum
|
681
|
+
first_received = $receivedfieldnum
|
682
|
+
first_bounced = $bouncedfieldnum
|
683
|
+
# before setting the cosmetic shifts, we wait till the next reading,
|
684
|
+
# which, in comparison with this reading, will indicate whether
|
685
|
+
# we need to reverse the byte order of the target timestamps.
|
686
|
+
readings = 1
|
687
|
+
next
|
688
|
+
}
|
689
|
+
else if (readings == 1) {
|
690
|
+
if (abs($receivedfieldnum - first_received) > 256 * 256)
|
691
|
+
needs_bytes_reversed = 1
|
692
|
+
sourceshift = -first_sent
|
693
|
+
targetshift = int((first_sent + first_bounced)/2 + sourceshift \
|
694
|
+
- fixbyteorder(first_received))
|
695
|
+
sent = 0
|
696
|
+
received = fixbyteorder(first_received) + targetshift
|
697
|
+
bounced = int((first_bounced + sourceshift) * sourcescale)
|
698
|
+
there = received - sent
|
699
|
+
back = bounced - received
|
700
|
+
roundtrip = bounced - sent
|
701
|
+
segments = 1
|
702
|
+
min_index[0,1] = min_index[1,1] = \
|
703
|
+
min_index[0,1] = min_index[1,1] = \
|
704
|
+
first_index
|
705
|
+
min_sent[0,1] = min_sent[1,1] = \
|
706
|
+
min_sent_late[0,1] = min_sent_late[1,1] = \
|
707
|
+
sent # 0
|
708
|
+
min_received[0,1] = min_received[1,1] = \
|
709
|
+
min_received_late[0,1] = min_received_late[1,1] = \
|
710
|
+
received
|
711
|
+
min_bounced[0,1] = min_bounced[1,1] = \
|
712
|
+
min_bounced_late[0,1] = min_bounced_late[1,1] = \
|
713
|
+
bounced
|
714
|
+
globalminthere = min[0,1] = there
|
715
|
+
globalminback = min[1,1] = back
|
716
|
+
globalminroundtrip = min[2,1] = roundtrip
|
717
|
+
this_stretch_startseg[0] = 1 # "there", candidate only!
|
718
|
+
this_stretch_startseg[1] = 1 # "back", candidate only!
|
719
|
+
if (showreadings) {
|
720
|
+
print "Segment 1:"
|
721
|
+
print "1 (line", first_NR ") at", sent \
|
722
|
+
": there", there ", back", back ", roundtrip", roundtrip
|
723
|
+
}
|
724
|
+
}
|
725
|
+
++readings
|
726
|
+
sent = int(($sentfieldnum + sourceshift) * sourcescale)
|
727
|
+
received = fixbyteorder($receivedfieldnum) + targetshift
|
728
|
+
bounced = int(($bouncedfieldnum + sourceshift) * sourcescale)
|
729
|
+
there = received - sent
|
730
|
+
back = bounced - received
|
731
|
+
roundtrip = bounced - sent
|
732
|
+
if (sent >= segments * segmentsecs * 1000) {
|
733
|
+
# the present reading begins a new segment; report on the old ...
|
734
|
+
segmentboundary()
|
735
|
+
|
736
|
+
# ... and initialize the new
|
737
|
+
++segments
|
738
|
+
if (showreadings)
|
739
|
+
print "\nSegment", segments ":"
|
740
|
+
min_index[0,segments] = min_index[1,segments] = \
|
741
|
+
min_index_late[0,segments] = min_index_late[1,segments] = \
|
742
|
+
datalines
|
743
|
+
min_sent[0,segments] = min_sent[1,segments] = \
|
744
|
+
min_sent_late[0,segments] = min_sent_late[1,segments] = \
|
745
|
+
sent
|
746
|
+
min_received[0,segments] = min_received[1,segments] = \
|
747
|
+
min_received_late[0,segments] = min_received_late[1,segments] =\
|
748
|
+
received
|
749
|
+
min_bounced[0,segments] = min_bounced[1,segments] = \
|
750
|
+
min_bounced_late[0,segments] = min_bounced_late[1,segments] = \
|
751
|
+
bounced
|
752
|
+
min[0,segments] = there
|
753
|
+
min[1,segments] = back
|
754
|
+
min[2,segments] = roundtrip
|
755
|
+
}
|
756
|
+
else {
|
757
|
+
if (there < min[0,segments]) {
|
758
|
+
min_index[0,segments] = min_index_late[0,segments] = datalines
|
759
|
+
min_sent[0,segments] = min_sent_late[0,segments] = sent
|
760
|
+
min_received[0,segments] = min_received_late[0,segments] = \
|
761
|
+
received
|
762
|
+
min_bounced[0,segments] = min_bounced_late[0,segments] = bounced
|
763
|
+
min[0,segments] = there
|
764
|
+
}
|
765
|
+
else if (there == min[0,segments]) {
|
766
|
+
min_index_late[0,segments] = datalines
|
767
|
+
min_sent_late[0,segments] = sent
|
768
|
+
min_received_late[0,segments] = received
|
769
|
+
min_bounced_late[0,segments] = bounced
|
770
|
+
}
|
771
|
+
if (back < min[1,segments]) {
|
772
|
+
min_index[1,segments] = min_index_late[1,segments] = datalines
|
773
|
+
min_sent[1,segments] = min_sent_late[1,segments] = sent
|
774
|
+
min_received[1,segments] = min_received_late[1,segments] = \
|
775
|
+
received
|
776
|
+
min_bounced[1,segments] = min_bounced_late[1,segments] = bounced
|
777
|
+
min[1,segments] = back
|
778
|
+
}
|
779
|
+
else if (back == min[1,segments]) {
|
780
|
+
min_index_late[1,segments] = datalines
|
781
|
+
min_sent_late[1,segments] = sent
|
782
|
+
min_received_late[1,segments] = received
|
783
|
+
min_bounced_late[1,segments] = bounced
|
784
|
+
}
|
785
|
+
if (roundtrip < min[2,segments])
|
786
|
+
min[2,segments] = roundtrip
|
787
|
+
}
|
788
|
+
if (showreadings)
|
789
|
+
print readings, "(line", NR ") at", sent \
|
790
|
+
": there", there ", back", back ", roundtrip", roundtrip
|
791
|
+
next
|
792
|
+
}
|
793
|
+
|
794
|
+
in_data == 0 {
|
795
|
+
if (writefixeddir)
|
796
|
+
print >> fixedfilename
|
797
|
+
next
|
798
|
+
}
|
799
|
+
|
800
|
+
in_data == 1 {
|
801
|
+
if (pastdatapattern == "" || $0 !~ pastdatapattern) {
|
802
|
+
++datalines
|
803
|
+
data[datalines] = $0
|
804
|
+
next
|
805
|
+
}
|
806
|
+
savepostdataline = $0
|
807
|
+
|
808
|
+
in_data = 2
|
809
|
+
pastdata()
|
810
|
+
|
811
|
+
if (writefixeddir) {
|
812
|
+
# write first post-data line to fixed file
|
813
|
+
print savepostdataline >> fixedfilename
|
814
|
+
next
|
815
|
+
}
|
816
|
+
exit
|
817
|
+
}
|
818
|
+
|
819
|
+
function pastdata() {
|
820
|
+
if (!readings) {
|
821
|
+
error = 3
|
822
|
+
printf "No readings found for target %s.\n", target \
|
823
|
+
> "/dev/stderr"
|
824
|
+
exit
|
825
|
+
}
|
826
|
+
|
827
|
+
duration=sent
|
828
|
+
segmentboundary()
|
829
|
+
if (showminima)
|
830
|
+
print "\nglobalminthere", globalminthere \
|
831
|
+
"; globalminback", globalminback \
|
832
|
+
";\n\t\t\tglobalminroundtrip, fictive",
|
833
|
+
(globalminthere + globalminback) \
|
834
|
+
", actual", globalminroundtrip
|
835
|
+
|
836
|
+
if (showonewaystretches) {
|
837
|
+
print "\nJumpless one-way stretches and their skews:"
|
838
|
+
for (ii = 1; ii <= segments; ++ii)
|
839
|
+
print "Segment", ii \
|
840
|
+
":\tthere stretch", stretch_index[0,ii] \
|
841
|
+
", skew", stretch_skew[0,stretch_index[0,ii]] \
|
842
|
+
";\n\t\t back stretch", stretch_index[1,ii] \
|
843
|
+
", skew", stretch_skew[1,stretch_index[1,ii]]
|
844
|
+
}
|
845
|
+
|
846
|
+
# The ideal, congestion-free, round-trip time -- needed for the
|
847
|
+
# reconciliation and coalescing of one-way stretches for opposite
|
848
|
+
# directions -- may not be available in globalminroundtrip: there
|
849
|
+
# may not have been a single reading without congestion in at least
|
850
|
+
# one of the directions. However, any pair of (non-spurious)
|
851
|
+
# stretches for opposite directions which overlap on at least two
|
852
|
+
# segments should, in their segment minima for their respective
|
853
|
+
# directions, represent collinear target clock deviation points.
|
854
|
+
# Expressing this collinearity by intertranslating the one-way
|
855
|
+
# transit-time minima for the opposite directions in terms of the
|
856
|
+
# unknown ideal round-trip time allows us to derive the ideal
|
857
|
+
# round-trip time -- provided the one-way transit-time minima are
|
858
|
+
# perfectly congestion-free and error-free. Practically, however,
|
859
|
+
# what we can expect to derive by this method is a useful "standard
|
860
|
+
# round-trip time" that, as said, may well be smaller than
|
861
|
+
# globalminroundtrip, perhaps considerably. It might also be just
|
862
|
+
# a bit bigger than globalminroundtrip, perhaps by a millisecond or
|
863
|
+
# two (depending on intrastretchmaxerr), as if the effective baseline
|
864
|
+
# round-trip time, given our limited sampling and our error tolerance
|
865
|
+
# for "collinearity", is a bit higher than the super-good time that
|
866
|
+
# may be observed as a fluke.
|
867
|
+
# Choosing the very lowest of the values for "standard round-trip
|
868
|
+
# time" that we can obtain by calculations of the sort suggested
|
869
|
+
# would give us the value closest to the true "ideal round-trip time".
|
870
|
+
# But this value may not be consistent with our generally imperfect
|
871
|
+
# one-way transit time minima, and so would not be the best choice of
|
872
|
+
# standard value to mediate the inter-direction translation we need
|
873
|
+
# to reconcile and coalesce counter-directional stretches. We must
|
874
|
+
# bear in mind that our objective is not to emerge from the analysis
|
875
|
+
# with as accurate an estimate as we can for the congestion-free
|
876
|
+
# transit times; but rather to emerge with a reliable assessment of
|
877
|
+
# whether no clock adjustments occurred between non-overlapping
|
878
|
+
# adjustment-free stretches.
|
879
|
+
# Therefore, we instead take as the effective stdroundtrip the
|
880
|
+
# average of all the values we can calculate as described above.
|
881
|
+
# We use globalminroundtrip as a guess at stdroundtrip if there
|
882
|
+
# are no approriate pairs of overlapping segments at all to admit
|
883
|
+
# our calculation -- and then with low expectations, after issuing
|
884
|
+
# a warning.
|
885
|
+
if (showstdroundtrips)
|
886
|
+
print "\nInferring \"ideal round-trip time\":"
|
887
|
+
idealcues = 0
|
888
|
+
total = 0
|
889
|
+
for (ii = 1; ii <= segments; ++ii) {
|
890
|
+
if ( (stretch_index_0 = stretch_index[0,ii]) == "" ||
|
891
|
+
(stretch_index_1 = stretch_index[1,ii]) == "" ||
|
892
|
+
min_sent[0,stretch_endseg[0,stretch_index_0]] < \
|
893
|
+
min_sent[1,stretch_startseg[1,stretch_index_1]] ||
|
894
|
+
min_sent[1,stretch_endseg[1,stretch_index_1]] < \
|
895
|
+
min_sent[0,stretch_startseg[0,stretch_index_0]] )
|
896
|
+
continue
|
897
|
+
if (!compatiblecounterskews(stretch_skew[0,stretch_index[0,ii]],
|
898
|
+
stretch_skew[1,stretch_index[1,ii]])) {
|
899
|
+
for (tb = 0; tb < 2; ++tb) {
|
900
|
+
this_stretch_index = stretch_index[tb,ii]
|
901
|
+
if (stretch_length(tb, this_stretch_index) == 4 &&
|
902
|
+
stretch_length(1-tb, this_stretch_index) >= 6) {
|
903
|
+
for (jj = stretch_startseg[tb, this_stretch_index];
|
904
|
+
jj <= stretch_endseg[tb, this_stretch_index];
|
905
|
+
++jj)
|
906
|
+
stretch_index[tb,ii] = ""
|
907
|
+
if (showrejectstretches)
|
908
|
+
print "REJECTING length 4", "\"" thereback[tb] "\"",
|
909
|
+
"stretch at Segment", ii ": incompatible skews"
|
910
|
+
break
|
911
|
+
}
|
912
|
+
}
|
913
|
+
continue
|
914
|
+
}
|
915
|
+
++stdcuesegs
|
916
|
+
total += inferstdroundtrip(ii)
|
917
|
+
}
|
918
|
+
if (stdcuesegs)
|
919
|
+
stdroundtrip_for_quality = stdroundtrip = total / stdcuesegs
|
920
|
+
else {
|
921
|
+
print "WARNING: no usable overlapping counter-stretches." \
|
922
|
+
> "/dev/null"
|
923
|
+
# local change -- ratul > "/dev/stderr"
|
924
|
+
stdroundtrip_for_quality = 0
|
925
|
+
stdroundtrip = globalminroundtrip
|
926
|
+
}
|
927
|
+
if (showquality) {
|
928
|
+
print "\nThe following provides a measure of the quality of",
|
929
|
+
"the timing data:"
|
930
|
+
#local change to avoid divide by zero errors
|
931
|
+
if (globalminroundtrip != 0) {
|
932
|
+
printf "inferred stdroundtrip / globalminroundtrip: " \
|
933
|
+
"%s / %s = %s\n",
|
934
|
+
stdroundtrip_for_quality, globalminroundtrip,
|
935
|
+
stdroundtrip_for_quality / globalminroundtrip
|
936
|
+
}
|
937
|
+
else {
|
938
|
+
printf "inferred stdroundtrip / globalminroundtrip: " \
|
939
|
+
"%s / %s = %s\n",
|
940
|
+
stdroundtrip_for_quality, globalminroundtrip,
|
941
|
+
"nan"
|
942
|
+
}
|
943
|
+
}
|
944
|
+
if (showstdroundtrips || showcompositestretches)
|
945
|
+
print "\nUsing stdroundtrip", stdroundtrip
|
946
|
+
|
947
|
+
# synthesize composite stretches
|
948
|
+
if (showcompositestretches) {
|
949
|
+
print "\nComposite stretch processing:"
|
950
|
+
}
|
951
|
+
last_stretch_segment = 0
|
952
|
+
last_stretch_tb = "" # (will prefer "there" data when both available)
|
953
|
+
for (ii = 1; ii <= segments; ++ii) {
|
954
|
+
there_skew = stretch_skew[0,stretch_index[0,ii]]
|
955
|
+
back_skew = stretch_skew[1,stretch_index[1,ii]]
|
956
|
+
if (there_skew == "" && back_skew == "") {
|
957
|
+
if (showcompositestretches)
|
958
|
+
print "Segment " ii ": not in a stretch."
|
959
|
+
segment_composite[ii] = "unknown" # may be overwritten
|
960
|
+
continue
|
961
|
+
}
|
962
|
+
# skews have been registered from "there" and/or from "back" data
|
963
|
+
if ((there_skew != "" && back_skew == "") ||
|
964
|
+
(there_skew == "" && back_skew != "")) {
|
965
|
+
# skews have been registered from "there" XOR from "back" data
|
966
|
+
this_tb = (there_skew != "") ? 0 : 1
|
967
|
+
if (stretch_index[this_tb,ii-1] == stretch_index[this_tb,ii]) {
|
968
|
+
# past start of stretch
|
969
|
+
if (showcompositestretches)
|
970
|
+
print "Segment " ii ":",
|
971
|
+
"past start of only stretch. CONTINUE."
|
972
|
+
segment_composite[ii] = "CONTINUE"
|
973
|
+
}
|
974
|
+
else if (last_stretch_segment &&
|
975
|
+
continuation(last_stretch_tb, last_stretch_segment,
|
976
|
+
this_tb, ii)) {
|
977
|
+
# new stretch resumes last stretch;
|
978
|
+
# assume intervening congestion, and fill the gap, if any
|
979
|
+
if (showcompositestretches)
|
980
|
+
print "Segment " ii ":",
|
981
|
+
"new stretch resumes last stretch. Back fill CONTINUE."
|
982
|
+
for (jj = last_stretch_segment + 1; jj <= ii; ++jj)
|
983
|
+
segment_composite[jj] = "CONTINUE"
|
984
|
+
}
|
985
|
+
else {
|
986
|
+
# start of the very first stretch, or following jump or turn
|
987
|
+
# ... which we may someday take the trouble to locate ...
|
988
|
+
if (showcompositestretches)
|
989
|
+
print "Segment " ii ":",
|
990
|
+
"START of the very first stretch, or following jump/turn."
|
991
|
+
segment_composite[ii] = "START"
|
992
|
+
}
|
993
|
+
last_stretch_segment = ii
|
994
|
+
last_stretch_tb = this_tb
|
995
|
+
continue
|
996
|
+
}
|
997
|
+
# skews have been registered both from "there" and from "back" data
|
998
|
+
if (stretch_index[0,ii-1] == stretch_index[0,ii] &&
|
999
|
+
stretch_index[1,ii-1] == stretch_index[1,ii]) {
|
1000
|
+
# past start of both of the stretches
|
1001
|
+
# (we save repeated continuation checks)
|
1002
|
+
if (showcompositestretches)
|
1003
|
+
print "Segment " ii ":",
|
1004
|
+
"in two stretches; past start of both. CONTINUE."
|
1005
|
+
segment_composite[ii] = "CONTINUE"
|
1006
|
+
last_stretch_segment = ii
|
1007
|
+
last_stretch_tb = 0
|
1008
|
+
continue
|
1009
|
+
}
|
1010
|
+
# at least one of the two stretches is just starting
|
1011
|
+
if (continuation(0, ii, 1, ii)) {
|
1012
|
+
# (The "continuation" test should work for arbitrarily
|
1013
|
+
# positioned stretches.)
|
1014
|
+
if (stretch_index[0,ii-1] == stretch_index[0,ii] ||
|
1015
|
+
stretch_index[1,ii-1] == stretch_index[1,ii]) {
|
1016
|
+
# one stretch continuing, another starting, compatibly
|
1017
|
+
if (showcompositestretches)
|
1018
|
+
print "Segment " ii ":",
|
1019
|
+
"CONTINUE test succeeded for start new mid-existing."
|
1020
|
+
segment_composite[ii] = "CONTINUE"
|
1021
|
+
}
|
1022
|
+
else if (last_stretch_segment &&
|
1023
|
+
continuation(last_stretch_tb, last_stretch_segment,
|
1024
|
+
0, ii)) {
|
1025
|
+
# both stretches are just starting, but resume last stretch;
|
1026
|
+
# assume intervening congestion, and fill the gap, if any
|
1027
|
+
if (showcompositestretches)
|
1028
|
+
print "Segment " ii ":",
|
1029
|
+
"new stretches resume last stretch. Back fill CONTINUE."
|
1030
|
+
for (jj = last_stretch_segment + 1; jj <= ii; ++jj)
|
1031
|
+
segment_composite[jj] = "CONTINUE"
|
1032
|
+
}
|
1033
|
+
else {
|
1034
|
+
# both stretches are just starting
|
1035
|
+
if (showcompositestretches)
|
1036
|
+
print "Segment " ii ":",
|
1037
|
+
"double START, very first or after jump/turn."
|
1038
|
+
segment_composite[ii] = "START"
|
1039
|
+
}
|
1040
|
+
last_stretch_segment = ii
|
1041
|
+
last_stretch_tb = 0
|
1042
|
+
continue
|
1043
|
+
}
|
1044
|
+
else {
|
1045
|
+
# "continuation" test failed: the two stretches can't be merged.
|
1046
|
+
# The stretches should be hinged on this single segment,
|
1047
|
+
# NOT overlapping on two or more segments. One must be ending.
|
1048
|
+
if (stretch_index[0,ii] == stretch_index[0,ii+1] &&
|
1049
|
+
stretch_index[1,ii] == stretch_index[1,ii+1]) {
|
1050
|
+
# BAD: neither is ending.
|
1051
|
+
if (showcompositestretches)
|
1052
|
+
print "Segment " ii ":",
|
1053
|
+
"continuation test failed; BAD non-hinge case."
|
1054
|
+
printf "ERROR: Stretches overlappiing at segment %d " \
|
1055
|
+
"are incompatible.\n",
|
1056
|
+
ii > "/dev/stderr"
|
1057
|
+
error = 4
|
1058
|
+
exit
|
1059
|
+
}
|
1060
|
+
if ((stretch_index[0,ii] != stretch_index[0,ii+1] &&
|
1061
|
+
min_sent[0,ii] > min_bounced[1,ii] - stdroundtrip) \
|
1062
|
+
|| (stretch_index[1,ii] != stretch_index[1,ii+1] &&
|
1063
|
+
min_bounced[1,ii] - stdroundtrip > min_sent[0,ii])) {
|
1064
|
+
# BAD: overlapping at a fine granularity, within segment.
|
1065
|
+
if (showcompositestretches)
|
1066
|
+
print "Segment " ii ":",
|
1067
|
+
"continuation test failed;",
|
1068
|
+
"BAD micro-overlap in hinge case."
|
1069
|
+
printf "ERROR: Stretches overlappiing inside segment %d " \
|
1070
|
+
"are incompatible.\n",
|
1071
|
+
ii > "/dev/stderr"
|
1072
|
+
error = 5
|
1073
|
+
exit
|
1074
|
+
}
|
1075
|
+
if (compatiblecounterskews(there_skew, back_skew)) {
|
1076
|
+
if (showcompositestretches)
|
1077
|
+
print "Segment " ii ": continuation test failed; JUMP."
|
1078
|
+
segment_composite[ii] = "JUMP"
|
1079
|
+
}
|
1080
|
+
else {
|
1081
|
+
if (showcompositestretches)
|
1082
|
+
print "Segment " ii ": continuation test failed; TURN."
|
1083
|
+
segment_composite[ii] = "TURN"
|
1084
|
+
}
|
1085
|
+
last_stretch_segment = ii
|
1086
|
+
last_stretch_tb = 0
|
1087
|
+
continue
|
1088
|
+
}
|
1089
|
+
}
|
1090
|
+
if (showcompositestretches) {
|
1091
|
+
print "\nComposite stretch end result:"
|
1092
|
+
for (ii = 1; ii <= segments; ++ii)
|
1093
|
+
print "Segment", ii \
|
1094
|
+
":\t" segment_composite[ii]
|
1095
|
+
}
|
1096
|
+
|
1097
|
+
# map final regions
|
1098
|
+
# Note: we assume no out-of-sequence packet delivery, at least at the
|
1099
|
+
# data's spacing of packets ... but perhaps necessarily, if moving
|
1100
|
+
# through a fixed path, with fixed hardware interfaces.
|
1101
|
+
regions = 0
|
1102
|
+
for (ii = 1; ii <= segments; ++ii) {
|
1103
|
+
if (segment_composite[ii] == "unknown") continue
|
1104
|
+
there_stretch = stretch_index[0,ii]
|
1105
|
+
back_stretch = stretch_index[1,ii]
|
1106
|
+
if (segment_composite[ii] == "START") {
|
1107
|
+
# region start point
|
1108
|
+
++regions
|
1109
|
+
if (there_stretch &&
|
1110
|
+
(!back_stretch || min_sent[0,ii] <= min_sent[1,ii]))
|
1111
|
+
set_region_start(0, ii, regions)
|
1112
|
+
else
|
1113
|
+
set_region_start(1, ii, regions)
|
1114
|
+
}
|
1115
|
+
if (segment_composite[ii] == "CONTINUE") {
|
1116
|
+
if (segment_composite[ii+1] == "CONTINUE" ||
|
1117
|
+
segment_composite[ii+1] == "JUMP" ||
|
1118
|
+
segment_composite[ii+1] == "TURN")
|
1119
|
+
continue
|
1120
|
+
# region end point
|
1121
|
+
if (there_stretch &&
|
1122
|
+
(!back_stretch || min_sent[0,ii] >= min_sent[1,ii]))
|
1123
|
+
set_region_end(0, ii, regions)
|
1124
|
+
else
|
1125
|
+
set_region_end(1, ii, regions)
|
1126
|
+
}
|
1127
|
+
else if (segment_composite[ii] == "JUMP" ||
|
1128
|
+
segment_composite[ii] == "TURN") {
|
1129
|
+
# region start and end points
|
1130
|
+
if (min_sent[0,ii] < min_sent[1,ii]) {
|
1131
|
+
set_region_end(0, ii, regions)
|
1132
|
+
set_region_start(1, ii, regions+1)
|
1133
|
+
}
|
1134
|
+
else {
|
1135
|
+
set_region_end(1, ii, regions)
|
1136
|
+
set_region_start(0, ii, regions+1)
|
1137
|
+
}
|
1138
|
+
++regions
|
1139
|
+
}
|
1140
|
+
}
|
1141
|
+
if (showregions) {
|
1142
|
+
print "\nFinal map of regions:"
|
1143
|
+
for (ii = 1; ii <= regions; ++ii)
|
1144
|
+
printf "Region %d (segments %d - %d):\n" \
|
1145
|
+
" %s %d->%d->%d to %s %d->%d->%d\n",
|
1146
|
+
ii, region_first_seg[ii], region_last_seg[ii],
|
1147
|
+
(region_first_tb[ii] == 0) ? "(\"there\")" \
|
1148
|
+
: "(\"back\")",
|
1149
|
+
region_first_orig_sent[ii],
|
1150
|
+
region_first_orig_received[ii],
|
1151
|
+
region_first_orig_bounced[ii],
|
1152
|
+
(region_last_tb[ii] == 0) ? "(\"there\")" \
|
1153
|
+
: "(\"back\")",
|
1154
|
+
region_last_orig_sent[ii],
|
1155
|
+
region_last_orig_received[ii],
|
1156
|
+
region_last_orig_bounced[ii]
|
1157
|
+
}
|
1158
|
+
if (showcoverage) {
|
1159
|
+
coverage = 0
|
1160
|
+
for (ii = 1; ii <= regions; ++ii)
|
1161
|
+
coverage += region_last_sent[ii] - region_first_sent[ii]
|
1162
|
+
printf "\nRelative coverage: %s / %s = %s\n",
|
1163
|
+
coverage, duration, coverage / duration
|
1164
|
+
}
|
1165
|
+
|
1166
|
+
if (!writefixeddir && !writeorigfixedplotdir) return
|
1167
|
+
|
1168
|
+
# write corrected data lines to fixed file
|
1169
|
+
saveOFS = OFS
|
1170
|
+
OFS = FS
|
1171
|
+
search_from_region = 1
|
1172
|
+
if (writeorigfixedplotdir)
|
1173
|
+
# display globalminthere as half the standard round trip.
|
1174
|
+
plottargetshift = targetshift + int(stdroundtrip/2) - globalminthere
|
1175
|
+
for (ii = 1; ii <= datalines; ++ii) {
|
1176
|
+
$0 = data[ii]
|
1177
|
+
|
1178
|
+
if ($0 !~ datalinepattern ||
|
1179
|
+
(hostfieldnum && $hostfieldnum != target) ||
|
1180
|
+
$sentfieldnum !~ intpattern ||
|
1181
|
+
$receivedfieldnum !~ intpattern ||
|
1182
|
+
$bouncedfieldnum !~ intpattern) {
|
1183
|
+
if (writefixeddir)
|
1184
|
+
print >> fixedfilename
|
1185
|
+
continue
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
# locate region, if any, covering this reading; else reject.
|
1189
|
+
for (jj = search_from_region; jj <= regions; ++jj) {
|
1190
|
+
if ($sentfieldnum <= region_last_orig_sent[jj]) break
|
1191
|
+
}
|
1192
|
+
search_from_region = jj
|
1193
|
+
|
1194
|
+
# fix the target byte order, even for the rejected data points
|
1195
|
+
$receivedfieldnum = fixbyteorder($receivedfieldnum)
|
1196
|
+
|
1197
|
+
if (writeorigfixedplotdir) {
|
1198
|
+
# shift and scale to match analytical output
|
1199
|
+
sent = int(($sentfieldnum + sourceshift) * sourcescale)
|
1200
|
+
received = $receivedfieldnum + plottargetshift
|
1201
|
+
bounced = int(($bouncedfieldnum + sourceshift) * sourcescale)
|
1202
|
+
printf "%d %d %d\n", sent, received, bounced \
|
1203
|
+
>> plotfilename
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
if (jj > regions || $sentfieldnum < region_first_orig_sent[jj]) {
|
1207
|
+
# didn't find one
|
1208
|
+
if (writefixeddir)
|
1209
|
+
print >> rejectedfilename
|
1210
|
+
if (writeorigfixedplotdir) {
|
1211
|
+
printf "%d %d %d\n", sent, received, bounced \
|
1212
|
+
>> rejectedplotfilename
|
1213
|
+
}
|
1214
|
+
continue
|
1215
|
+
}
|
1216
|
+
|
1217
|
+
# found the region
|
1218
|
+
first_orig_received = region_first_orig_received[jj]
|
1219
|
+
last_orig_received = region_last_orig_received[jj]
|
1220
|
+
first_received_shouldbe = region_first_received_shouldbe[jj]
|
1221
|
+
last_received_shouldbe = region_last_received_shouldbe[jj]
|
1222
|
+
received = $receivedfieldnum
|
1223
|
+
$receivedfieldnum = int( \
|
1224
|
+
((last_orig_received - received) * first_received_shouldbe + \
|
1225
|
+
(received - first_orig_received) * last_received_shouldbe) / \
|
1226
|
+
(last_orig_received - first_orig_received) )
|
1227
|
+
if (writefixeddir)
|
1228
|
+
print >> fixedfilename
|
1229
|
+
if (writeorigfixedplotdir) {
|
1230
|
+
# shift and scale fixed received to match sent shift and scale
|
1231
|
+
received = int(($receivedfieldnum + sourceshift) * sourcescale)
|
1232
|
+
printf "%d %d %d\n", sent, received, bounced \
|
1233
|
+
>> fixedplotfilename
|
1234
|
+
}
|
1235
|
+
}
|
1236
|
+
OFS = saveOFS
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
END {
|
1240
|
+
if (error) exit error
|
1241
|
+
if (in_data != 2) pastdata()
|
1242
|
+
}
|
1243
|
+
|
1244
|
+
# The objective is to compose a map of the target's clock skews and jumps over
|
1245
|
+
# the duration of the probing run. This allows compensation, removing target
|
1246
|
+
# clock artifacts from the probe's timing data.
|
1247
|
+
#
|
1248
|
+
# Note: I refer to the outgoing direction as "there" and the incoming direction
|
1249
|
+
# as "back".
|
1250
|
+
#
|
1251
|
+
# We analyze the "there" data and the "back" data independently, at first, for
|
1252
|
+
# maximal stretches of length at least 4 of segments whose segment minima for
|
1253
|
+
# one-way packet transit times, in the respective directions, are collinear.
|
1254
|
+
# The idea in the independent analysis of the two directions is two-fold:
|
1255
|
+
# foremost, a lack of persuasive data for one direction, due to obscuring of
|
1256
|
+
# clock behavior by network congestion in that direciton, can be covered for
|
1257
|
+
# by persuasive data for the other direction; and secondly, if data for both
|
1258
|
+
# directions are independently persuasive, the redundancy provides a measure
|
1259
|
+
# of error-checking and allows us to infer an uncongested round-trip time that
|
1260
|
+
# should be more reliable than the global minimum round-trip time.
|