perf_event_data/records/
mod.rs

1//! This module contains the actual structs.
2//!
3//! This is mostly to separate them from the support code of this crate.
4
5// Having a file named aux causes errors on windows so we rename it here.
6#[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
47/// FORK records indicate that a process called [`fork(2)`] successfully.
48///
49/// This struct corresponds to `PERF_RECORD_FORK`. See the [manpage] for more
50/// documentation.
51///
52/// [`fork(2)`]: https://man7.org/linux/man-pages/man2/fork.2.html
53/// [manpage]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
54pub 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/// A subset of the sample fields that can be recorded in non-SAMPLE records.
76///
77/// This will be empty by default unless `sample_id_all` was set when
78/// configuring the perf event counter.
79#[derive(Copy, Clone, Default)]
80pub struct SampleId(sample_id::SampleId);
81
82impl SampleId {
83    /// Construct a `SampleId` by reading its fields out of a full sample
84    /// struct.
85    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    /// The process ID that generated this event.
97    pub fn pid(&self) -> Option<u32> {
98        self.0.pid().copied()
99    }
100
101    /// The thread ID that generated this event.
102    pub fn tid(&self) -> Option<u32> {
103        self.0.tid().copied()
104    }
105
106    /// The time at which this event was recorded.
107    ///
108    /// The clock used to record the time depends on how the clock was
109    /// configured when setting up the counter.
110    pub fn time(&self) -> Option<u64> {
111        self.0.time().copied()
112    }
113
114    /// The unique kernel-assigned ID for the leader of this counter group.
115    pub fn id(&self) -> Option<u64> {
116        self.0.id().copied()
117    }
118
119    /// The unique kernel-assigned ID for the counter that generated this event.
120    pub fn stream_id(&self) -> Option<u64> {
121        self.0.stream_id().copied()
122    }
123
124    /// The CPU on which this event was recorded.
125    pub fn cpu(&self) -> Option<u32> {
126        self.0.cpu().copied()
127    }
128
129    /// Get the length in bytes that this struct would need to be parsed from
130    /// the provided parser.
131    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/// A record emitted by the linux kernel.
202///
203/// This enum contains every supported record type emitted by the kernel.
204/// Depending on how the perf event counter was configured only a few of these
205/// will be emitted by any one counter.
206#[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    /// A record type that is unknown to this crate.
233    ///
234    /// Note that just because a record is parsed as unknown in one release of
235    /// this crate does not mean it will continue to be parsed in future
236    /// releases. Adding a new variant to this enum is not considered to be a
237    /// breaking change.
238    ///
239    /// If you find yourself using the unknown variant to parse valid records
240    /// emitted by the kernel please file an issue or create a PR to add support
241    /// for them.
242    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>);
268// These are both the same struct
269// record_from!(Exit);
270// record_from!(Fork);
271record_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    /// Parse a `Record` using a [`perf_event_header`] that has already been
404    /// parsed.
405    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}