measureme_mirror/
raw_event.rs

1use crate::event_id::EventId;
2use crate::stringtable::StringId;
3#[cfg(target_endian = "big")]
4use std::convert::TryInto;
5
6/// `RawEvent` is how events are stored on-disk. If you change this struct,
7/// make sure that you increment `file_header::CURRENT_FILE_FORMAT_VERSION`.
8#[derive(Eq, PartialEq, Debug)]
9#[repr(C)]
10pub struct RawEvent {
11    pub event_kind: StringId,
12    pub event_id: EventId,
13    pub thread_id: u32,
14
15    // The following 96 bits store the payload values, using
16    // 48 bits for each.
17    // Interval:
18    // Payload 1 is start value and payload 2 is end value
19    // SSSSSSSSSSSSSSSSEEEEEEEEEEEEEEEESSSSSSSEEEEEEEEE
20    // [payload1_lower][payload2_lower][payloads_upper]
21    // Instant:
22    // Payload2 is 0xFFFF_FFFF_FFFF
23    // VVVVVVVVVVVVVVVV1111111111111111VVVVVVV11111111
24    // [payload1_lower][payload2_lower][payloads_upper]
25    // Integer:
26    // Payload2 is 0xFFFF_FFFF_FFFE
27    // VVVVVVVVVVVVVVVV1111111111111111VVVVVVV11111110
28    // [payload1_lower][payload2_lower][payloads_upper]
29    pub payload1_lower: u32,
30    pub payload2_lower: u32,
31    pub payloads_upper: u32,
32}
33
34/// `RawEvents` that have a payload 2 value with this value are instant events.
35const INSTANT_MARKER: u64 = 0xFFFF_FFFF_FFFF;
36/// `RawEvents` that have a payload 2 value with this value are integer events.
37const INTEGER_MARKER: u64 = INSTANT_MARKER - 1;
38
39/// The max value we can represent with the 48 bits available.
40pub const MAX_SINGLE_VALUE: u64 = 0xFFFF_FFFF_FFFF;
41
42/// The max value we can represent with the 48 bits available.
43/// The highest two values are reserved for the `INSTANT_MARKER` and `INTEGER_MARKER`.
44pub const MAX_INTERVAL_VALUE: u64 = INTEGER_MARKER - 1;
45
46impl RawEvent {
47    #[inline]
48    pub fn new_interval(
49        event_kind: StringId,
50        event_id: EventId,
51        thread_id: u32,
52        start: u64,
53        end: u64,
54    ) -> Self {
55        assert!(start <= end);
56        assert!(end <= MAX_INTERVAL_VALUE);
57
58        Self::pack_values(event_kind, event_id, thread_id, start, end)
59    }
60
61    #[inline]
62    pub fn new_instant(
63        event_kind: StringId,
64        event_id: EventId,
65        thread_id: u32,
66        instant: u64,
67    ) -> Self {
68        assert!(instant <= MAX_SINGLE_VALUE);
69        Self::pack_values(event_kind, event_id, thread_id, instant, INSTANT_MARKER)
70    }
71
72    #[inline]
73    pub fn new_integer(
74        event_kind: StringId,
75        event_id: EventId,
76        thread_id: u32,
77        value: u64,
78    ) -> Self {
79        assert!(value <= MAX_SINGLE_VALUE);
80        Self::pack_values(event_kind, event_id, thread_id, value, INTEGER_MARKER)
81    }
82
83    #[inline]
84    fn pack_values(
85        event_kind: StringId,
86        event_id: EventId,
87        thread_id: u32,
88        value1: u64,
89        value2: u64,
90    ) -> Self {
91        let payload1_lower = value1 as u32;
92        let payload2_lower = value2 as u32;
93
94        let value1_upper = (value1 >> 16) as u32 & 0xFFFF_0000;
95        let value2_upper = (value2 >> 32) as u32;
96
97        let payloads_upper = value1_upper | value2_upper;
98
99        Self {
100            event_kind,
101            event_id,
102            thread_id,
103            payload1_lower,
104            payload2_lower,
105            payloads_upper,
106        }
107    }
108
109    /// The start value assuming self is an interval
110    #[inline]
111    pub fn start_value(&self) -> u64 {
112        self.payload1_lower as u64 | (((self.payloads_upper & 0xFFFF_0000) as u64) << 16)
113    }
114
115    /// The end value assuming self is an interval
116    #[inline]
117    pub fn end_value(&self) -> u64 {
118        self.payload2_lower as u64 | (((self.payloads_upper & 0x0000_FFFF) as u64) << 32)
119    }
120
121    /// The value assuming self is an interval or integer.
122    #[inline]
123    pub fn value(&self) -> u64 {
124        self.payload1_lower as u64 | (((self.payloads_upper & 0xFFFF_0000) as u64) << 16)
125    }
126
127    #[inline]
128    pub fn is_instant(&self) -> bool {
129        self.end_value() == INSTANT_MARKER
130    }
131
132    #[inline]
133    pub fn is_integer(&self) -> bool {
134        self.end_value() == INTEGER_MARKER
135    }
136
137    #[inline]
138    pub fn serialize(&self, bytes: &mut [u8]) {
139        assert!(bytes.len() == std::mem::size_of::<RawEvent>());
140
141        #[cfg(target_endian = "little")]
142        {
143            let raw_event_bytes: &[u8] = unsafe {
144                std::slice::from_raw_parts(
145                    self as *const _ as *const u8,
146                    std::mem::size_of::<RawEvent>(),
147                )
148            };
149
150            bytes.copy_from_slice(raw_event_bytes);
151        }
152
153        #[cfg(target_endian = "big")]
154        {
155            // We always emit data as little endian, which we have to do
156            // manually on big endian targets.
157            bytes[0..8].copy_from_slice(&self.event_kind.as_u64().to_le_bytes());
158            bytes[8..16].copy_from_slice(&self.event_id.as_u64().to_le_bytes());
159            bytes[16..20].copy_from_slice(&self.thread_id.to_le_bytes());
160            bytes[20..24].copy_from_slice(&self.payload1_lower.to_le_bytes());
161            bytes[24..28].copy_from_slice(&self.payload2_lower.to_le_bytes());
162            bytes[28..32].copy_from_slice(&self.payloads_upper.to_le_bytes());
163        }
164    }
165
166    #[inline]
167    pub fn deserialize(bytes: &[u8]) -> RawEvent {
168        assert!(bytes.len() == std::mem::size_of::<RawEvent>());
169
170        #[cfg(target_endian = "little")]
171        {
172            let mut raw_event = RawEvent::default();
173            unsafe {
174                let raw_event = std::slice::from_raw_parts_mut(
175                    &mut raw_event as *mut RawEvent as *mut u8,
176                    std::mem::size_of::<RawEvent>(),
177                );
178                raw_event.copy_from_slice(bytes);
179            };
180            raw_event
181        }
182
183        #[cfg(target_endian = "big")]
184        {
185            RawEvent {
186                event_kind: StringId::new(u64::from_le_bytes(bytes[0..8].try_into().unwrap())),
187                event_id: EventId::from_u64(u64::from_le_bytes(bytes[8..16].try_into().unwrap())),
188                thread_id: u32::from_le_bytes(bytes[16..20].try_into().unwrap()),
189                payload1_lower: u32::from_le_bytes(bytes[20..24].try_into().unwrap()),
190                payload2_lower: u32::from_le_bytes(bytes[24..28].try_into().unwrap()),
191                payloads_upper: u32::from_le_bytes(bytes[28..32].try_into().unwrap()),
192            }
193        }
194    }
195}
196
197impl Default for RawEvent {
198    fn default() -> Self {
199        RawEvent {
200            event_kind: StringId::INVALID,
201            event_id: EventId::INVALID,
202            thread_id: 0,
203            payload1_lower: 0,
204            payload2_lower: 0,
205            payloads_upper: 0,
206        }
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213
214    #[test]
215    fn raw_event_has_expected_size() {
216        // A test case to prevent accidental regressions of RawEvent's size.
217        assert_eq!(std::mem::size_of::<RawEvent>(), 32);
218    }
219
220    #[test]
221    fn is_instant() {
222        assert!(RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, 0,).is_instant());
223
224        assert!(
225            RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
226                .is_instant()
227        );
228
229        assert!(!RawEvent::new_interval(
230            StringId::INVALID,
231            EventId::INVALID,
232            987,
233            0,
234            MAX_INTERVAL_VALUE,
235        )
236        .is_instant());
237    }
238
239    #[test]
240    fn is_integer() {
241        let integer = RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 0);
242        assert!(integer.is_integer());
243        assert_eq!(integer.value(), 0);
244
245        let integer = RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 8769);
246        assert!(integer.is_integer());
247        assert_eq!(integer.value(), 8769);
248
249        assert!(
250            RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
251                .is_integer()
252        );
253
254        assert!(!RawEvent::new_interval(
255            StringId::INVALID,
256            EventId::INVALID,
257            987,
258            0,
259            MAX_INTERVAL_VALUE,
260        )
261        .is_integer());
262    }
263
264    #[test]
265    #[should_panic]
266    fn invalid_instant_count() {
267        let _ = RawEvent::new_instant(
268            StringId::INVALID,
269            EventId::INVALID,
270            123,
271            // count too large
272            MAX_SINGLE_VALUE + 1,
273        );
274    }
275
276    #[test]
277    #[should_panic]
278    fn invalid_start_count() {
279        let _ = RawEvent::new_interval(
280            StringId::INVALID,
281            EventId::INVALID,
282            123,
283            // start count too large
284            MAX_INTERVAL_VALUE + 1,
285            MAX_INTERVAL_VALUE + 1,
286        );
287    }
288
289    #[test]
290    #[should_panic]
291    fn invalid_end_count() {
292        let _ = RawEvent::new_interval(
293            StringId::INVALID,
294            EventId::INVALID,
295            123,
296            0,
297            // end count too large
298            MAX_INTERVAL_VALUE + 3,
299        );
300    }
301
302    #[test]
303    #[should_panic]
304    fn invalid_end_count2() {
305        let _ = RawEvent::new_interval(StringId::INVALID, EventId::INVALID, 123, 0, INTEGER_MARKER);
306    }
307
308    #[test]
309    #[should_panic]
310    fn start_greater_than_end_count() {
311        let _ = RawEvent::new_interval(
312            StringId::INVALID,
313            EventId::INVALID,
314            123,
315            // start count greater than end count
316            1,
317            0,
318        );
319    }
320
321    #[test]
322    fn start_equal_to_end_count() {
323        // This is allowed, make sure we don't panic
324        let _ = RawEvent::new_interval(StringId::INVALID, EventId::INVALID, 123, 1, 1);
325    }
326
327    #[test]
328    fn interval_count_decoding() {
329        // Check the upper limits
330        let e = RawEvent::new_interval(
331            StringId::INVALID,
332            EventId::INVALID,
333            1234,
334            MAX_INTERVAL_VALUE,
335            MAX_INTERVAL_VALUE,
336        );
337
338        assert_eq!(e.start_value(), MAX_INTERVAL_VALUE);
339        assert_eq!(e.end_value(), MAX_INTERVAL_VALUE);
340
341        // Check the lower limits
342        let e = RawEvent::new_interval(StringId::INVALID, EventId::INVALID, 1234, 0, 0);
343
344        assert_eq!(e.start_value(), 0);
345        assert_eq!(e.end_value(), 0);
346
347        // Check that end does not bleed into start
348        let e = RawEvent::new_interval(
349            StringId::INVALID,
350            EventId::INVALID,
351            1234,
352            0,
353            MAX_INTERVAL_VALUE,
354        );
355
356        assert_eq!(e.start_value(), 0);
357        assert_eq!(e.end_value(), MAX_INTERVAL_VALUE);
358
359        // Test some random values
360        let e = RawEvent::new_interval(
361            StringId::INVALID,
362            EventId::INVALID,
363            1234,
364            0x1234567890,
365            0x1234567890A,
366        );
367
368        assert_eq!(e.start_value(), 0x1234567890);
369        assert_eq!(e.end_value(), 0x1234567890A);
370    }
371
372    #[test]
373    fn instant_count_decoding() {
374        assert_eq!(
375            RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, 0,).start_value(),
376            0
377        );
378
379        assert_eq!(
380            RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, 42,).start_value(),
381            42
382        );
383
384        assert_eq!(
385            RawEvent::new_instant(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
386                .start_value(),
387            MAX_SINGLE_VALUE
388        );
389    }
390
391    #[test]
392    fn integer_decoding() {
393        assert_eq!(
394            RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 0,).start_value(),
395            0
396        );
397
398        assert_eq!(
399            RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, 42,).start_value(),
400            42
401        );
402
403        assert_eq!(
404            RawEvent::new_integer(StringId::INVALID, EventId::INVALID, 987, MAX_SINGLE_VALUE,)
405                .start_value(),
406            MAX_SINGLE_VALUE
407        );
408    }
409}