Accurately measuring clock drift

Thangalin <[email protected]>
Newsgroups gmane.comp.time.chrony.user
Message-ID <CAANrE7rvB4rcpfN90OOfkTgmxZ8Yo0xVt+ps9A_0iQ0P+JzrOQ@mail.gmail.com>
Hi list,

We'd like to achieve a sub-30 μs window of transmission accuracy across
multiple devices for simulcast purposes. Ideally, sub-10 μs.

The system uses NTP and 1PPS, which works nearly all the time. We tested
both NTP and chrony over a weekend, and the results were not what we
expected. In the first plot, NTP+1PPS never drifted above *17 μs*. In the
second plot, chrony+1PPS drifted up to *281 μs*:

   - https://i.ibb.co/bs4V000/ntp.png
   - https://i.ibb.co/1drgncc/chrony.png

Something is wrong with the test, the configuration, or most likely both.

The test data was generated by running the following program:

// SOF
#include <stdio.h>
#include <stdlib.h>
#include <sys/timex.h>
#include <unistd.h>

int main( void ) {
  struct timex t = { 0 };

  while( 1 ) {
    const int clockState = adjtimex( &t );

    printf( "%ld,%ld,%ld,%ld\n", t.esterror, t.maxerror, t.offset, t.jitter
);
    fflush( stdout );
    sleep( 1 );
  }

  return 0;
}
// EOF

The configuration file for the chrony-side of the test follows:

# SOF
server 10.10.10.200 minpoll 0 maxpoll 0 maxdelay 0.5 iburst

# Location of ID/key pairs for NTP authentication.
keyfile /etc/chrony/chrony.keys

# Stores new gain/loss rate, for compensating the system clock upon restart.
driftfile /var/lib/chrony/chrony.drift

logdir /var/log/chrony

# Stop bad estimates from upsetting the machine clock.
maxupdateskew 100.0

# Enables kernel synchronisation (every 11 minutes) of the real-time clock.
rtcsync

# Step the system clock instead of slewing it if the adjustment is larger
than
# one second, but only in the first three clock updates.
makestep 1 3

# Enable hardware timestamping of NTP packets for all interfaces.
hwtimestamp *

# Synchronize time using the rising edge of a 1-pulse-per-second clock.
refclock PPS /dev/pps1 refid PPS1 poll 0 precision 1e-9 prefer
# EOF

When running *chronyc sources -v*, we see:

MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#* PPS1                          0   0   377     1   -502ns[ -534ns] +/-
1000ns
^- 10.10.10.200                  1   0   377     0    +33us[  +33us] +/-
1186us

The plots were generated using R:

ntp.data <- read.csv( 'ntp-drift.csv', header=TRUE );
ntp.data$id <- 1:nrow(ntp.data);
plot(x=ntp.data$id,ntp.data$est.err, xlab="ntp", ylab="estimated error
(us)", type="l");

chrony.data <- read.csv( 'chrony-drift.csv', header=TRUE );
chrony.data$id <- 1:nrow(chrony.data);
plot(x=chrony.data$id,chrony.data$est.err, xlab="chrony", ylab="estimated
error (us)", type="l");

I'm wondering, in no particular order:

   - Do the *esterror* values from calling *adjtimex()* yield an
   apples-to-apples comparison between chrony and NTP?
   - Do we need to combine PPS1 with the NTP server?
      - If so, how?
   - What else would we need to do to achieve sub-30 μs clock drift (or
   sub-10 μs)?
   - How can we verify that the clock isn't drifting more than 30 μs,
   programatically (i.e., what API calls return the recent clock drift
   adjustment value)?
   - What API call returns the most recent clock drift adjustment value in
   nanoseconds?

Any help is much appreciated.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.