Hi all, Thank you for suggesting we use /sys/class/pps/pps1/assert to measure the clock. (Source code below.) Here's a comparison of the results between chrony and ntpd over 24 hours:
https://ibb.co/album/5YxH2m Chrony clearly improves the offsets to sub-20 microseconds much of the time. We're seeing some spikes in the timing, though, that exceed ntpd.* The chrony configuration file is the same as in the other thread ( https://www.mail-archive.com/chrony-users@chrony.tuxfamily.org/msg03281.html ). Other processes may be affected by changing the CPU, so we haven't switched to a constant frequency nor disabled the power saving states (e.g. idle=poll). Setting sched_priority to 1 yields a modest improvement over an hour: https://ibb.co/album/1Z824p Are there any other ways we could help chronyd stay below 20 microseconds (e.g., optimized build) that may have been overlooked (besides using GPIO)? Many thanks! *ntpd had one 1500+ us outlier, which we removed from the graphs. P.S. Code improvement suggestions welcome: // SOF #include <stdio.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #define PPS_DEVICE "/sys/class/pps/pps1/assert" static void diff_timespec( const struct timespec *time1, const struct timespec *time0, struct timespec* diff ) { diff->tv_sec = time1->tv_sec - time0->tv_sec; diff->tv_nsec = time1->tv_nsec - time0->tv_nsec; if( diff->tv_nsec < 0 ) { // nsec/sec diff->tv_nsec += 1000000000; diff->tv_sec--; } } int main( int argc, char** argv ) { struct timespec curr_pps_time = {0}; struct timespec prev_pps_time = {0}; int curr_assert = 0; int prev_assert = -1; struct timespec diff = {0}; struct timespec drift = {0}; char pps_buff[64] = {'\0'}; printf( "seconds,nanoSeconds\n" ); FILE* pps_fd = fopen( PPS_DEVICE, "r" ); while( 1 ) { fread( pps_buff,1, 63, pps_fd ); sscanf( pps_buff, "%ld.%ld#%d", &curr_pps_time.tv_sec, &curr_pps_time.tv_nsec, &curr_assert ); if( prev_assert == -1 ) { prev_assert = curr_assert; prev_pps_time.tv_sec = curr_pps_time.tv_sec; prev_pps_time.tv_nsec = curr_pps_time.tv_nsec; } if( ( curr_assert - prev_assert ) == 1 ) { struct timespec one_second = {.tv_sec = 1, .tv_nsec = 0}; diff_timespec( &curr_pps_time, &prev_pps_time, &diff ); diff.tv_sec >= 1 ? diff_timespec( &diff, &one_second, &drift ) : diff_timespec( &one_second, &diff, &drift ); printf( "%ld,%ld\n", drift.tv_sec, drift.tv_nsec ); fflush( stdout ); prev_assert = curr_assert; prev_pps_time.tv_sec = curr_pps_time.tv_sec; prev_pps_time.tv_nsec = curr_pps_time.tv_nsec; } fseek( pps_fd,0,SEEK_SET ); usleep( 250000 ); } fclose( pps_fd ); return 0; } // EOF Graphs were generated using R: # SOF plotOffsets <- function( filename ) { csv.data <- read.table( filename, sep=",", header=T, na.strings="", stringsAsFactors=F ); csv.data$nanoSeconds <- csv.data$nanoSeconds / 1000; plot(x=1:length(csv.data$nanoSeconds), csv.data$nanoSeconds, xlab="index", ylab="offset (us)", type="l"); } # EOF