From b7c7c293e5d0deb0b150b082ffbb2a0143d7df19 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Tue, 1 Sep 2020 11:21:46 +0200 Subject: [PATCH] conf: add clockprecision directive Make the precision of the system clock configurable. This can be useful on servers using hardware timestamping to reduce the amount of noise added to the NTP timestamps and improve stability of NTP measurements. --- conf.c | 11 +++++++++++ conf.h | 1 + doc/chrony.conf.adoc | 21 +++++++++++++++++++++ local.c | 28 +++++++++++++--------------- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/conf.c b/conf.c index 94c4dbb..9dede19 100644 --- a/conf.c +++ b/conf.c @@ -100,6 +100,7 @@ static double correction_time_ratio = 3.0; static double max_clock_error = 1.0; /* in ppm */ static double max_drift = 500000.0; /* in ppm */ static double max_slew_rate = 1e6 / 12.0; /* in ppm */ +static double clock_precision = 0.0; /* in seconds */ static SRC_AuthSelectMode authselect_mode = SRC_AUTHSELECT_MIX; static double max_distance = 3.0; @@ -544,6 +545,8 @@ CNF_ParseLine(const char *filename, int number, char *line) parse_broadcast(p); } else if (!strcasecmp(command, "clientloglimit")) { parse_clientloglimit(p); + } else if (!strcasecmp(command, "clockprecision")) { + parse_double(p, &clock_precision); } else if (!strcasecmp(command, "cmdallow")) { parse_allow_deny(p, cmd_restrictions, 1); } else if (!strcasecmp(command, "cmddeny")) { @@ -2048,6 +2051,14 @@ CNF_GetMaxSlewRate(void) /* ================================================== */ +double +CNF_GetClockPrecision(void) +{ + return clock_precision; +} + +/* ================================================== */ + double CNF_GetMaxDistance(void) { diff --git a/conf.h b/conf.h index b1f6e64..1d3f36b 100644 --- a/conf.h +++ b/conf.h @@ -95,6 +95,7 @@ extern double CNF_GetMaxClockError(void); extern double CNF_GetMaxDrift(void); extern double CNF_GetCorrectionTimeRatio(void); extern double CNF_GetMaxSlewRate(void); +extern double CNF_GetClockPrecision(void); extern SRC_AuthSelectMode CNF_GetAuthSelectMode(void); extern double CNF_GetMaxDistance(void); diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc index 42e3997..5f029e4 100644 --- a/doc/chrony.conf.adoc +++ b/doc/chrony.conf.adoc @@ -908,6 +908,27 @@ distances are in milliseconds. === System clock +[[clockprecision]]*clockprecision* _precision_:: +The *clockprecision* directive specifies the precision of the system clock (in +seconds). It is used by *chronyd* to estimate the minimum noise in NTP +measurements and randomise low-order bits of timestamps in NTP responses. By +default, the precision is measured on start as the minimum time to read the +clock. ++ +The measured value works well in most cases. However, it generally +overestimates the precision and it can be sensitive to the CPU speed, which can +change over time to save power. In some cases with a high-precision clocksource +(e.g. the Time Stamp Counter of the CPU) and hardware timestamping, setting the +precision on the server to a smaller value can improve stability of clients' +NTP measurements. The server's precision is reported on clients by the +<> command. ++ +An example setting the precision to 8 nanoseconds is: ++ +---- +clockprecision 8e-9 +---- + [[corrtimeratio]]*corrtimeratio* _ratio_:: When *chronyd* is slewing the system clock to correct an offset, the rate at which it is slewing adds to the frequency error of the clock. On all supported diff --git a/local.c b/local.c index 15c37b1..c0916cf 100644 --- a/local.c +++ b/local.c @@ -108,8 +108,8 @@ static double max_clock_error; #define NSEC_PER_SEC 1000000000 -static void -calculate_sys_precision(void) +static double +measure_clock_precision(void) { struct timespec ts, old_ts; int iters, diff, best; @@ -135,18 +135,7 @@ calculate_sys_precision(void) assert(best > 0); - precision_quantum = 1.0e-9 * best; - - /* Get rounded log2 value of the measured precision */ - precision_log = 0; - while (best < 707106781) { - precision_log--; - best *= 2; - } - - assert(precision_log >= -30); - - DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log); + return 1.0e-9 * best; } /* ================================================== */ @@ -170,7 +159,16 @@ LCL_Initialise(void) current_freq_ppm = 0.0; temp_comp_ppm = 0.0; - calculate_sys_precision(); + precision_quantum = CNF_GetClockPrecision(); + if (precision_quantum <= 0.0) + precision_quantum = measure_clock_precision(); + + precision_quantum = CLAMP(1.0e-9, precision_quantum, 1.0); + precision_log = round(log(precision_quantum) / log(2.0)); + /* NTP code doesn't support smaller log than -30 */ + assert(precision_log >= -30); + + DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log); /* This is the maximum allowed frequency offset in ppm, the time must never stop or run backwards */