linux_perf_data/
feature_sections.rs

1use std::io::{Read, Seek, SeekFrom};
2
3use byteorder::{ByteOrder, ReadBytesExt};
4use linear_map::LinearMap;
5use linux_perf_event_reader::PerfEventAttr;
6
7use super::section::PerfFileSection;
8use crate::simpleperf::SimplePerfEventType;
9use crate::{Error, ReadError};
10
11/// The number of available and online CPUs. (`nr_cpus`)
12#[derive(Debug, Clone, Copy)]
13pub struct NrCpus {
14    /// CPUs not yet onlined
15    pub nr_cpus_available: u32,
16    pub nr_cpus_online: u32,
17}
18
19impl NrCpus {
20    pub const STRUCT_SIZE: usize = 4 + 4;
21
22    pub fn parse<R: Read, T: ByteOrder>(mut reader: R) -> Result<Self, std::io::Error> {
23        let nr_cpus_available = reader.read_u32::<T>()?;
24        let nr_cpus_online = reader.read_u32::<T>()?;
25        Ok(Self {
26            nr_cpus_available,
27            nr_cpus_online,
28        })
29    }
30}
31
32/// The timestamps of the first and last sample.
33#[derive(Debug, Clone, Copy)]
34pub struct SampleTimeRange {
35    pub first_sample_time: u64,
36    pub last_sample_time: u64,
37}
38
39impl SampleTimeRange {
40    pub const STRUCT_SIZE: usize = 8 + 8;
41
42    pub fn parse<R: Read, T: ByteOrder>(mut reader: R) -> Result<Self, std::io::Error> {
43        let first_sample_time = reader.read_u64::<T>()?;
44        let last_sample_time = reader.read_u64::<T>()?;
45        Ok(Self {
46            first_sample_time,
47            last_sample_time,
48        })
49    }
50}
51
52pub struct HeaderString;
53
54impl HeaderString {
55    /// Parse a string.
56    pub fn parse<R: Read, T: ByteOrder>(mut reader: R) -> Result<Option<String>, std::io::Error> {
57        let len = reader.read_u32::<T>()?;
58        let mut s = vec![0; len as usize];
59        reader.read_exact(&mut s)?;
60        let actual_len = memchr::memchr(0, &s).unwrap_or(s.len());
61        s.truncate(actual_len);
62        Ok(String::from_utf8(s).ok())
63    }
64}
65
66/// A single event attr with name and corresponding event IDs.
67#[derive(Debug, Clone)]
68pub struct AttributeDescription {
69    pub attr: PerfEventAttr,
70    pub name: Option<String>,
71    pub event_ids: Vec<u64>,
72}
73
74impl AttributeDescription {
75    /// Parse the `HEADER_EVENT_DESC` section of a perf.data file into a Vec of `AttributeDescription` structs.
76    pub fn parse_event_desc_section<C: Read + Seek, T: ByteOrder>(
77        mut cursor: C,
78    ) -> Result<Vec<Self>, Error> {
79        // ```c
80        // struct {
81        //   uint32_t nr; /* number of events */
82        //   uint32_t attr_size; /* size of each perf_event_attr */
83        //   struct {
84        //     struct perf_event_attr attr;  /* size of attr_size */
85        //     uint32_t nr_ids;
86        //     struct perf_header_string event_string;
87        //     uint64_t ids[nr_ids];
88        //   } events[nr]; /* Variable length records */
89        // };
90        // ```
91        let nr = cursor.read_u32::<T>()?;
92        let mut attributes = Vec::with_capacity(nr as usize);
93        let attr_size = cursor.read_u32::<T>()? as u64;
94        for _ in 0..nr {
95            let attr = Self::parse_single_attr::<_, T>(&mut cursor, attr_size)?;
96            let nr_ids = cursor.read_u32::<T>()?;
97            let event_string = HeaderString::parse::<_, T>(&mut cursor)?;
98            let mut ids = Vec::with_capacity(nr_ids as usize);
99            for _ in 0..nr_ids {
100                ids.push(cursor.read_u64::<T>()?);
101            }
102            attributes.push(AttributeDescription {
103                attr,
104                name: event_string,
105                event_ids: ids,
106            });
107        }
108        Ok(attributes)
109    }
110
111    /// Parse the `event_types` section of a perf.data file into a Vec of `AttributeDescription` structs.
112    /// This section was used in the past but is no longer used.
113    /// Only call this function if event_types_section.size is non-zero.
114    pub fn parse_event_types_section<C: Read + Seek, T: ByteOrder>(
115        cursor: C,
116        event_types_section: &PerfFileSection,
117        attr_size: u64,
118    ) -> Result<Vec<Self>, Error> {
119        // In the event_types section, each attribute takes up attr_size bytes and is followed
120        // by a PerfFileSection struct (16 bytes).
121        Self::parse_sequence_of_attr_and_id_section::<C, T>(
122            cursor,
123            event_types_section,
124            attr_size,
125            None,
126        )
127    }
128
129    /// Parse the `attr` section of a perf.data file into a Vec of `AttributeDescription` structs,
130    /// for files from Simpleperf. These files pack event ID information into the `attr` section
131    /// and contain event names in the `SIMPLEPERF_META_INFO` section.
132    pub fn parse_simpleperf_attr_section<C: Read + Seek, T: ByteOrder>(
133        cursor: C,
134        attr_section: &PerfFileSection,
135        attr_size: u64,
136        event_types: &[SimplePerfEventType],
137    ) -> Result<Vec<Self>, Error> {
138        if attr_size < PerfFileSection::STRUCT_SIZE {
139            return Err(ReadError::PerfEventAttr.into());
140        }
141        // Simpleperf reports an attr_size which is 16 bytes larger than the size that's used
142        // for the perf_event_attr data. These 16 extra bytes carry the (offset, size) of the
143        // per-event event IDs section.
144        // So the format of the attr section in the simpleperf is very similar to the format of the
145        // event_types section in old perf.data files, with the only difference being that the
146        // id_section information is "inside" the attr_size rather than outside it.
147        let attr_size_without_id_section = attr_size - PerfFileSection::STRUCT_SIZE;
148        let event_names: Vec<_> = event_types.iter().map(|t| t.name.as_str()).collect();
149        Self::parse_sequence_of_attr_and_id_section::<C, T>(
150            cursor,
151            attr_section,
152            attr_size_without_id_section,
153            Some(&event_names),
154        )
155    }
156
157    /// Used for parsing the `event_types` section (old Linux perf) and for parsing the `attr` section (Simpleperf).
158    fn parse_sequence_of_attr_and_id_section<C: Read + Seek, T: ByteOrder>(
159        mut cursor: C,
160        section: &PerfFileSection,
161        attr_size: u64,
162        event_names: Option<&[&str]>,
163    ) -> Result<Vec<Self>, Error> {
164        cursor.seek(SeekFrom::Start(section.offset))?;
165
166        // Each entry in the event_types section is a PerfEventAttr followed by a PerfFileSection.
167        let entry_size = attr_size + PerfFileSection::STRUCT_SIZE;
168        let entry_count = section.size / entry_size;
169        let mut perf_event_event_type_info = Vec::with_capacity(entry_count as usize);
170        for _ in 0..entry_count {
171            let attr = Self::parse_single_attr::<_, T>(&mut cursor, attr_size)?;
172            let event_ids = PerfFileSection::parse::<_, T>(&mut cursor)?;
173            perf_event_event_type_info.push((attr, event_ids));
174        }
175
176        // Read the lists of event IDs for each event type.
177        let mut attributes = Vec::new();
178        for (event_index, (attr, section)) in perf_event_event_type_info.into_iter().enumerate() {
179            cursor.seek(SeekFrom::Start(section.offset))?;
180            // This section is just a list of u64 event IDs.
181            let id_count = section.size / 8;
182            let mut event_ids = Vec::with_capacity(id_count as usize);
183            for _ in 0..id_count {
184                event_ids.push(cursor.read_u64::<T>()?);
185            }
186            let name = if let Some(names) = event_names {
187                names.get(event_index).map(|s| s.to_string())
188            } else {
189                None
190            };
191            attributes.push(AttributeDescription {
192                attr,
193                name,
194                event_ids,
195            });
196        }
197        Ok(attributes)
198    }
199
200    /// Parse the `attr` section of a perf.data file into a Vec of `AttributeDescription` structs.
201    /// This section is used as a last resort because it does not have any
202    /// information about event IDs. If multiple events are observed, we will
203    /// not be able to know which event record belongs to which attr.
204    pub fn parse_attr_section<C: Read + Seek, T: ByteOrder>(
205        mut cursor: C,
206        attr_section: &PerfFileSection,
207        attr_size: u64,
208    ) -> Result<Vec<Self>, Error> {
209        cursor.seek(SeekFrom::Start(attr_section.offset))?;
210        let attr_count = attr_section.size / attr_size;
211        let mut attributes = Vec::with_capacity(attr_count as usize);
212        for _ in 0..attr_count {
213            let attr = Self::parse_single_attr::<_, T>(&mut cursor, attr_size)?;
214            attributes.push(AttributeDescription {
215                attr,
216                name: None,
217                event_ids: vec![],
218            });
219        }
220        Ok(attributes)
221    }
222
223    fn parse_single_attr<C: Read + Seek, T: ByteOrder>(
224        mut cursor: C,
225        attr_size: u64,
226    ) -> Result<PerfEventAttr, Error> {
227        let (attr, size) =
228            PerfEventAttr::parse::<_, T>(&mut cursor).map_err(|_| ReadError::PerfEventAttr)?;
229        if size > attr_size {
230            return Err(Error::InconsistentAttributeSizes(size, attr_size));
231        }
232        if size < attr_size {
233            let remaining_bytes = attr_size - size;
234            cursor.seek(SeekFrom::Current(remaining_bytes as i64))?;
235        }
236        Ok(attr)
237    }
238
239    /// The event attributes.
240    pub fn attributes(&self) -> &PerfEventAttr {
241        &self.attr
242    }
243
244    /// The event name.
245    pub fn name(&self) -> Option<&str> {
246        self.name.as_deref()
247    }
248
249    /// The IDs for this event.
250    pub fn ids(&self) -> &[u64] {
251        &self.event_ids
252    }
253}
254
255/// The names of the dynamic PMU types used in [`PerfEventType::DynamicPmu`](linux_perf_event_reader::PerfEventType::DynamicPmu).
256///
257/// For example, this allows you to find out whether a `DynamicPmu`
258/// perf event is a kprobe or a uprobe, which then lets you interpret
259/// the meaning of the config fields.
260pub struct PmuMappings(pub LinearMap<u32, String>);
261
262impl PmuMappings {
263    pub fn parse<R: Read, T: ByteOrder>(mut reader: R) -> Result<Self, std::io::Error> {
264        // struct {
265        //     uint32_t nr;
266        //     struct pmu {
267        //        uint32_t pmu_type;
268        //        struct perf_header_string pmu_name;
269        //     } [nr]; /* Variable length records */
270        // };
271        let nr = reader.read_u32::<T>()?;
272        let mut vec = Vec::with_capacity(nr as usize);
273        for _ in 0..nr {
274            let pmu_type = reader.read_u32::<T>()?;
275            if let Some(pmu_name) = HeaderString::parse::<_, T>(&mut reader)? {
276                vec.push((pmu_type, pmu_name));
277            }
278        }
279        vec.sort_by_key(|item| item.0);
280        Ok(Self(vec.into_iter().collect()))
281    }
282}
283
284/// The clock data header contains information about the clock used to
285/// record timestamps in the perf.data file.
286#[derive(Debug, Clone, PartialEq, Eq)]
287pub struct ClockData {
288    /// Clock ID used for timestamps
289    pub clockid: u32,
290    /// Wall clock time in nanoseconds since Unix epoch.
291    pub wall_clock_ns: u64,
292    /// Clock ID time in nanoseconds at the same instant as `wall_clock_ns`.
293    pub clockid_time_ns: u64,
294}
295
296impl ClockData {
297    pub const STRUCT_SIZE: usize = 4 + 4 + 8 + 8;
298
299    pub fn parse<R: Read, T: ByteOrder>(mut data: R) -> Result<Self, std::io::Error> {
300        let version = data.read_u32::<T>()?;
301        if version != 1 {
302            return Err(std::io::Error::new(
303                std::io::ErrorKind::InvalidData,
304                format!("Unsupported clock data version: {version}"),
305            ));
306        }
307        let clockid = data.read_u32::<T>()?;
308        let wall_clock_ns = data.read_u64::<T>()?;
309        let clockid_time_ns = data.read_u64::<T>()?;
310
311        Ok(Self {
312            clockid,
313            wall_clock_ns,
314            clockid_time_ns,
315        })
316    }
317}