1#![no_std]
11
12use bitrs::{bitfield_repr, layout};
13
14pub const MAGIC_VALUE: u32 = 0x16547846;
16
17#[bitfield_repr(u8)]
19pub enum RecordType {
20 Metadata = 0,
21 Initialization = 1,
22 String = 2,
23 Thread = 3,
24 Event = 4,
25 Blob = 5,
26 UserspaceObject = 6,
27 KernelObject = 7,
28 Scheduler = 8,
29 Log = 9,
30 Profiler = 10,
31 LargeBlob = 15,
33}
34
35#[bitfield_repr(u8)]
37pub enum ProfilerRecordType {
38 Module = 0,
39 Mmap = 1,
40 Backtrace = 2,
41}
42
43#[bitfield_repr(u8)]
44pub enum LargeRecordType {
45 Blob = 0,
46}
47
48#[bitfield_repr(u8)]
50pub enum MetadataType {
51 ProviderInfo = 1,
52 ProviderSection = 2,
53 ProviderEvent = 3,
54 TraceInfo = 4,
55}
56
57#[bitfield_repr(u8)]
59pub enum ProviderEventType {
60 BufferOverflow = 0,
61}
62
63#[bitfield_repr(u8)]
65pub enum TraceInfoType {
66 MagicNumber = 0,
67}
68
69#[derive(Debug, Copy, Clone, Eq, PartialEq)]
71pub enum RefType {
72 Inline,
73 Id,
74}
75
76#[bitfield_repr(u8)]
78pub enum ArgumentType {
79 Null = 0,
80 Int32 = 1,
81 Uint32 = 2,
82 Int64 = 3,
83 Uint64 = 4,
84 Double = 5,
85 String = 6,
86 Pointer = 7,
87 Koid = 8,
88 Bool = 9,
89 Blob = 10,
90}
91
92#[bitfield_repr(u8)]
94pub enum EventType {
95 Instant = 0,
96 Counter = 1,
97 DurationBegin = 2,
98 DurationEnd = 3,
99 DurationComplete = 4,
100 AsyncBegin = 5,
101 AsyncInstant = 6,
102 AsyncEnd = 7,
103 FlowBegin = 8,
104 FlowStep = 9,
105 FlowEnd = 10,
106}
107
108#[bitfield_repr(u8)]
110pub enum SchedulerEventType {
111 LegacyContextSwitch = 0,
112 ContextSwitch = 1,
113 ThreadWakeup = 2,
114}
115
116#[bitfield_repr(u8)]
118pub enum EventScope {
119 Thread = 0,
120 Process = 1,
121 Global = 2,
122}
123
124pub type ProviderId = u32;
126
127#[bitfield_repr(u8)]
128pub enum BlobType {
129 Data = 1,
130 LastBranch = 2,
131 Perfetto = 3,
132}
133
134#[bitfield_repr(u8)]
135pub enum LargeBlobFormat {
136 Metadata = 0,
137 NoMetadata = 1,
138}
139
140layout!({
141 pub struct RecordHeader(u64);
143 {
144 let record_size @ 15..4;
145 let record_type @ 3..0: RecordType;
146 }
147});
148
149layout!({
150 pub struct LargeRecordHeader(u64);
152 {
153 let large_type @ 39..36;
154 let record_size @ 35..4;
155 let record_type @ 3..0: RecordType = RecordType::LargeBlob;
156 }
157});
158
159layout!({
160 pub struct StringRefHeader(u16);
162 {
163 let is_inline @ 15;
164 let id_or_len @ 14..0;
165 }
166});
167
168impl StringRefHeader {
169 pub fn indexed(id: u16) -> Self {
171 let mut hdr = Self::new();
172 hdr.set_id_or_len(id);
173 hdr
174 }
175
176 pub fn inline(len: u16) -> Self {
178 let mut hdr = Self::new();
179 hdr.set_is_inline(true).set_id_or_len(len);
180 hdr
181 }
182}
183
184layout!({
185 pub struct ThreadRefHeader(u8);
187 {
188 let is_inline @ 7;
189 let id_or_len @ 6..0;
190 }
191});
192
193impl ThreadRefHeader {
194 pub fn indexed(id: u8) -> Self {
196 let mut hdr = Self::new();
197 hdr.set_id_or_len(id);
198 hdr
199 }
200
201 pub fn inline(len: u8) -> Self {
203 let mut hdr = Self::new();
204 hdr.set_is_inline(true).set_id_or_len(len);
205 hdr
206 }
207}
208
209layout!({
210 pub struct ArgumentHeader(u64);
212 {
213 let value_bits @ 63..32;
214 let name_ref @ 31..16;
215 let size_words @ 15..4;
216 let arg_type @ 3..0: ArgumentType;
217 }
218});
219
220impl ArgumentHeader {
221 pub fn for_argument(name_ref: u16, size_words: u16, arg_type: ArgumentType) -> Self {
223 let mut hdr = Self::new();
224 hdr.set_arg_type(arg_type).set_size_words(size_words).set_name_ref(name_ref);
225 hdr
226 }
227}
228
229layout!({
230 pub struct KernelObjectRecordHeader(u64);
232 {
233 let arg_count @ 43..40;
234 let name_ref @ 39..24;
235 let obj_type @ 23..16;
236 let record_size @ 15..4;
237 let record_type @ 3..0: RecordType = RecordType::KernelObject;
238 }
239});
240
241layout!({
242 pub struct UserspaceObjectRecordHeader(u64);
244 {
245 let arg_count @ 43..40;
246 let name_ref @ 39..24;
247 let process_thread_ref @ 23..16;
248 let record_size @ 15..4;
249 let record_type @ 3..0: RecordType = RecordType::UserspaceObject;
250 }
251});
252
253layout!({
254 pub struct EventRecordHeader(u64);
256 {
257 let name_ref @ 63..48;
258 let category_ref @ 47..32;
259 let thread_ref @ 31..24;
260 let arg_count @ 23..20;
261 let event_type @ 19..16: EventType;
262 let record_size @ 15..4;
263 let record_type @ 3..0: RecordType = RecordType::Event;
264 }
265});
266
267layout!({
268 pub struct StringRecordHeader(u64);
270 {
271 let string_len @ 46..32;
272 let string_index @ 30..16;
273 let record_size @ 15..4;
274 let record_type @ 3..0: RecordType = RecordType::String;
275 }
276});
277
278layout!({
279 pub struct ThreadRecordHeader(u64);
281 {
282 let thread_index @ 23..16;
283 let record_size @ 15..4;
284 let record_type @ 3..0: RecordType = RecordType::Thread;
285 }
286});
287
288layout!({
289 pub struct BlobRecordHeader(u64);
291 {
292 let blob_type @ 55..48: BlobType;
293 let blob_size @ 46..32;
294 let name_ref @ 31..16;
295 let record_size @ 15..4;
296 let record_type @ 3..0: RecordType = RecordType::Blob;
297 }
298});
299
300layout!({
301 pub struct LogRecordHeader(u64);
303 {
304 let thread_ref @ 39..32;
305 let log_message_len @ 30..16;
306 let record_size @ 15..4;
307 let record_type @ 3..0: RecordType = RecordType::Log;
308 }
309});
310
311layout!({
312 pub struct ContextSwitchRecordHeader(u64);
314 {
315 let event_type @ 63..60: SchedulerEventType = SchedulerEventType::ContextSwitch;
316 let thread_state @ 39..36;
317 let cpu_number @ 35..20;
318 let arg_count @ 19..16;
319 let record_size @ 15..4;
320 let record_type @ 3..0: RecordType = RecordType::Scheduler;
321 }
322});
323
324layout!({
325 pub struct ThreadWakeupRecordHeader(u64);
327 {
328 let event_type @ 63..60: SchedulerEventType = SchedulerEventType::ThreadWakeup;
329 let cpu_number @ 35..20;
330 let arg_count @ 19..16;
331 let record_size @ 15..4;
332 let record_type @ 3..0: RecordType = RecordType::Scheduler;
333 }
334});
335
336#[cfg(test)]
337mod tests {
338 use super::*;
339
340 #[test]
341 fn test_record_header() {
342 let mut rec = RecordHeader::new();
343 rec.set_record_size(12).set_record_type(RecordType::Event);
344 assert_eq!(rec.record_type(), RecordType::Event);
345 assert_eq!(rec.record_size(), 12);
346 let raw = rec.bits();
347 assert_eq!(raw & 0xf, 4);
348 assert_eq!((raw >> 4) & 0xfff, 12);
349 }
350
351 #[test]
352 fn test_large_record_header() {
353 let mut lrec = LargeRecordHeader::default();
354 lrec.set_record_size(0x1000).set_large_type(2);
355 assert_eq!(lrec.record_type(), RecordType::LargeBlob);
356 assert_eq!(lrec.record_size(), 0x1000);
357 assert_eq!(lrec.large_type(), 2);
358 let raw = lrec.bits();
359 assert_eq!(raw & 0xf, 15);
360 assert_eq!((raw >> 4) & 0xffffffff, 0x1000);
361 assert_eq!((raw >> 36) & 0xf, 2);
362 }
363
364 #[test]
365 fn test_string_ref_header() {
366 let mut interned = StringRefHeader::new();
367 interned.set_id_or_len(42);
368 assert_eq!(interned.id_or_len(), 42);
369 assert!(!interned.is_inline());
370 assert_eq!(interned.bits(), 42);
371
372 let mut inline = StringRefHeader::new();
373 inline.set_is_inline(true).set_id_or_len(15);
374 assert!(inline.is_inline());
375 assert_eq!(inline.id_or_len(), 15);
376 assert_eq!(inline.bits(), 0x800f);
377 }
378
379 #[test]
380 fn test_thread_ref_header() {
381 let mut interned = ThreadRefHeader::new();
382 interned.set_id_or_len(5);
383 assert_eq!(interned.id_or_len(), 5);
384 assert!(!interned.is_inline());
385 assert_eq!(interned.bits(), 5);
386
387 let mut inline = ThreadRefHeader::new();
388 inline.set_is_inline(true).set_id_or_len(3);
389 assert!(inline.is_inline());
390 assert_eq!(inline.id_or_len(), 3);
391 assert_eq!(inline.bits(), 0x83);
392 }
393
394 #[test]
395 fn test_argument_header() {
396 let mut arg = ArgumentHeader::for_argument(10, 2, ArgumentType::Uint64);
397 assert_eq!(arg.arg_type(), ArgumentType::Uint64);
398 assert_eq!(arg.size_words(), 2);
399 assert_eq!(arg.name_ref(), 10);
400 assert_eq!(arg.value_bits(), 0);
401
402 arg.set_value_bits(0x12345678);
403 assert_eq!(arg.value_bits(), 0x12345678);
404 let raw = arg.bits();
405 assert_eq!(raw & 0xf, 4);
406 assert_eq!((raw >> 4) & 0xfff, 2);
407 assert_eq!((raw >> 16) & 0xffff, 10);
408 assert_eq!((raw >> 32) & 0xffffffff, 0x12345678);
409 }
410
411 #[test]
412 fn test_kernel_object_record_header() {
413 let mut ko = KernelObjectRecordHeader::default();
414 ko.set_record_size(6).set_obj_type(1).set_name_ref(0x8009).set_arg_count(1);
415 assert_eq!(ko.record_type(), RecordType::KernelObject);
416 assert_eq!(ko.record_size(), 6);
417 assert_eq!(ko.obj_type(), 1);
418 assert_eq!(ko.name_ref(), 0x8009);
419 assert_eq!(ko.arg_count(), 1);
420 let raw = ko.bits();
421 assert_eq!(raw & 0xf, 7);
422 assert_eq!((raw >> 4) & 0xfff, 6);
423 assert_eq!((raw >> 16) & 0xff, 1);
424 assert_eq!((raw >> 24) & 0xffff, 0x8009);
425 assert_eq!((raw >> 40) & 0xf, 1);
426 }
427
428 #[test]
429 fn test_event_record_header() {
430 let mut ev = EventRecordHeader::default();
431 ev.set_record_size(5)
432 .set_event_type(EventType::Instant)
433 .set_arg_count(1)
434 .set_thread_ref(0)
435 .set_category_ref(10)
436 .set_name_ref(20);
437 assert_eq!(ev.record_type(), RecordType::Event);
438 assert_eq!(ev.record_size(), 5);
439 assert_eq!(ev.event_type(), EventType::Instant);
440 assert_eq!(ev.arg_count(), 1);
441 assert_eq!(ev.thread_ref(), 0);
442 assert_eq!(ev.category_ref(), 10);
443 assert_eq!(ev.name_ref(), 20);
444 let raw = ev.bits();
445 assert_eq!(raw & 0xf, 4);
446 assert_eq!((raw >> 4) & 0xfff, 5);
447 assert_eq!((raw >> 16) & 0xf, 0);
448 assert_eq!((raw >> 20) & 0xf, 1);
449 assert_eq!((raw >> 24) & 0xff, 0);
450 assert_eq!((raw >> 32) & 0xffff, 10);
451 assert_eq!((raw >> 48) & 0xffff, 20);
452 }
453
454 #[test]
455 fn test_context_switch_record_header() {
456 let mut cs = ContextSwitchRecordHeader::default();
457 cs.set_record_size(6).set_arg_count(2).set_cpu_number(0x1234).set_thread_state(3);
458 assert_eq!(cs.record_type(), RecordType::Scheduler);
459 assert_eq!(cs.record_size(), 6);
460 assert_eq!(cs.arg_count(), 2);
461 assert_eq!(cs.cpu_number(), 0x1234);
462 assert_eq!(cs.thread_state(), 3);
463 assert_eq!(cs.event_type(), SchedulerEventType::ContextSwitch);
464 let raw = cs.bits();
465 assert_eq!(raw & 0xf, 8);
466 assert_eq!((raw >> 4) & 0xfff, 6);
467 assert_eq!((raw >> 16) & 0xf, 2);
468 assert_eq!((raw >> 20) & 0xffff, 0x1234);
469 assert_eq!((raw >> 36) & 0xf, 3);
470 assert_eq!((raw >> 60) & 0xf, 1);
471 }
472
473 #[test]
474 fn test_thread_wakeup_record_header() {
475 let mut tw = ThreadWakeupRecordHeader::default();
476 tw.set_record_size(4).set_arg_count(1).set_cpu_number(0x5678);
477 assert_eq!(tw.record_type(), RecordType::Scheduler);
478 assert_eq!(tw.record_size(), 4);
479 assert_eq!(tw.arg_count(), 1);
480 assert_eq!(tw.cpu_number(), 0x5678);
481 assert_eq!(tw.event_type(), SchedulerEventType::ThreadWakeup);
482 let raw = tw.bits();
483 assert_eq!(raw & 0xf, 8);
484 assert_eq!((raw >> 4) & 0xfff, 4);
485 assert_eq!((raw >> 16) & 0xf, 1);
486 assert_eq!((raw >> 20) & 0xffff, 0x5678);
487 assert_eq!((raw >> 60) & 0xf, 2);
488 }
489}