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
311#[cfg(test)]
312mod tests {
313 use super::*;
314
315 #[test]
316 fn test_record_header() {
317 let mut rec = RecordHeader::new();
318 rec.set_record_size(12).set_record_type(RecordType::Event);
319 assert_eq!(rec.record_type(), RecordType::Event);
320 assert_eq!(rec.record_size(), 12);
321 let raw = rec.bits();
322 assert_eq!(raw & 0xf, 4);
323 assert_eq!((raw >> 4) & 0xfff, 12);
324 }
325
326 #[test]
327 fn test_large_record_header() {
328 let mut lrec = LargeRecordHeader::default();
329 lrec.set_record_size(0x1000).set_large_type(2);
330 assert_eq!(lrec.record_type(), RecordType::LargeBlob);
331 assert_eq!(lrec.record_size(), 0x1000);
332 assert_eq!(lrec.large_type(), 2);
333 let raw = lrec.bits();
334 assert_eq!(raw & 0xf, 15);
335 assert_eq!((raw >> 4) & 0xffffffff, 0x1000);
336 assert_eq!((raw >> 36) & 0xf, 2);
337 }
338
339 #[test]
340 fn test_string_ref_header() {
341 let mut interned = StringRefHeader::new();
342 interned.set_id_or_len(42);
343 assert_eq!(interned.id_or_len(), 42);
344 assert!(!interned.is_inline());
345 assert_eq!(interned.bits(), 42);
346
347 let mut inline = StringRefHeader::new();
348 inline.set_is_inline(true).set_id_or_len(15);
349 assert!(inline.is_inline());
350 assert_eq!(inline.id_or_len(), 15);
351 assert_eq!(inline.bits(), 0x800f);
352 }
353
354 #[test]
355 fn test_thread_ref_header() {
356 let mut interned = ThreadRefHeader::new();
357 interned.set_id_or_len(5);
358 assert_eq!(interned.id_or_len(), 5);
359 assert!(!interned.is_inline());
360 assert_eq!(interned.bits(), 5);
361
362 let mut inline = ThreadRefHeader::new();
363 inline.set_is_inline(true).set_id_or_len(3);
364 assert!(inline.is_inline());
365 assert_eq!(inline.id_or_len(), 3);
366 assert_eq!(inline.bits(), 0x83);
367 }
368
369 #[test]
370 fn test_argument_header() {
371 let mut arg = ArgumentHeader::for_argument(10, 2, ArgumentType::Uint64);
372 assert_eq!(arg.arg_type(), ArgumentType::Uint64);
373 assert_eq!(arg.size_words(), 2);
374 assert_eq!(arg.name_ref(), 10);
375 assert_eq!(arg.value_bits(), 0);
376
377 arg.set_value_bits(0x12345678);
378 assert_eq!(arg.value_bits(), 0x12345678);
379 let raw = arg.bits();
380 assert_eq!(raw & 0xf, 4);
381 assert_eq!((raw >> 4) & 0xfff, 2);
382 assert_eq!((raw >> 16) & 0xffff, 10);
383 assert_eq!((raw >> 32) & 0xffffffff, 0x12345678);
384 }
385
386 #[test]
387 fn test_kernel_object_record_header() {
388 let mut ko = KernelObjectRecordHeader::default();
389 ko.set_record_size(6).set_obj_type(1).set_name_ref(0x8009).set_arg_count(1);
390 assert_eq!(ko.record_type(), RecordType::KernelObject);
391 assert_eq!(ko.record_size(), 6);
392 assert_eq!(ko.obj_type(), 1);
393 assert_eq!(ko.name_ref(), 0x8009);
394 assert_eq!(ko.arg_count(), 1);
395 let raw = ko.bits();
396 assert_eq!(raw & 0xf, 7);
397 assert_eq!((raw >> 4) & 0xfff, 6);
398 assert_eq!((raw >> 16) & 0xff, 1);
399 assert_eq!((raw >> 24) & 0xffff, 0x8009);
400 assert_eq!((raw >> 40) & 0xf, 1);
401 }
402
403 #[test]
404 fn test_event_record_header() {
405 let mut ev = EventRecordHeader::default();
406 ev.set_record_size(5)
407 .set_event_type(EventType::Instant)
408 .set_arg_count(1)
409 .set_thread_ref(0)
410 .set_category_ref(10)
411 .set_name_ref(20);
412 assert_eq!(ev.record_type(), RecordType::Event);
413 assert_eq!(ev.record_size(), 5);
414 assert_eq!(ev.event_type(), EventType::Instant);
415 assert_eq!(ev.arg_count(), 1);
416 assert_eq!(ev.thread_ref(), 0);
417 assert_eq!(ev.category_ref(), 10);
418 assert_eq!(ev.name_ref(), 20);
419 let raw = ev.bits();
420 assert_eq!(raw & 0xf, 4);
421 assert_eq!((raw >> 4) & 0xfff, 5);
422 assert_eq!((raw >> 16) & 0xf, 0);
423 assert_eq!((raw >> 20) & 0xf, 1);
424 assert_eq!((raw >> 24) & 0xff, 0);
425 assert_eq!((raw >> 32) & 0xffff, 10);
426 assert_eq!((raw >> 48) & 0xffff, 20);
427 }
428}