]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
hwclock: don't drop valid samples in HCL_ProcessReadings()
authorMiroslav Lichvar <mlichvar@redhat.com>
Mon, 11 Aug 2025 14:00:38 +0000 (16:00 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 14 Aug 2025 12:24:54 +0000 (14:24 +0200)
Modify the HCL_ProcessReadings() function to try to always provide
a valid sample. Instead of dropping a sample outside of the expected
delay, provide its assumed quality level as a small integer (relative to
already accumulated samples), and let the caller decide what quality is
acceptable.

hwclock.c
hwclock.h
ntp_io_linux.c
refclock_phc.c
test/unit/hwclock.c

index 06515e7b1c2a35a3a35ac0dc16433e596d5c20e2..eea2c7744586471c58fbb2a11d69d0be66480255 100644 (file)
--- a/hwclock.c
+++ b/hwclock.c
@@ -163,7 +163,8 @@ HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
 
 int
 HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
-                    struct timespec *hw_ts, struct timespec *local_ts, double *err)
+                    struct timespec *hw_ts, struct timespec *local_ts, double *err,
+                    int *quality)
 {
   double delay, raw_delay, min_delay, low_delay, high_delay, e, pred_err;
   double delay_sum, hw_sum, local_sum, local_prec, freq;
@@ -228,11 +229,13 @@ HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3]
     UTI_AddDoubleToTimespec(&tss[0][1], hw_sum / combined, hw_ts);
     UTI_AddDoubleToTimespec(&tss[0][0], local_sum / combined, local_ts);
     *err = MAX(delay_sum / combined / 2.0, clock->precision);
+    *quality = 2;
     return 1;
   }
 
-  /* Accept the reading with minimum delay if its interval does not contain
-     the current offset predicted from previous samples */
+  /* Indicate acceptable quality of the reading with minimum delay if its
+     interval does not contain the current offset predicted from previous
+     samples, or a new sample is needed to get the tracking working */
 
   *hw_ts = tss[min_reading][1];
   UTI_AddDoubleToTimespec(&tss[min_reading][0], min_delay / freq / 2.0, local_ts);
@@ -242,11 +245,14 @@ HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3]
   LCL_CookTime(local_ts, &ts1, NULL);
   if (!HCL_CookTime(clock, hw_ts, &ts2, &e) ||
       ((pred_err = UTI_DiffTimespecsToDouble(&ts1, &ts2)) > *err)) {
-    DEBUG_LOG("Accepted reading err=%e prerr=%e", *err, pred_err);
-    return 1;
+    *quality = 1;
+  } else {
+    *quality = 0;
   }
 
-  return 0;
+  DEBUG_LOG("Min-delay reading err=%e prerr=%e ql=%d", *err, pred_err, *quality);
+
+  return 1;
 }
 
 /* ================================================== */
index c3415ad6881f707ec920d8b2f3cb0e2ce61dbc2e..1484ddaa2fb0ec44e6247714c9bf32261403ea8f 100644 (file)
--- a/hwclock.h
+++ b/hwclock.h
@@ -38,10 +38,14 @@ extern void HCL_DestroyInstance(HCL_Instance clock);
 /* Check if a new sample should be accumulated at this time */
 extern int HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now);
 
-/* Process new readings of the HW clock in form of (sys, hw, sys) triplets and
-   produce a sample which can be accumulated */
+/* Process new readings of the HW clock in the form of (sys, hw, sys) triplets
+   and produce a sample which can be accumulated by HCL_AccumulateSample().
+   Indicate the quality of the sample relative to already processed samples as
+   a value of 0, 1, or 2, where a sample of quality 0 should normally be
+   dropped. */
 extern int HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
-                               struct timespec *hw_ts, struct timespec *local_ts, double *err);
+                               struct timespec *hw_ts, struct timespec *local_ts, double *err,
+                               int *quality);
 
 /* Accumulate a new sample */
 extern void HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
index 9b53d7bf19fe07d52fc4a3a7392669b212a441a6..23f427a5287808f6206d1ccdce1c0493b33b546a 100644 (file)
@@ -519,7 +519,7 @@ poll_phc(struct Interface *iface, struct timespec *now)
   struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts;
   struct timespec phc_readings[PHC_READINGS][3];
   double phc_err, local_err, interval;
-  int n_readings;
+  int n_readings, quality;
 
   if (!HCL_NeedsNewSample(iface->clock, now))
     return;
@@ -543,7 +543,8 @@ poll_phc(struct Interface *iface, struct timespec *now)
     return;
 
   if (!HCL_ProcessReadings(iface->clock, n_readings, phc_readings,
-                           &sample_phc_ts, &sample_sys_ts, &phc_err))
+                           &sample_phc_ts, &sample_sys_ts, &phc_err, &quality) ||
+      quality <= 0)
     return;
 
   LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);
index 08da75f30c9daad858239827da507858f3dcccb8..fe79c839c4a5f534830e64feae2e0346642e008a 100644 (file)
@@ -198,7 +198,7 @@ static int phc_poll(RCL_Instance instance)
   struct timespec phc_ts, sys_ts, local_ts, readings[PHC_READINGS][3];
   struct phc_instance *phc;
   double phc_err, local_err;
-  int n_readings;
+  int n_readings, quality;
 
   phc = (struct phc_instance *)RCL_GetDriverData(instance);
 
@@ -210,15 +210,20 @@ static int phc_poll(RCL_Instance instance)
   if (!phc->extpps)
     RCL_UpdateReachability(instance);
 
-  if (!HCL_ProcessReadings(phc->clock, n_readings, readings, &phc_ts, &sys_ts, &phc_err))
+  if (!HCL_ProcessReadings(phc->clock, n_readings, readings,
+                           &phc_ts, &sys_ts, &phc_err, &quality))
     return 0;
 
   LCL_CookTime(&sys_ts, &local_ts, &local_err);
-  HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);
+  if (quality > 0)
+    HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);
 
   if (phc->extpps)
     return 0;
 
+  if (quality <= 0)
+    return 0;
+
   DEBUG_LOG("PHC offset: %+.9f err: %.9f",
             UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts), phc_err);
 
index 79c08790949aa207bb09f7d2b7d585f64a05f9d7..d2b94143fe83fa07b093f22f8380699d86eb7565 100644 (file)
@@ -32,9 +32,9 @@ test_unit(void)
 {
   struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
   struct timespec readings[MAX_READINGS][3];
+  int i, j, k, l, new_sample, n_readings, count, quality;
   HCL_Instance clock;
   double freq, jitter, interval, dj, err, sum;
-  int i, j, k, l, new_sample, n_readings, count;
 
   LCL_Initialise();
   TST_RegisterDummyDrivers();
@@ -84,11 +84,13 @@ test_unit(void)
 
           UTI_ZeroTimespec(&hw_ts);
           UTI_ZeroTimespec(&local_ts);
-          if (HCL_ProcessReadings(clock, n_readings, readings, &hw_ts, &local_ts, &err)) {
-            HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
-            new_sample = 1;
-          } else {
-            new_sample = 0;
+          new_sample = 0;
+          if (HCL_ProcessReadings(clock, n_readings, readings, &hw_ts, &local_ts, &err, &quality)) {
+            TEST_CHECK(quality >= 0 && quality <= 2);
+            if (quality > 0) {
+              HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
+              new_sample = 1;
+            }
           }
         }