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.

Reply via email to