kernel_api/time.rs
1//! Temporal quantification.
2//!
3//! # Examples
4//!
5//! Using [`Instant`] to calculate how long a function took to run:
6//!
7//! ```ignore (incomplete)
8//! # use kernel_api::time::Instant;
9//! let now = Instant::now();
10//!
11//! // Calling a slow function, it may take a while
12//! slow_function();
13//!
14//! let elapsed_time = now.elapsed();
15//! println!("Running slow_function() took {} seconds.", elapsed_time.as_secs());
16//! ```
17
18use core::ops::{Add, AddAssign, Sub, SubAssign};
19use core::time::Duration;
20
21/// A measurement of the current system time.
22/// Opaque and useful only with [`Duration`].
23///
24/// Instants are opaque types that should usually only be compared to one another.
25/// [`get()`] can be used to get the internal value, but no guarantees are made about
26/// the meaning of the value. The meaning of the result of `get()` varies by system
27/// and may even change at runtime during a single boot. A best-attempt value of the
28/// time since system boot can be retrieved with [`nanos_since_boot()`].
29///
30/// The size of an `Instant` struct may vary depending on the target platform.
31///
32/// Example:
33///
34/// ```compile_fail (incomplete)
35/// use core::time::Duration;
36/// use kernel_api::time::Instant;
37/// use kernel_api::threading::sleep;
38/// use kernel_api::executor::block_on;
39///
40/// fn main() {
41/// let now = Instant::now();
42///
43/// // we sleep for 2 seconds
44/// block_on(sleep(Duration::new(2, 0)));
45/// // it prints '2'
46/// sprintln!("{}", now.elapsed().as_secs());
47/// }
48/// ```
49///
50/// # Underlying system
51///
52/// The following mechanisms are currently being used by `now()` to find out
53/// the current time:
54///
55/// | Platform | Mechanism |
56/// |----------|---------------------|
57/// | `x86_64` | `rdtsc` instruction |
58///
59/// <div class="warning">
60/// These mechanisms might change over time.
61/// </div>
62///
63/// > Note: mathematical operations like [`add()`](`Instant::add`) may panic if the underlying
64/// > structure cannot represent the new point in time.
65#[derive(Copy, Clone, Hash, Debug, Ord, PartialOrd, Eq, PartialEq)]
66pub struct Instant {
67 arch_val: u128
68}
69
70impl Instant {
71 fn nanos(&self) -> u128 {
72 Self::arch_to_nanos(self.arch_val)
73 }
74
75 fn arch_to_nanos(arch_val: u128) -> u128 {
76 let (num, denom) = crate::bridge::time::system_time_to_nanos();
77
78 arch_val * num / denom.get()
79 }
80
81 fn nanos_to_arch(nanos: u128) -> u128 {
82 let (num, denom) = crate::bridge::time::system_time_to_nanos();
83
84 nanos * denom.get() / num
85 }
86
87 /// The current system time.
88 ///
89 /// # Examples
90 ///
91 /// ```
92 /// use kernel_api::time::Instant;
93 ///
94 /// let now = Instant::now();
95 /// ```
96 #[must_use]
97 pub fn now() -> Self {
98 let arch_val = crate::bridge::time::system_time();
99 Self {
100 arch_val
101 }
102 }
103
104 /// Returns the amount of time elapsed from another instant to this one.
105 ///
106 /// # Panics
107 ///
108 /// This method may panic if `self` is earlier than `earlier`.
109 ///
110 /// # Examples
111 ///
112 /// ```compile_fail (incomplete)
113 /// use core::time::Duration;
114 /// use kernel_api::time::Instant;
115 /// use kernel_api::threading::sleep;
116 /// use kernel_api::executor::block_on;
117 ///
118 /// let now = Instant::now();
119 /// block_on(sleep(Duration::new(1, 0)));
120 /// let new_now = Instant::now();
121 /// sprintln!("{:?}", new_now.duration_since(now));
122 /// ```
123 #[must_use = "this returns the result of the operation, without modifying the original"]
124 pub fn duration_since(&self, earlier: Self) -> Duration {
125 self.saturating_duration_since(earlier)
126 }
127
128 /// Returns the amount of time elapsed from another instant to this one,
129 /// or None if that instant is later than this one.
130 ///
131 /// # Examples
132 ///
133 /// ```compile_fail (incomplete)
134 /// use core::time::Duration;
135 /// use kernel_api::time::Instant;
136 /// use kernel_api::threading::sleep;
137 /// use kernel_api::executor::block_on;
138 ///
139 /// let now = Instant::now();
140 /// block_on(sleep(Duration::new(1, 0)));
141 /// let new_now = Instant::now();
142 /// sprintln!("{:?}", new_now.checked_duration_since(now));
143 /// sprintln!("{:?}", now.checked_duration_since(new_now)); // None
144 /// ```
145 #[must_use = "this returns the result of the operation, without modifying the original"]
146 pub fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
147 let nanos = self.nanos().checked_sub(earlier.nanos())?;
148 Some(Duration::new(
149 (nanos / 1_000_000_000) as u64,
150 (nanos % 1_000_000_000) as u32
151 ))
152 }
153
154 /// Returns the amount of time elapsed from another instant to this one,
155 /// or zero duration if that instant is later than this one.
156 ///
157 /// # Examples
158 ///
159 /// ```compile_fail (incomplete)
160 /// use core::time::Duration;
161 /// use kernel_api::time::Instant;
162 /// use kernel_api::threading::sleep;
163 /// use kernel_api::executor::block_on;
164 ///
165 /// let now = Instant::now();
166 /// block_on(sleep(Duration::new(1, 0)));
167 /// let new_now = Instant::now();
168 /// sprintln!("{:?}", new_now.saturating_duration_since(now));
169 /// sprintln!("{:?}", now.saturating_duration_since(new_now)); // 0ns
170 /// ```
171 #[must_use = "this returns the result of the operation, without modifying the original"]
172 pub fn saturating_duration_since(&self, earlier: Self) -> Duration {
173 let nanos = self.nanos().saturating_sub(earlier.nanos());
174 Duration::new(
175 (nanos / 1_000_000_000) as u64,
176 (nanos % 1_000_000_000) as u32
177 )
178 }
179
180 /// Returns the amount of time elapsed since this instant.
181 ///
182 /// # Panics
183 ///
184 /// This method may panic if the current time is earlier than `self`.
185 ///
186 /// # Examples
187 ///
188 /// ```compile_fail (incomplete)
189 /// use core::time::Duration;
190 /// use kernel_api::time::Instant;
191 /// use kernel_api::threading::sleep;
192 /// use kernel_api::executor::block_on;
193 ///
194 /// let instant = Instant::now();
195 /// let three_secs = Duration::from_secs(3);
196 /// block_on(sleep(three_secs));
197 /// assert!(instant.elapsed() >= three_secs);
198 /// ```
199 #[must_use = "this returns the result of the operation, without modifying the original"]
200 pub fn elapsed(&self) -> Duration {
201 Self::now() - *self
202 }
203
204 /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
205 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
206 /// otherwise.
207 #[must_use = "this returns the result of the operation, without modifying the original"]
208 pub fn checked_add(&self, duration: Duration) -> Option<Self> {
209 let arch_val = self.arch_val.checked_add(Self::nanos_to_arch(duration.as_nanos()))?;
210 Some(Self { arch_val })
211 }
212
213 /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
214 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
215 /// otherwise.
216 #[must_use = "this returns the result of the operation, without modifying the original"]
217 pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
218 let arch_val = self.arch_val.checked_sub(Self::nanos_to_arch(duration.as_nanos()))?;
219 Some(Self { arch_val })
220 }
221
222 /// The number of nanoseconds since the system booted.
223 ///
224 /// No guarantees are provided on time before overflow.
225 #[must_use]
226 pub fn nanos_since_boot(&self) -> u128 {
227 self.nanos()
228 }
229
230 /// Returns the opaque numeric value of the instant.
231 ///
232 /// The meaning of the returned value is architecture dependant, see the
233 /// [struct level documentation](`Instant#underlying-system`) for more information.
234 #[must_use]
235 pub const fn get(&self) -> u128 { self.arch_val }
236}
237
238impl Add<Duration> for Instant {
239 type Output = Self;
240
241 /// # Panics
242 ///
243 /// This function may panic if the resulting point in time cannot be represented by the
244 /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
245 #[track_caller]
246 fn add(self, rhs: Duration) -> Self::Output {
247 Self { arch_val: self.arch_val + Self::nanos_to_arch(rhs.as_nanos()) }
248 }
249}
250
251impl AddAssign<Duration> for Instant {
252 fn add_assign(&mut self, rhs: Duration) {
253 self.arch_val += Self::nanos_to_arch(rhs.as_nanos());
254 }
255}
256
257impl Sub for Instant {
258 type Output = Duration;
259
260 fn sub(self, rhs: Self) -> Self::Output {
261 self.duration_since(rhs)
262 }
263}
264
265impl Sub<Duration> for Instant {
266 type Output = Self;
267
268 /// # Panics
269 ///
270 /// This function may panic if the resulting point in time cannot be represented by the
271 /// underlying data structure. See [`Instant::checked_sub`] for a version without panic.
272 #[track_caller]
273 fn sub(self, rhs: Duration) -> Self::Output {
274 Self { arch_val: self.arch_val - Self::nanos_to_arch(rhs.as_nanos()) }
275 }
276}
277
278impl SubAssign<Duration> for Instant {
279 fn sub_assign(&mut self, rhs: Duration) {
280 self.arch_val -= Self::nanos_to_arch(rhs.as_nanos());
281 }
282}