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}
410