rpkt_time/
instant.rs

1// This file is taken from minstant at https://github.com/tikv/minstant and modified
2// for compatibility with the code in lib.rs.
3
4// Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0.
5
6use crate::tsc;
7
8use std::{
9    ops::{Add, AddAssign, Sub, SubAssign},
10    time::{Duration, SystemTime, UNIX_EPOCH},
11};
12
13/// A measurement of a monotonically nondecreasing clock. Similar to
14/// [`std::time::Instant`](std::time::Instant) but is faster and more
15/// accurate with stable TSC.
16#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct Instant(u64);
18
19impl Instant {
20    /// Returns the raw value of the tsc counter.
21    /// 
22    /// # Examples
23    /// ```
24    /// use rdtsc_time::Instant;
25    /// 
26    /// let ddl = Instant::now().raw().checked_add(rdtsc_time::cycles_per_sec()).unwrap();
27    /// while Instant::now().raw() <= ddl {}
28    /// 
29    /// println!("1s has passed");
30    /// ```
31    #[inline]
32    pub fn raw(&self) -> u64 {
33        self.0
34    }
35
36    /// Returns an instant corresponding to "now".
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use minstant::Instant;
42    ///
43    /// let now = Instant::now();
44    /// ```
45    #[inline]
46    pub fn now() -> Instant {
47        Instant(tsc::tsc_from_ref())
48    }
49
50    /// Returns the amount of time elapsed from another instant to this one,
51    /// or zero duration if that instant is later than this one.
52    ///
53    /// # Panics
54    ///
55    /// Previously we panicked if `earlier` was later than `self`. Currently this method saturates
56    /// to follow the behavior of the standard library. Future versions may reintroduce the panic
57    /// in some circumstances.
58    ///
59    /// # Examples
60    ///
61    /// ```
62    /// use std::time::Duration;
63    /// use std::thread::sleep;
64    ///
65    /// use minstant::Instant;
66    ///
67    /// let now = Instant::now();
68    /// sleep(Duration::new(1, 0));
69    /// let new_now = Instant::now();
70    /// println!("{:?}", new_now.duration_since(now));
71    /// println!("{:?}", now.duration_since(new_now)); // 0ns
72    /// ```
73    #[inline]
74    pub fn duration_since(&self, earlier: Instant) -> Duration {
75        self.checked_duration_since(earlier).unwrap_or_default()
76    }
77
78    /// Returns the amount of time elapsed from another instant to this one,
79    /// or None if that instant is later than this one.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use std::time::Duration;
85    /// use std::thread::sleep;
86    ///
87    /// use minstant::Instant;
88    ///
89    /// let now = Instant::now();
90    /// sleep(Duration::new(1, 0));
91    /// let new_now = Instant::now();
92    /// println!("{:?}", new_now.checked_duration_since(now));
93    /// println!("{:?}", now.checked_duration_since(new_now)); // None
94    /// ```
95    #[inline]
96    pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
97        Some(Duration::from_nanos(
98            (self.0.checked_sub(earlier.0)? as f64 * tsc::nanos_per_cycle()) as u64,
99        ))
100    }
101
102    /// Returns the amount of time elapsed from another instant to this one,
103    /// or zero duration if that instant is later than this one.
104    ///
105    /// # Examples
106    ///
107    /// ```
108    /// use std::time::Duration;
109    /// use std::thread::sleep;
110    ///
111    /// use minstant::Instant;
112    ///
113    /// let now = Instant::now();
114    /// sleep(Duration::new(1, 0));
115    /// let new_now = Instant::now();
116    /// println!("{:?}", new_now.saturating_duration_since(now));
117    /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
118    /// ```
119    #[inline]
120    pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
121        self.checked_duration_since(earlier).unwrap_or_default()
122    }
123
124    /// Returns the amount of time elapsed since this instant was created.
125    ///
126    /// # Panics
127    ///
128    /// This function may panic if the current time is earlier than this
129    /// instant, which is something that can happen if an `Instant` is
130    /// produced synthetically.
131    ///
132    /// # Examples
133    ///
134    /// ```
135    /// use std::time::Duration;
136    /// use std::thread::sleep;
137    ///
138    /// use minstant::Instant;
139    ///
140    /// let instant = Instant::now();
141    /// let three_secs = Duration::from_secs(3);
142    /// sleep(three_secs);
143    /// assert!(instant.elapsed() >= three_secs);
144    /// ```
145    #[inline]
146    pub fn elapsed(&self) -> Duration {
147        Instant::now() - *self
148    }
149
150    /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
151    /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
152    /// otherwise.
153    #[inline]
154    pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
155        self.0
156            .checked_add((duration.as_nanos() as u64 as f64 / tsc::nanos_per_cycle()) as u64)
157            .map(Instant)
158    }
159
160    /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
161    /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
162    /// otherwise.
163    #[inline]
164    pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
165        self.0
166            .checked_sub((duration.as_nanos() as u64 as f64 / tsc::nanos_per_cycle()) as u64)
167            .map(Instant)
168    }
169
170    /// Convert interal clocking counter into a UNIX timestamp represented as the
171    /// nanoseconds elapsed from [UNIX_EPOCH](std::time::UNIX_EPOCH).
172    ///
173    /// [`Anchor`](crate::Anchor) contains the necessary calibration data for conversion.
174    /// Typically, initializing an [`Anchor`](crate::Anchor) takes about 50 nano seconds, so
175    /// try to reuse it for a batch of `Instant`.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use std::time::UNIX_EPOCH;
181    /// use minstant::{Instant, Anchor};
182    ///
183    /// let anchor = Anchor::new();
184    /// let instant = Instant::now();
185    ///
186    /// let expected = UNIX_EPOCH.elapsed().unwrap().as_nanos();
187    /// assert!((instant.as_unix_nanos(&anchor) as i64 - expected as i64).abs() < 1_000_000);
188    /// ```
189    pub fn as_unix_nanos(&self, anchor: &Anchor) -> u64 {
190        if self.0 > anchor.cycle {
191            let forward_ns = ((self.0 - anchor.cycle) as f64 * tsc::nanos_per_cycle()) as u64;
192            anchor.unix_time_ns + forward_ns
193        } else {
194            let backward_ns = ((anchor.cycle - self.0) as f64 * tsc::nanos_per_cycle()) as u64;
195            anchor.unix_time_ns - backward_ns
196        }
197    }
198}
199
200impl Add<Duration> for Instant {
201    type Output = Instant;
202
203    #[inline]
204    fn add(self, other: Duration) -> Instant {
205        self.checked_add(other)
206            .expect("overflow when adding duration to instant")
207    }
208}
209
210impl AddAssign<Duration> for Instant {
211    #[inline]
212    fn add_assign(&mut self, other: Duration) {
213        *self = *self + other;
214    }
215}
216
217impl Sub<Duration> for Instant {
218    type Output = Instant;
219
220    #[inline]
221    fn sub(self, other: Duration) -> Instant {
222        self.checked_sub(other)
223            .expect("overflow when subtracting duration from instant")
224    }
225}
226
227impl SubAssign<Duration> for Instant {
228    #[inline]
229    fn sub_assign(&mut self, other: Duration) {
230        *self = *self - other;
231    }
232}
233
234impl Sub<Instant> for Instant {
235    type Output = Duration;
236
237    /// Returns the amount of time elapsed from another instant to this one,
238    /// or zero duration if that instant is later than this one.
239    ///
240    /// # Panics
241    ///
242    /// Previously we panicked if `other` was later than `self`. Currently this method saturates
243    /// to follow the behavior of the standard library. Future versions may reintroduce the panic
244    /// in some circumstances.
245    #[inline]
246    fn sub(self, other: Instant) -> Duration {
247        self.duration_since(other)
248    }
249}
250
251impl std::fmt::Debug for Instant {
252    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253        self.0.fmt(f)
254    }
255}
256
257/// An anchor which can be used to convert internal clocking counter into system timestamp.
258///
259/// *[See also the `Instant::as_unix_nanos()`](crate::Instant::as_unix_nanos).*
260#[derive(Copy, Clone)]
261pub struct Anchor {
262    unix_time_ns: u64,
263    cycle: u64,
264}
265
266impl Default for Anchor {
267    fn default() -> Self {
268        Self::new()
269    }
270}
271
272impl Anchor {
273    pub fn new() -> Anchor {
274        let unix_time_ns = SystemTime::now()
275            .duration_since(UNIX_EPOCH)
276            .expect("unexpected time drift")
277            .as_nanos() as u64;
278        Anchor {
279            unix_time_ns,
280            cycle: tsc::tsc_from_ref(),
281        }
282    }
283}