rustmeter_beacon_core/
time_delta.rs1#![allow(unused)] use arbitrary_int::traits::Integer;
3
4use crate::{
5 buffer::{BufferReader, BufferWriter},
6 protocol::{EventPayload, TypeDefinitionPayload},
7 tracing::{ReadTracingError, write_tracing_event},
8};
9
10#[cfg(not(feature = "multicore"))]
11static LAST_TIMESTAMP: [portable_atomic::AtomicU32; 1] = [portable_atomic::AtomicU32::new(0)];
12#[cfg(feature = "multicore")]
13static LAST_TIMESTAMP: [portable_atomic::AtomicU32; 2] = [
14 portable_atomic::AtomicU32::new(0),
15 portable_atomic::AtomicU32::new(0),
16];
17
18pub static CORE_CLOCK_REFERENCED: [portable_atomic::AtomicBool; 2] = [
21 portable_atomic::AtomicBool::new(false),
22 portable_atomic::AtomicBool::new(false),
23];
24static PREINIT_CLOCK_RUN: [portable_atomic::AtomicBool; 2] = [
27 portable_atomic::AtomicBool::new(false),
28 portable_atomic::AtomicBool::new(false),
29];
30
31#[inline(always)]
32fn do_core_clock_referencing(core_id: usize) {
33 CORE_CLOCK_REFERENCED[core_id].store(true, portable_atomic::Ordering::Relaxed);
34
35 critical_section::with(|_| {
41 #[cfg(not(feature = "std"))]
43 unsafe {
44 if !PREINIT_CLOCK_RUN[core_id].load(portable_atomic::Ordering::Relaxed) {
45 PREINIT_CLOCK_RUN[core_id].store(true, portable_atomic::Ordering::Relaxed);
46 preinit_clock_reference();
47 }
48 };
49
50 let cpu_ticks = unsafe { get_tracing_raw_ticks() };
52 let systimer_us = unsafe { get_system_time_us() };
53 write_tracing_event(EventPayload::TypeDefinition(
54 TypeDefinitionPayload::CoreClockReference {
55 core_id: core_id as u8,
56 systimer_us,
57 cpu_ticks,
58 },
59 ));
60 });
61}
62
63unsafe extern "Rust" {
64 pub fn preinit_clock_reference();
71
72 pub fn get_tracing_raw_ticks() -> u32;
75
76 pub fn get_system_time_us() -> u64;
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct TimeDelta {
81 delta: u32,
82}
83
84impl TimeDelta {
85 #[inline(always)]
87 #[cfg(not(test))]
88 pub fn from_now() -> Self {
89 let core_id = unsafe { crate::get_current_core_id() as usize };
90 if !CORE_CLOCK_REFERENCED[core_id].load(portable_atomic::Ordering::Relaxed) {
91 do_core_clock_referencing(core_id);
92 }
93
94 let now = unsafe { get_tracing_raw_ticks() };
96 let last = LAST_TIMESTAMP[core_id].swap(now, portable_atomic::Ordering::Relaxed);
97
98 if now < last {
99 let last_till_end = arbitrary_int::u26::MAX.as_u32() - last;
101 return TimeDelta {
102 delta: last_till_end + now,
103 };
104 } else {
105 TimeDelta { delta: now - last }
106 }
107 }
108
109 #[cfg(test)]
110 pub fn from_now() -> Self {
111 let now = unsafe { get_tracing_raw_ticks() };
112 TimeDelta { delta: now }
113 }
114
115 #[inline(always)]
117 pub const fn is_extended(&self) -> bool {
118 self.delta >= 2u32.pow(15)
119 }
120
121 pub fn write_bytes(&self, writer: &mut BufferWriter) {
125 if self.is_extended() {
126 let capped_delta = if self.delta > (2u32.pow(31) - 1) {
128 2u32.pow(31) - 1
129 } else {
130 self.delta
131 };
132
133 let extended_value = capped_delta | 0x8000_0000; writer.write_bytes(&extended_value.to_be_bytes());
136 } else {
137 let single_value = (self.delta & 0x7FFF) as u16; writer.write_bytes(&single_value.to_be_bytes());
140 }
141 }
142
143 #[inline(always)]
144 pub fn write_bytes_mut(&self, writer: &mut [u8]) -> usize {
145 if self.is_extended() {
146 let capped_delta = if self.delta > (2u32.pow(31) - 1) {
148 2u32.pow(31) - 1
149 } else {
150 self.delta
151 };
152
153 let extended_value = capped_delta | 0x8000_0000; let bytes = extended_value.to_be_bytes();
156 writer[..4].copy_from_slice(&bytes);
157 4
158 } else {
159 let single_value = self.delta as u16;
161 let bytes = single_value.to_be_bytes();
162 writer[..2].copy_from_slice(&bytes);
163 2
164 }
165 }
166
167 pub fn read_bytes(reader: &mut BufferReader) -> Result<Self, ReadTracingError> {
171 let first_byte = reader.read_byte()?;
173 let second_byte = reader.read_byte()?;
174
175 if (first_byte & 0x80) == 0 {
176 let delta = u16::from_be_bytes([first_byte, second_byte]) as u32;
178 Ok(TimeDelta { delta })
179 } else {
180 let next_two_bytes = reader.read_bytes(2)?;
182 let extended_value = u32::from_be_bytes([
183 first_byte,
184 second_byte,
185 next_two_bytes[0],
186 next_two_bytes[1],
187 ]);
188 let delta = extended_value & 0x7FFF_FFFF; Ok(TimeDelta { delta })
190 }
191 }
192
193 pub fn delta(&self) -> u32 {
195 self.delta
196 }
197}
198
199#[cfg(all(feature = "std", not(test)))]
200mod std_time {
201 #[unsafe(no_mangle)]
202 unsafe fn get_tracing_raw_ticks() -> u32 {
203 use std::time::{SystemTime, UNIX_EPOCH};
204
205 let now = SystemTime::now()
206 .duration_since(UNIX_EPOCH)
207 .expect("Time went backwards");
208 now.as_micros() as u32
209 }
210
211 #[unsafe(no_mangle)]
212 unsafe fn get_system_time_us() -> u64 {
213 use std::time::{SystemTime, UNIX_EPOCH};
214
215 let now = SystemTime::now()
216 .duration_since(UNIX_EPOCH)
217 .expect("Time went backwards");
218 now.as_micros() as u64
219 }
220}
221
222#[cfg(test)]
223mod tests {
224
225 use super::*;
226 use crate::buffer::BufferWriter;
227
228 #[test]
229 fn test_time_delta_read_and_write_exponents() {
230 for exponent in 0..=32 {
232 let delta = (2u64.pow(exponent) - 1) as u32; let time_delta = TimeDelta { delta };
234
235 let mut writer = BufferWriter::new();
237 time_delta.write_bytes(&mut writer);
238 let written_bytes = writer.as_slice();
239
240 if exponent <= 15 {
241 assert_eq!(
243 written_bytes.len(),
244 2,
245 "Expected 2 bytes for delta {}",
246 delta
247 );
248 } else {
249 assert_eq!(
251 written_bytes.len(),
252 4,
253 "Expected 4 bytes for delta {}",
254 delta
255 );
256 }
257
258 let mut reader = BufferReader::new(written_bytes);
260 let read_time_delta =
261 TimeDelta::read_bytes(&mut reader).expect("Failed to read TimeDelta");
262
263 let expected_delta = delta.min(2u32.pow(31) - 1);
265
266 assert_eq!(
267 expected_delta, read_time_delta.delta,
268 "Mismatch for delta {}",
269 delta
270 );
271 }
272 }
273
274 #[test]
275 fn test_time_delta_read_and_write_specials() {
276 let deltas = [
277 (0u32, 2),
278 (1u32, 2),
279 (2u32.pow(15) - 1, 2),
280 (2u32.pow(15), 4),
281 (2u32.pow(15) + 1, 4),
282 (2u32.pow(16), 4),
283 (2u32.pow(31) - 1, 4),
284 (2u32.pow(31), 4),
285 ];
286
287 for (delta, byte_size) in &deltas {
288 let time_delta = TimeDelta { delta: *delta };
289
290 let mut writer = BufferWriter::new();
292 time_delta.write_bytes(&mut writer);
293 let written_bytes = writer.as_slice();
294
295 assert_eq!(
296 written_bytes.len(),
297 *byte_size,
298 "Expected {} bytes for delta {}",
299 byte_size,
300 delta
301 );
302
303 let mut reader = BufferReader::new(written_bytes);
305 let read_time_delta =
306 TimeDelta::read_bytes(&mut reader).expect("Failed to read TimeDelta");
307
308 let expected_delta = (*delta).min(2u32.pow(31) - 1);
310
311 assert_eq!(
312 expected_delta, read_time_delta.delta,
313 "Mismatch for delta {}",
314 delta
315 );
316 }
317 }
318}