base/
cross_process_instant.rs1use std::ops::{Add, Sub};
15
16use malloc_size_of_derive::MallocSizeOf;
17use serde::{Deserialize, Serialize};
18use time::Duration;
19
20#[derive(
26 Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
27)]
28pub struct CrossProcessInstant {
29 value: u64,
30}
31
32impl CrossProcessInstant {
33 pub fn now() -> Self {
34 Self {
35 value: platform::now(),
36 }
37 }
38
39 pub fn epoch() -> Self {
42 Self { value: 0 }
43 }
44}
45
46impl Sub for CrossProcessInstant {
47 type Output = Duration;
48
49 fn sub(self, rhs: Self) -> Self::Output {
50 Duration::nanoseconds(self.value as i64 - rhs.value as i64)
51 }
52}
53
54impl Add<Duration> for CrossProcessInstant {
55 type Output = Self;
56
57 fn add(self, rhs: Duration) -> Self::Output {
58 Self {
59 value: self.value + rhs.whole_nanoseconds() as u64,
60 }
61 }
62}
63
64impl Sub<Duration> for CrossProcessInstant {
65 type Output = Self;
66
67 fn sub(self, rhs: Duration) -> Self::Output {
68 Self {
69 value: self.value - rhs.whole_nanoseconds() as u64,
70 }
71 }
72}
73
74#[cfg(all(unix, not(any(target_os = "macos", target_os = "ios"))))]
75mod platform {
76 use libc::timespec;
77
78 #[allow(unsafe_code)]
79 pub(super) fn now() -> u64 {
80 let time = unsafe {
82 let mut time: timespec = std::mem::zeroed();
83 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut time);
84 time
85 };
86 (time.tv_sec as u64) * 1000000000 + (time.tv_nsec as u64)
87 }
88}
89
90#[cfg(any(target_os = "macos", target_os = "ios"))]
91mod platform {
92 use std::sync::LazyLock;
93
94 use mach2::mach_time::{mach_absolute_time, mach_timebase_info};
95
96 #[allow(unsafe_code)]
97 fn timebase_info() -> &'static mach_timebase_info {
98 static TIMEBASE_INFO: LazyLock<mach_timebase_info> = LazyLock::new(|| {
99 let mut timebase_info = mach_timebase_info { numer: 0, denom: 0 };
100 unsafe { mach_timebase_info(&mut timebase_info) };
101 timebase_info
102 });
103 &TIMEBASE_INFO
104 }
105
106 #[allow(unsafe_code)]
107 pub(super) fn now() -> u64 {
108 let timebase_info = timebase_info();
109 let absolute_time = unsafe { mach_absolute_time() };
110 absolute_time * timebase_info.numer as u64 / timebase_info.denom as u64
111 }
112}
113
114#[cfg(target_os = "windows")]
115mod platform {
116 use std::sync::atomic::{AtomicU64, Ordering};
117
118 use windows_sys::Win32::System::Performance::{
119 QueryPerformanceCounter, QueryPerformanceFrequency,
120 };
121
122 #[allow(unsafe_code)]
126 fn frequency() -> i64 {
127 static FREQUENCY: AtomicU64 = AtomicU64::new(0);
132
133 let cached = FREQUENCY.load(Ordering::Relaxed);
134 if cached != 0 {
136 return cached as i64;
137 }
138 let mut frequency = 0;
140 let result = unsafe { QueryPerformanceFrequency(&mut frequency) };
141
142 if result == 0 {
143 return 0;
144 }
145
146 FREQUENCY.store(frequency as u64, Ordering::Relaxed);
147 frequency
148 }
149
150 #[allow(unsafe_code)]
151 pub(super) fn now() -> u64 {
154 let mut counter_value = 0;
155 unsafe { QueryPerformanceCounter(&mut counter_value) };
156
157 fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
162 let q = value / denom;
163 let r = value % denom;
164 q * numer + r * numer / denom
168 }
169
170 static NANOSECONDS_PER_SECOND: u64 = 1_000_000_000;
171 mul_div_u64(
172 counter_value as u64,
173 NANOSECONDS_PER_SECOND,
174 frequency() as u64,
175 )
176 }
177}