ntpstats.refcheck¶
Check a disciplined clock, its daemon's claims and every estimator against an independent reference.
The validation campaign of docs/validation-campaign.md: a host is
disciplined over the network (chrony, ntpd, ...) while a reference it does
not use, typically a GNSS receiver's PPS logged by chrony as a noselect
refclock, records the true error of its clock. :func:validate then answers
four questions from the logs:
- How good is the clock? Error statistics, TDEV and MTIE of the
reference series, which is the clock's error (reference - local). For
chrony's
refclocks.logthe raw column is used: chrony'srefclock.clogs there the pulse against the system clock as applications read it, while the cooked column also subtracts the correction chrony is still slewing out (and adds the refclock'soffsetoption).reference_column="cooked"selects the latter. - Is the daemon's error bound honest? chrony.conf(5) defines the
Max. erroroftracking.logas "the maximum estimated error of the system clock in the interval since the previous update", so every reference sample between two updates must lie within the later update's value. Logs of chrony versions without that column are checked at the update times against root delay / 2 + root dispersion, which omits the offset being corrected and is marked approximate. Also reported: how well the daemon knew its own offset at each update. - Is every server inside its correctness interval? For each NTP
measurement,
theta - x(server error plus path asymmetry) must lie within the root distance(delay + root delay) / 2 + dispersion + root dispersion, the correctness interval of RFC 5905 section 11.2.1 with the root distance of its appendix A.5.5.2 less the peer jitter term (a statistical allowance for a filtered sample, not part of one exchange's bound): a correct server cannot be farther away, whatever the asymmetry. Violations identify falsetickers. - Which estimator is best on real data? Every bench estimator runs on the measured exchanges of each server (multi-server ones on all servers) and is scored against the reference, the comparison that simulation alone cannot make.
The reference's own uncertainty (ref_uncertainty, default 1 us for a
timing receiver's PPS with kernel time stamps) is added to every bound.
:func:synthetic_campaign writes logs with a known truth for tests and
for trying the command.
ValidationReport
dataclass
¶
Result of :func:validate; as_dict() for JSON.
passed
property
¶
The daemon's bound held (within max_violation_rate); servers are reported, not judged.
truth_at(reference, t, max_gap=4.0)
¶
The reference interpolated at t; NaN where the neighbouring reference samples are farther apart
than max_gap seconds or t is outside the reference.
validate(reference, tracking=None, measurements=None, estimators=DEFAULT_ESTIMATORS, ref_uncertainty=1e-06, max_gap=4.0, warmup=0.0, max_violation_rate=0.0, min_samples=16, reference_column='raw')
¶
Score a clock, its daemon's bound, its servers and the estimators against reference.
reference is the true error of the clock, reference - local (chrony's
refclocks.log cooked offset of a noselect PPS refclock, or any
series in that convention). tracking is the daemon's own record
(chrony tracking.log), measurements the per-server exchanges
(chrony measurements.log, ntpd peerstats, a capture). The first
warmup seconds of the reference are excluded everywhere. With
reference_column="raw" (default) a reference carrying chrony's raw
refclock error (extra["raw_error"]) is read from that column.
synthetic_campaign(directory, hours=6.0, seed=1, poll=64.0, falseticker=True, bound_scale=1.0)
¶
Write chrony tracking.log, measurements.log and refclocks.log with a known truth.
The clock's true error wanders by tens of microseconds; three servers
(plus a falseticker 20 ms off with a 10 ms delay, if falseticker)
are polled every poll seconds with exponential queueing delays; the
PPS refclock records the true error every second with 20 ns of noise.
bound_scale scales the maximum error written to tracking.log
(below 1 to make the daemon's bound dishonest). Returns the paths.