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 */