trace_recorder_parser/
time.rs

1use derive_more::{
2    Add, AddAssign, Binary, Deref, Display, Into, LowerHex, MulAssign, Octal, Sub, Sum, UpperHex,
3};
4use std::ops;
5
6/// Frequency of the clock/timer/counter used as time base
7#[derive(
8    Copy,
9    Clone,
10    Eq,
11    PartialEq,
12    Ord,
13    PartialOrd,
14    Hash,
15    Debug,
16    Display,
17    Deref,
18    Into,
19    Binary,
20    Octal,
21    LowerHex,
22    UpperHex,
23    Add,
24    Sum,
25    AddAssign,
26    MulAssign,
27)]
28#[display(fmt = "{_0}")]
29pub struct Frequency(pub(crate) u32);
30
31impl Frequency {
32    pub fn is_unitless(&self) -> bool {
33        self.0 == 0
34    }
35
36    pub fn get_raw(&self) -> u32 {
37        self.0
38    }
39}
40
41#[derive(
42    Copy,
43    Clone,
44    Eq,
45    PartialEq,
46    Ord,
47    PartialOrd,
48    Hash,
49    Debug,
50    Display,
51    Binary,
52    Octal,
53    LowerHex,
54    UpperHex,
55    Add,
56    Sub,
57    Sum,
58    AddAssign,
59    MulAssign,
60    Into,
61)]
62#[display(fmt = "{_0}")]
63pub struct Ticks(pub(crate) u32);
64
65impl Ticks {
66    pub const fn zero() -> Self {
67        Self(0)
68    }
69
70    pub const fn get_raw(&self) -> u32 {
71        self.0
72    }
73
74    pub fn new(ticks: u32) -> Self {
75        Self(ticks)
76    }
77}
78
79/// Timestamp (in ticks).
80/// Stores accumulated differential timestamps in snapshot mode and device timer instant
81/// in streaming mode.
82///
83/// Note that in streaming mode this can rollover. `StreamingInstant` can be used to
84/// track the rollovers.
85#[derive(
86    Copy,
87    Clone,
88    Eq,
89    PartialEq,
90    Ord,
91    PartialOrd,
92    Hash,
93    Debug,
94    Display,
95    Binary,
96    Octal,
97    LowerHex,
98    UpperHex,
99    Add,
100    Sub,
101    Sum,
102    AddAssign,
103    MulAssign,
104    Into,
105)]
106#[display(fmt = "{_0}")]
107pub struct Timestamp(pub(crate) u64);
108
109impl Timestamp {
110    pub const fn zero() -> Self {
111        Self(0)
112    }
113
114    pub const fn get_raw(&self) -> u64 {
115        self.0
116    }
117
118    pub const fn ticks(&self) -> u64 {
119        self.get_raw()
120    }
121}
122
123impl From<Ticks> for Timestamp {
124    fn from(t: Ticks) -> Self {
125        Timestamp(t.0.into())
126    }
127}
128
129impl ops::Add<DifferentialTimestamp> for Timestamp {
130    type Output = Timestamp;
131
132    fn add(self, dt: DifferentialTimestamp) -> Timestamp {
133        Timestamp(
134            self.0
135                .checked_add(u64::from(dt.0))
136                .expect("Overflow when adding differential time to timestamp"),
137        )
138    }
139}
140
141impl ops::AddAssign<DifferentialTimestamp> for Timestamp {
142    fn add_assign(&mut self, dt: DifferentialTimestamp) {
143        self.0 = self
144            .0
145            .checked_add(u64::from(dt.0))
146            .expect("Overflow when adding differential time to timestamp")
147    }
148}
149
150/// Time (in ticks) since the previous event in the recorder log.
151/// Can be up to 4 bytes in size, depending on how many DTS bytes are
152/// available in the event at hand and how much time has elapsed since
153/// the previous event.
154#[derive(
155    Copy,
156    Clone,
157    Eq,
158    PartialEq,
159    Ord,
160    PartialOrd,
161    Hash,
162    Debug,
163    Display,
164    Binary,
165    Octal,
166    LowerHex,
167    UpperHex,
168    Add,
169    Sum,
170    AddAssign,
171    MulAssign,
172)]
173#[display(fmt = "{_0}")]
174pub struct DifferentialTimestamp(pub(crate) u32);
175
176impl DifferentialTimestamp {
177    pub fn ticks(&self) -> Ticks {
178        Ticks(self.0)
179    }
180}
181
182impl DifferentialTimestamp {
183    /// Construct a differential timestamp from the data of an XTS8 event.
184    /// XTS8 events contain the upper 3 bytes, and the event following contains
185    /// the lower byte.
186    pub(crate) fn from_xts8(xts_8: u8, xts_16: u16) -> Self {
187        DifferentialTimestamp(u32::from(xts_8) << 24 | (u32::from(xts_16) << 8))
188    }
189
190    /// Construct a differential timestamp from the data of an XTS16 event.
191    /// XTS16 events contain the upper 2 bytes, and the event following contains
192    /// the lower 2 bytes.
193    pub(crate) fn from_xts16(xts_16: u16) -> Self {
194        DifferentialTimestamp(u32::from(xts_16) << 16)
195    }
196
197    pub const fn zero() -> Self {
198        Self(0)
199    }
200
201    pub fn clear(&mut self) {
202        self.0 = 0;
203    }
204}
205
206impl ops::AddAssign<Dts8> for DifferentialTimestamp {
207    fn add_assign(&mut self, dts: Dts8) {
208        self.0 = self
209            .0
210            .checked_add(u32::from(dts.0))
211            .expect("Overflow when adding DTS8 to differential time")
212    }
213}
214
215impl ops::AddAssign<Dts16> for DifferentialTimestamp {
216    fn add_assign(&mut self, dts: Dts16) {
217        self.0 = self
218            .0
219            .checked_add(u32::from(dts.0))
220            .expect("Overflow when adding DTS16 to differential time")
221    }
222}
223
224/// The lower 8-bit portion of a differential timestamp recorded in an event
225#[derive(
226    Copy,
227    Clone,
228    Eq,
229    PartialEq,
230    Ord,
231    PartialOrd,
232    Hash,
233    Debug,
234    Into,
235    Display,
236    Binary,
237    Octal,
238    LowerHex,
239    UpperHex,
240)]
241#[display(fmt = "{_0}")]
242pub struct Dts8(pub(crate) u8);
243
244/// The lower 16-bit portion of a differential timestamp recorded in an event
245#[derive(
246    Copy,
247    Clone,
248    Eq,
249    PartialEq,
250    Ord,
251    PartialOrd,
252    Hash,
253    Debug,
254    Into,
255    Display,
256    Binary,
257    Octal,
258    LowerHex,
259    UpperHex,
260)]
261#[display(fmt = "{_0}")]
262pub struct Dts16(pub(crate) u16);
263
264/// A monotonic clock measurement in ticks for tracking rollovers
265/// of streaming protocol timestamps.
266#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display)]
267#[display(fmt = "{}", "self.to_timestamp()")]
268pub struct StreamingInstant {
269    lower: u32,
270    upper: u32,
271}
272
273impl StreamingInstant {
274    pub const fn zero() -> Self {
275        Self { lower: 0, upper: 0 }
276    }
277
278    pub const fn new(lower: u32, upper: u32) -> Self {
279        Self { lower, upper }
280    }
281
282    pub const fn from_initial_value(initial_value: u64) -> Self {
283        Self {
284            lower: initial_value as u32,
285            upper: (initial_value >> 32) as u32,
286        }
287    }
288
289    pub fn elapsed(&mut self, now: Timestamp) -> Timestamp {
290        // Streaming protocol timestamps are always 32 bits
291        let now = now.0 as u32;
292
293        // Check for rollover on the lower
294        if now < self.lower {
295            self.upper += 1;
296        }
297
298        self.lower = now;
299
300        self.to_timestamp()
301    }
302
303    pub fn to_timestamp(&self) -> Timestamp {
304        Timestamp(u64::from(self.upper) << 32 | u64::from(self.lower))
305    }
306}
307
308#[cfg(test)]
309mod test {
310    use super::*;
311
312    #[test]
313    fn differential_time_xts16() {
314        let mut accumulated_time = Timestamp::zero();
315        accumulated_time.0 += 0x0F;
316        assert_eq!(accumulated_time.ticks(), 0x0F);
317
318        let xts_16 = 0x00_03;
319        let mut dts_for_next_event = DifferentialTimestamp::from_xts16(xts_16);
320        assert_eq!(dts_for_next_event.ticks().0, 0x00_03_00_00);
321
322        let dts = Dts16(0x5F_D5);
323        dts_for_next_event += dts;
324        assert_eq!(dts_for_next_event.ticks().0, 0x00_03_5F_D5);
325
326        accumulated_time += dts_for_next_event;
327        assert_eq!(accumulated_time.ticks(), 0x00_03_5F_D5 + 0x0F);
328    }
329
330    #[test]
331    fn differential_time_xts8() {
332        let mut accumulated_time = Timestamp::zero();
333        accumulated_time.0 += 0x0F;
334        assert_eq!(accumulated_time.ticks(), 0x0F);
335
336        let xts_16 = 0x11_22;
337        let xts_8 = 0xE1;
338        let mut dts_for_next_event = DifferentialTimestamp::from_xts8(xts_8, xts_16);
339        assert_eq!(dts_for_next_event.ticks().0, 0xE1_11_22_00);
340
341        let dts = Dts8(0x33);
342        dts_for_next_event += dts;
343        assert_eq!(dts_for_next_event.ticks().0, 0xE1_11_22_33);
344
345        accumulated_time += dts_for_next_event;
346        assert_eq!(accumulated_time.ticks(), 0xE1_11_22_33 + 0x0F);
347    }
348
349    #[test]
350    fn streaming_instant_rollover() {
351        // 5 ms before rollover
352        let t0 = Timestamp(4_294_967_290);
353
354        // 10 ms after rollover
355        let t1 = Timestamp(10);
356
357        let mut instant = StreamingInstant::zero();
358        assert_eq!(instant.elapsed(t0), t0);
359
360        let t2 = instant.elapsed(t1);
361        assert_eq!(t0.ticks() + 16, t2.ticks());
362    }
363
364    #[test]
365    fn streaming_instant_construction() {
366        let mut t = StreamingInstant::from_initial_value(u64::from(u32::MAX) + 1);
367        assert_eq!(t.lower, 0);
368        assert_eq!(t.upper, 1);
369        let t0 = Timestamp(2);
370        let instant = t.elapsed(t0);
371        assert_eq!(t.lower, 2);
372        assert_eq!(t.upper, 1);
373        assert_eq!(instant.0, u64::from(u32::MAX) + 3);
374    }
375}