1use std::time::Instant;
2
3use crate::time::{fence, FineDuration, Timer, TimerKind};
4
5mod tsc;
6
7pub(crate) use tsc::*;
8
9/// A measurement timestamp.
10#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub(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
19impl 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)]
50pub(crate) union UntaggedTimestamp {
51 /// [`Timestamp::Os`].
52 pub os: Instant,
53
54 /// [`Timestamp::Tsc`].
55 pub tsc: TscTimestamp,
56}
57
58impl 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