1 | use std::time::Instant; |
2 | |
3 | use crate::time::{fence, FineDuration, Timer, TimerKind}; |
4 | |
5 | mod tsc; |
6 | |
7 | pub(crate) use tsc::*; |
8 | |
9 | /// A measurement timestamp. |
10 | #[derive (Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] |
11 | pub(crate) enum Timestamp { |
12 | /// Time provided by the operating system. |
13 | Os(Instant), |
14 | |
15 | /// [CPU timestamp counter](https://en.wikipedia.org/wiki/Time_Stamp_Counter). |
16 | Tsc(TscTimestamp), |
17 | } |
18 | |
19 | impl Timestamp { |
20 | #[inline (always)] |
21 | pub fn start(timer_kind: TimerKind) -> Self { |
22 | fence::full_fence(); |
23 | let value: Timestamp = match timer_kind { |
24 | TimerKind::Os => Self::Os(Instant::now()), |
25 | TimerKind::Tsc => Self::Tsc(TscTimestamp::start()), |
26 | }; |
27 | fence::compiler_fence(); |
28 | value |
29 | } |
30 | |
31 | pub fn duration_since(self, earlier: Self, timer: Timer) -> FineDuration { |
32 | match (self, earlier, timer) { |
33 | (Self::Os(this: Instant), Self::Os(earlier: Instant), Timer::Os) => this.duration_since(earlier).into(), |
34 | (Self::Tsc(this: TscTimestamp), Self::Tsc(earlier: TscTimestamp), Timer::Tsc { frequency: NonZero }) => { |
35 | this.duration_since(earlier, frequency) |
36 | } |
37 | _ => unreachable!(), |
38 | } |
39 | } |
40 | } |
41 | |
42 | /// A [`Timestamp`] where the variant is determined by an external source of |
43 | /// truth. |
44 | /// |
45 | /// By making the variant tag external to this type, we produce more optimized |
46 | /// code by: |
47 | /// - Reusing the same condition variable |
48 | /// - Reducing the size of the timestamp variables |
49 | #[derive (Clone, Copy)] |
50 | pub(crate) union UntaggedTimestamp { |
51 | /// [`Timestamp::Os`]. |
52 | pub os: Instant, |
53 | |
54 | /// [`Timestamp::Tsc`]. |
55 | pub tsc: TscTimestamp, |
56 | } |
57 | |
58 | impl UntaggedTimestamp { |
59 | #[inline (always)] |
60 | pub fn start(timer_kind: TimerKind) -> Self { |
61 | fence::full_fence(); |
62 | let value = match timer_kind { |
63 | TimerKind::Os => Self { os: Instant::now() }, |
64 | TimerKind::Tsc => Self { tsc: TscTimestamp::start() }, |
65 | }; |
66 | fence::compiler_fence(); |
67 | value |
68 | } |
69 | |
70 | #[inline (always)] |
71 | pub fn end(timer_kind: TimerKind) -> Self { |
72 | fence::compiler_fence(); |
73 | let value = match timer_kind { |
74 | TimerKind::Os => Self { os: Instant::now() }, |
75 | TimerKind::Tsc => Self { tsc: TscTimestamp::end() }, |
76 | }; |
77 | fence::full_fence(); |
78 | value |
79 | } |
80 | |
81 | #[inline (always)] |
82 | pub unsafe fn into_timestamp(self, timer_kind: TimerKind) -> Timestamp { |
83 | match timer_kind { |
84 | TimerKind::Os => Timestamp::Os(self.os), |
85 | TimerKind::Tsc => Timestamp::Tsc(self.tsc), |
86 | } |
87 | } |
88 | } |
89 | |