]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
reference: allow clock adjustments without updating reference
authorMiroslav Lichvar <mlichvar@redhat.com>
Tue, 22 Feb 2022 10:00:27 +0000 (11:00 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Wed, 23 Feb 2022 13:43:39 +0000 (14:43 +0100)
Add support for accumulating frequency and time offset without changing
the reference parameters and calling the local parameter change
handlers.

This will allow an unsynchronized source to operate below other sources
in order to stabilize the clock.

local.c
local.h
reference.c
reference.h

diff --git a/local.c b/local.c
index 8dbee1838e2bb666188e2ba4c26a5668ca415b34..80fb6ba980820525cf292eeac22c1856152633dd 100644 (file)
--- a/local.c
+++ b/local.c
@@ -628,6 +628,24 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
 
 /* ================================================== */
 
+int
+LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset, double corr_rate)
+{
+  ChangeListEntry *first_handler;
+  int r;
+
+  first_handler = change_list.next;
+  change_list.next = &change_list;
+
+  r = LCL_AccumulateFrequencyAndOffset(dfreq, doffset, corr_rate);
+
+  change_list.next = first_handler;
+
+  return r;
+}
+
+/* ================================================== */
+
 void
 lcl_InvokeDispersionNotifyHandlers(double dispersion)
 {
diff --git a/local.h b/local.h
index 63d80e9ee8f769dccc8583a9f5b2b0085e266572..a23d275f2dda8a8b9e8bc5b03e2bac8c8fdee6d4 100644 (file)
--- a/local.h
+++ b/local.h
@@ -173,6 +173,11 @@ extern void LCL_NotifyLeap(int leap);
    a slew, in one easy step */
 extern int LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
 
+/* Same as the routine above, except it does not call the registered
+   parameter change handlers */
+extern int LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset,
+                                                      double corr_rate);
+
 /* Routine to read the system precision as a log to base 2 value. */
 extern int LCL_GetSysPrecisionAsLog(void);
 
index 903232305acbc44c811fbbf8cacdaecc55705fea..e6b95e94875d2792aa8b7be78498d1c8e248d92d 100644 (file)
@@ -150,6 +150,9 @@ static SCH_TimeoutID fb_drift_timeout_id;
 static double last_ref_update;
 static double last_ref_update_interval;
 
+static double last_ref_adjustment;
+static int ref_adjustments;
+
 /* ================================================== */
 
 static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
@@ -286,6 +289,8 @@ REF_Initialise(void)
   UTI_ZeroTimespec(&our_ref_time);
   last_ref_update = 0.0;
   last_ref_update_interval = 0.0;
+  last_ref_adjustment = 0.0;
+  ref_adjustments = 0;
 
   LCL_AddParameterChangeHandler(handle_slew, NULL);
 
@@ -960,6 +965,27 @@ fuzz_ref_time(struct timespec *ts)
 
 /* ================================================== */
 
+static double
+get_correction_rate(double offset_sd, double update_interval)
+{
+  /* We want to correct the offset quickly, but we also want to keep the
+     frequency error caused by the correction itself low.
+
+     Define correction rate as the area of the region bounded by the graph of
+     offset corrected in time.  Set the rate so that the time needed to correct
+     an offset equal to the current sourcestats stddev will be equal to the
+     update interval multiplied by the correction time ratio (assuming linear
+     adjustment).  The offset and the time needed to make the correction are
+     inversely proportional.
+
+     This is only a suggestion and it's up to the system driver how the
+     adjustment will be executed. */
+
+  return correction_time_ratio * 0.5 * offset_sd * update_interval;
+}
+
+/* ================================================== */
+
 void
 REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
                  uint32_t ref_id, IPAddr *ref_ip, struct timespec *ref_time,
@@ -969,7 +995,7 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
 {
   double uncorrected_offset, accumulate_offset, step_offset;
   double residual_frequency, local_abs_frequency;
-  double elapsed, mono_now, update_interval, correction_rate, orig_root_distance;
+  double elapsed, mono_now, update_interval, orig_root_distance;
   struct timespec now, raw_now;
   int manual;
 
@@ -1024,21 +1050,6 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
   last_ref_update_interval = update_interval;
   last_offset = offset;
 
-  /* We want to correct the offset quickly, but we also want to keep the
-     frequency error caused by the correction itself low.
-
-     Define correction rate as the area of the region bounded by the graph of
-     offset corrected in time. Set the rate so that the time needed to correct
-     an offset equal to the current sourcestats stddev will be equal to the
-     update interval multiplied by the correction time ratio (assuming linear
-     adjustment). The offset and the time needed to make the correction are
-     inversely proportional.
-
-     This is only a suggestion and it's up to the system driver how the
-     adjustment will be executed. */
-
-  correction_rate = correction_time_ratio * 0.5 * offset_sd * update_interval;
-
   /* Check if the clock should be stepped */
   if (is_step_limit_reached(offset, uncorrected_offset)) {
     /* Cancel the uncorrected offset and correct the total offset by step */
@@ -1050,7 +1061,8 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
   }
 
   /* Adjust the clock */
-  LCL_AccumulateFrequencyAndOffset(frequency, accumulate_offset, correction_rate);
+  LCL_AccumulateFrequencyAndOffset(frequency, accumulate_offset,
+                                   get_correction_rate(offset_sd, update_interval));
     
   maybe_log_offset(offset, raw_now.tv_sec);
 
@@ -1095,6 +1107,27 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
       avg2_moving = 1;
     avg2_offset = SQUARE(offset);
   }
+
+  ref_adjustments = 0;
+}
+
+/* ================================================== */
+
+int
+REF_AdjustReference(double offset, double frequency)
+{
+  double adj_corr_rate, ref_corr_rate, mono_now;
+
+  mono_now = SCH_GetLastEventMonoTime();
+  ref_adjustments++;
+
+  adj_corr_rate = get_correction_rate(fabs(offset), mono_now - last_ref_adjustment);
+  ref_corr_rate = get_correction_rate(our_offset_sd, last_ref_update_interval) /
+                  ref_adjustments;
+  last_ref_adjustment = mono_now;
+
+  return LCL_AccumulateFrequencyAndOffsetNoHandlers(frequency, offset,
+                                                    MAX(adj_corr_rate, ref_corr_rate));
 }
 
 /* ================================================== */
index 09400d45b5699687b8a3a63473b28098e0fa6624..73454d40ab9effcf9a4e77ff0e666c8e4f71579f 100644 (file)
@@ -162,6 +162,10 @@ extern void REF_SetManualReference
 extern void
 REF_SetUnsynchronised(void);
 
+/* Make a small correction of the clock without updating the reference
+   parameters and calling the clock change handlers */
+extern int REF_AdjustReference(double offset, double frequency);
+
 /* Announce a leap second before the full reference update */
 extern void REF_UpdateLeapStatus(NTP_Leap leap);