Feed an event into this algorithm Returns [`Some`] if the event has improved this source's [`ClockParameters`].
(&mut self, event: event::Phc)
| 80 | /// |
| 81 | /// Returns [`Some`] if the event has improved this source's [`ClockParameters`]. |
| 82 | pub fn feed(&mut self, event: event::Phc) -> Option<&ClockParameters> { |
| 83 | // FIXME: take a MONOTONIC_COARSE timestamp *before* computing the clock error bound. |
| 84 | // |
| 85 | // The only use of this timestamp is to support and maintain the behavior for clients built |
| 86 | // against ClockBound 2.0. These clients grow the CEB by calculating the time elapsed |
| 87 | // between the instant the ClockParameters were computed, and the instant they read the |
| 88 | // system clock. This needs to be a bit pessimistic, hence the as_of_monotonic timestamp is |
| 89 | // taken *before* computing the clock error bound. |
| 90 | // |
| 91 | // This could be eliminated once we decide to stop supporting ClockBound 2.0 clients. |
| 92 | let as_of_monotonic = MonotonicCoarse.get_time(); |
| 93 | |
| 94 | let tsc_midpoint = event.tsc_midpoint(); |
| 95 | |
| 96 | // First update the internal local (current SKM) and estimate (long term) |
| 97 | // sample buffers |
| 98 | let within_threshold = self |
| 99 | .feed_internal_buffers(event) |
| 100 | .inspect_err(|error_msg| match error_msg { |
| 101 | FeedError::Old { event, .. } => { |
| 102 | tracing::warn!(?event, ?error_msg); |
| 103 | } |
| 104 | }) |
| 105 | .ok()?; // early exit if there was an error with the sample |
| 106 | |
| 107 | if !within_threshold { |
| 108 | // At this point, if the input does not meet our expectations on the rtt threshold, |
| 109 | // there is no more processing to do. The end calculation will not be more accurate than |
| 110 | // the previous value (if we have one) |
| 111 | tracing::trace!("Early exit. Event not within threshold"); |
| 112 | return None; |
| 113 | } |
| 114 | |
| 115 | // Functionality from this point will fill out the equation |
| 116 | // `C(t) = TSC(t) × p^ + K − θ^(t)` where: |
| 117 | // - `C(t)` is the absolute time. Corrected. This is effectively the output of the clock sync algorithm |
| 118 | // - `TSC(t)` is the tsc reading at a time |
| 119 | // - `p^` is the estimation of the clock period |
| 120 | // - `K` is the "epoch" (the uncorrected time at `TSC(0)`) |
| 121 | // - `θ^(t)` is the time correction |
| 122 | |
| 123 | // Calculate uncorrected clock, aka `p^` and `K` |
| 124 | self.uncorrected_clock = Self::calculate_uncorrected_clock(&self.local, &self.estimate); |
| 125 | |
| 126 | // Then calculate the local period using just the local event buffer |
| 127 | // |
| 128 | // This value is not used in the above equation, but IS reported in the final clock parameters |
| 129 | let Some(local_period) = Self::calculate_local_period_and_error(&self.local) else { |
| 130 | tracing::debug!("Early exit. Calculate local period returned none"); |
| 131 | return None; |
| 132 | }; |
| 133 | |
| 134 | // expect because not having an uncorrected clock is a bug at this point |
| 135 | // |
| 136 | // If we are able to calculate a local period, then uncorrected clock must be available |
| 137 | #[expect(clippy::missing_panics_doc, reason = "comment above")] |
| 138 | let uncorrected_clock = self |
| 139 | .uncorrected_clock |