1#[path = "aux_record.rs"]
7mod aux;
8mod aux_output_hw_id;
9mod bpf_event;
10mod cgroup;
11mod comm;
12mod exit;
13mod itrace_start;
14mod ksymbol;
15mod lost;
16mod lost_samples;
17mod mmap;
18mod mmap2;
19mod namespaces;
20mod read;
21mod sample;
22mod switch_cpu_wide;
23mod text_poke;
24mod throttle;
25
26use perf_event_open_sys::bindings::perf_event_header;
27
28pub use self::aux::*;
29pub use self::aux_output_hw_id::*;
30pub use self::bpf_event::*;
31pub use self::cgroup::*;
32pub use self::comm::*;
33pub use self::exit::*;
34pub use self::itrace_start::*;
35pub use self::ksymbol::*;
36pub use self::lost::*;
37pub use self::lost_samples::*;
38pub use self::mmap::*;
39pub use self::mmap2::*;
40pub use self::namespaces::*;
41pub use self::read::*;
42pub use self::sample::*;
43pub use self::switch_cpu_wide::*;
44pub use self::text_poke::*;
45pub use self::throttle::*;
46
47pub type Fork = Exit;
55
56mod sample_id {
57 option_struct! {
58 ##[copy]
59 pub(super) struct SampleId : u8 {
60 pub pid: u32,
61 pub tid: u32,
62 pub time: u64,
63 pub id: u64,
64 pub stream_id: u64,
65 pub cpu: u32,
66 }
67 }
68}
69
70use std::borrow::Cow;
71use std::fmt;
72
73use crate::prelude::*;
74
75#[derive(Copy, Clone, Default)]
80pub struct SampleId(sample_id::SampleId);
81
82impl SampleId {
83 pub fn from_sample(sample: &Sample<'_>) -> Self {
86 Self(sample_id::SampleId::new(
87 sample.pid(),
88 sample.tid(),
89 sample.time(),
90 sample.id(),
91 sample.stream_id(),
92 sample.cpu(),
93 ))
94 }
95
96 pub fn pid(&self) -> Option<u32> {
98 self.0.pid().copied()
99 }
100
101 pub fn tid(&self) -> Option<u32> {
103 self.0.tid().copied()
104 }
105
106 pub fn time(&self) -> Option<u64> {
111 self.0.time().copied()
112 }
113
114 pub fn id(&self) -> Option<u64> {
116 self.0.id().copied()
117 }
118
119 pub fn stream_id(&self) -> Option<u64> {
121 self.0.stream_id().copied()
122 }
123
124 pub fn cpu(&self) -> Option<u32> {
126 self.0.cpu().copied()
127 }
128
129 pub fn estimate_len<E: Endian>(config: &ParseConfig<E>) -> usize {
132 let sty = config.sample_type();
133
134 if !config.sample_id_all() {
135 return 0;
136 }
137
138 let flags = SampleFlags::TID
139 | SampleFlags::TIME
140 | SampleFlags::ID
141 | SampleFlags::STREAM_ID
142 | SampleFlags::CPU
143 | SampleFlags::IDENTIFIER;
144
145 (sty & flags).bits().count_ones() as usize * std::mem::size_of::<u64>()
146 }
147}
148
149impl<'p> Parse<'p> for SampleId {
150 fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
151 where
152 E: Endian,
153 B: ParseBuf<'p>,
154 {
155 let config = p.config();
156 let sty = config.sample_type();
157
158 if !config.sample_id_all() {
159 return Ok(Self::default());
160 }
161
162 let pid = p.parse_if(sty.contains(SampleFlags::TID))?;
163 let tid = p.parse_if(sty.contains(SampleFlags::TID))?;
164 let time = p.parse_if(sty.contains(SampleFlags::TIME))?;
165 let id = p.parse_if(sty.contains(SampleFlags::ID))?;
166 let stream_id = p.parse_if(sty.contains(SampleFlags::STREAM_ID))?;
167 let cpu = p.parse_if_with(sty.contains(SampleFlags::CPU), |p| {
168 Ok((p.parse_u32()?, p.parse_u32()?).0)
169 })?;
170 let identifier = p.parse_if(sty.contains(SampleFlags::IDENTIFIER))?;
171
172 Ok(Self(sample_id::SampleId::new(
173 pid,
174 tid,
175 time,
176 id.or(identifier),
177 stream_id,
178 cpu,
179 )))
180 }
181}
182
183impl fmt::Debug for SampleId {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 self.0.fmt(f)
186 }
187}
188
189impl From<&'_ Sample<'_>> for SampleId {
190 fn from(value: &Sample) -> Self {
191 Self::from_sample(value)
192 }
193}
194
195impl From<Sample<'_>> for SampleId {
196 fn from(value: Sample<'_>) -> Self {
197 Self::from_sample(&value)
198 }
199}
200
201#[derive(Clone, Debug)]
207#[non_exhaustive]
208#[allow(missing_docs)]
209pub enum Record<'a> {
210 Mmap(Mmap<'a>),
211 Lost(Lost),
212 Comm(Comm<'a>),
213 Exit(Exit),
214 Throttle(Throttle),
215 Unthrottle(Throttle),
216 Fork(Fork),
217 Read(Read),
218 Sample(Box<Sample<'a>>),
219 Mmap2(Mmap2<'a>),
220 Aux(Aux),
221 ITraceStart(ITraceStart),
222 LostSamples(LostSamples),
223 Switch,
224 SwitchCpuWide(SwitchCpuWide),
225 Namespaces(Namespaces<'a>),
226 KSymbol(KSymbol<'a>),
227 BpfEvent(BpfEvent),
228 CGroup(CGroup<'a>),
229 TextPoke(TextPoke<'a>),
230 AuxOutputHwId(AuxOutputHwId),
231
232 Unknown {
243 ty: u32,
244 data: Cow<'a, [u8]>,
245 },
246}
247
248macro_rules! record_from {
249 ($ty:ident) => {
250 impl<'a> From<$ty> for Record<'a> {
251 fn from(value: $ty) -> Self {
252 Self::$ty(value)
253 }
254 }
255 };
256 ($ty:ident<$lt:lifetime>) => {
257 impl<$lt> From<$ty<$lt>> for Record<$lt> {
258 fn from(value: $ty<$lt>) -> Self {
259 Self::$ty(value)
260 }
261 }
262 };
263}
264
265record_from!(Mmap<'a>);
266record_from!(Lost);
267record_from!(Comm<'a>);
268record_from!(Read);
272record_from!(Mmap2<'a>);
273record_from!(Aux);
274record_from!(ITraceStart);
275record_from!(LostSamples);
276record_from!(SwitchCpuWide);
277record_from!(Namespaces<'a>);
278record_from!(KSymbol<'a>);
279record_from!(BpfEvent);
280record_from!(CGroup<'a>);
281record_from!(TextPoke<'a>);
282record_from!(AuxOutputHwId);
283
284impl<'a> From<Sample<'a>> for Record<'a> {
285 fn from(value: Sample<'a>) -> Self {
286 Self::Sample(Box::new(value))
287 }
288}
289
290struct RecordVisitor;
291
292impl<'a> crate::Visitor<'a> for RecordVisitor {
293 type Output = Record<'a>;
294
295 fn visit_unimplemented(self, metadata: crate::RecordMetadata) -> Self::Output {
296 panic!(
297 "parsing for records of type {} is not implemented",
298 metadata.ty()
299 );
300 }
301
302 fn visit_mmap(self, record: Mmap<'a>, _: crate::RecordMetadata) -> Self::Output {
303 record.into()
304 }
305
306 fn visit_lost(self, record: Lost, _: crate::RecordMetadata) -> Self::Output {
307 record.into()
308 }
309
310 fn visit_comm(self, record: Comm<'a>, _: crate::RecordMetadata) -> Self::Output {
311 record.into()
312 }
313
314 fn visit_exit(self, record: Exit, _: crate::RecordMetadata) -> Self::Output {
315 Record::Exit(record)
316 }
317
318 fn visit_throttle(self, record: Throttle, _: crate::RecordMetadata) -> Self::Output {
319 Record::Throttle(record)
320 }
321
322 fn visit_unthrottle(self, record: Throttle, _: crate::RecordMetadata) -> Self::Output {
323 Record::Unthrottle(record)
324 }
325
326 fn visit_fork(self, record: Fork, _: crate::RecordMetadata) -> Self::Output {
327 Record::Fork(record)
328 }
329
330 fn visit_read(self, record: Read, _: crate::RecordMetadata) -> Self::Output {
331 record.into()
332 }
333
334 fn visit_sample(self, record: Sample<'a>, _: crate::RecordMetadata) -> Self::Output {
335 record.into()
336 }
337
338 fn visit_mmap2(self, record: Mmap2<'a>, _: crate::RecordMetadata) -> Self::Output {
339 record.into()
340 }
341
342 fn visit_aux(self, record: Aux, _: crate::RecordMetadata) -> Self::Output {
343 record.into()
344 }
345
346 fn visit_itrace_start(self, record: ITraceStart, _: crate::RecordMetadata) -> Self::Output {
347 record.into()
348 }
349
350 fn visit_lost_samples(self, record: LostSamples, _: crate::RecordMetadata) -> Self::Output {
351 record.into()
352 }
353
354 fn visit_switch(self, _: crate::RecordMetadata) -> Self::Output {
355 Record::Switch
356 }
357
358 fn visit_switch_cpu_wide(
359 self,
360 record: SwitchCpuWide,
361 _: crate::RecordMetadata,
362 ) -> Self::Output {
363 record.into()
364 }
365
366 fn visit_namespaces(self, record: Namespaces<'a>, _: crate::RecordMetadata) -> Self::Output {
367 record.into()
368 }
369
370 fn visit_ksymbol(self, record: KSymbol<'a>, _: crate::RecordMetadata) -> Self::Output {
371 record.into()
372 }
373
374 fn visit_bpf_event(self, record: BpfEvent, _: crate::RecordMetadata) -> Self::Output {
375 record.into()
376 }
377
378 fn visit_cgroup(self, record: CGroup<'a>, _: crate::RecordMetadata) -> Self::Output {
379 record.into()
380 }
381
382 fn visit_text_poke(self, record: TextPoke<'a>, _: crate::RecordMetadata) -> Self::Output {
383 record.into()
384 }
385
386 fn visit_aux_output_hw_id(
387 self,
388 record: AuxOutputHwId,
389 _: crate::RecordMetadata,
390 ) -> Self::Output {
391 record.into()
392 }
393
394 fn visit_unknown(self, data: Cow<'a, [u8]>, metadata: crate::RecordMetadata) -> Self::Output {
395 Record::Unknown {
396 ty: metadata.ty(),
397 data,
398 }
399 }
400}
401
402impl<'p> Record<'p> {
403 pub fn parse_with_header<B, E>(
406 p: &mut Parser<B, E>,
407 header: perf_event_header,
408 ) -> ParseResult<Self>
409 where
410 E: Endian,
411 B: ParseBuf<'p>,
412 {
413 p.parse_record_with_header(RecordVisitor, header)
414 }
415}
416
417impl<'p> Parse<'p> for Record<'p> {
418 fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
419 where
420 E: Endian,
421 B: ParseBuf<'p>,
422 {
423 p.parse_record(RecordVisitor)
424 }
425}