Skip to main content

linux_perf_data/
record.rs

1use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt};
2use linux_perf_event_reader::RawEventRecord;
3use linux_perf_event_reader::{Endianness, PerfEventAttr, RawData, RecordType};
4
5use crate::auxtrace::Auxtrace;
6use crate::constants::*;
7use crate::features::Feature;
8use crate::thread_map::ThreadMap;
9
10/// A record from a perf.data file's data stream.
11///
12/// This can be either a record emitted by the kernel for a perf event, or a
13/// synthesized record that was added by a user-space tool like `perf`.
14pub enum PerfFileRecord<'a> {
15    /// Emitted by the kernel for a perf event.
16    EventRecord {
17        /// And index into the array returned by [`PerfFile::event_attributes`](crate::PerfFile::event_attributes).
18        attr_index: usize,
19        /// The record.
20        record: RawEventRecord<'a>,
21    },
22    /// Synthesized by a user space tool, for example by `perf` or by `simpleperf`.
23    UserRecord(RawUserRecord<'a>),
24}
25
26/// A record emitted by a user space tool, for example by `perf` or by `simpleperf`.
27#[derive(Debug, Clone)]
28#[non_exhaustive]
29pub enum UserRecord<'a> {
30    ThreadMap(ThreadMap<'a>),
31    HeaderAttr(HeaderAttr),
32    HeaderFeature(HeaderFeature),
33    Auxtrace(Auxtrace<'a>),
34    Raw(RawUserRecord<'a>),
35}
36
37/// A newtype wrapping `RecordType` values for which `RecordType::is_user_type()` returns true.
38#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub struct UserRecordType(RecordType);
40
41impl UserRecordType {
42    pub const PERF_HEADER_ATTR: Self = Self(RecordType(PERF_RECORD_HEADER_ATTR));
43    pub const PERF_HEADER_EVENT_TYPE: Self = Self(RecordType(PERF_RECORD_HEADER_EVENT_TYPE));
44    pub const PERF_HEADER_TRACING_DATA: Self = Self(RecordType(PERF_RECORD_HEADER_TRACING_DATA));
45    pub const PERF_HEADER_BUILD_ID: Self = Self(RecordType(PERF_RECORD_HEADER_BUILD_ID));
46    pub const PERF_FINISHED_ROUND: Self = Self(RecordType(PERF_RECORD_FINISHED_ROUND));
47    pub const PERF_ID_INDEX: Self = Self(RecordType(PERF_RECORD_ID_INDEX));
48    pub const PERF_AUXTRACE_INFO: Self = Self(RecordType(PERF_RECORD_AUXTRACE_INFO));
49    pub const PERF_AUXTRACE: Self = Self(RecordType(PERF_RECORD_AUXTRACE));
50    pub const PERF_AUXTRACE_ERROR: Self = Self(RecordType(PERF_RECORD_AUXTRACE_ERROR));
51    pub const PERF_THREAD_MAP: Self = Self(RecordType(PERF_RECORD_THREAD_MAP));
52    pub const PERF_CPU_MAP: Self = Self(RecordType(PERF_RECORD_CPU_MAP));
53    pub const PERF_STAT_CONFIG: Self = Self(RecordType(PERF_RECORD_STAT_CONFIG));
54    pub const PERF_STAT: Self = Self(RecordType(PERF_RECORD_STAT));
55    pub const PERF_STAT_ROUND: Self = Self(RecordType(PERF_RECORD_STAT_ROUND));
56    pub const PERF_EVENT_UPDATE: Self = Self(RecordType(PERF_RECORD_EVENT_UPDATE));
57    pub const PERF_TIME_CONV: Self = Self(RecordType(PERF_RECORD_TIME_CONV));
58    pub const PERF_HEADER_FEATURE: Self = Self(RecordType(PERF_RECORD_HEADER_FEATURE));
59    pub const PERF_COMPRESSED: Self = Self(RecordType(PERF_RECORD_COMPRESSED));
60    pub const PERF_COMPRESSED2: Self = Self(RecordType(PERF_RECORD_COMPRESSED2));
61
62    pub const SIMPLEPERF_KERNEL_SYMBOL: Self = Self(RecordType(SIMPLE_PERF_RECORD_KERNEL_SYMBOL));
63    pub const SIMPLEPERF_DSO: Self = Self(RecordType(SIMPLE_PERF_RECORD_DSO));
64    pub const SIMPLEPERF_SYMBOL: Self = Self(RecordType(SIMPLE_PERF_RECORD_SYMBOL));
65    pub const SIMPLEPERF_SPLIT: Self = Self(RecordType(SIMPLE_PERF_RECORD_SPLIT));
66    pub const SIMPLEPERF_SPLIT_END: Self = Self(RecordType(SIMPLE_PERF_RECORD_SPLIT_END));
67    pub const SIMPLEPERF_EVENT_ID: Self = Self(RecordType(SIMPLE_PERF_RECORD_EVENT_ID));
68    pub const SIMPLEPERF_CALLCHAIN: Self = Self(RecordType(SIMPLE_PERF_RECORD_CALLCHAIN));
69    pub const SIMPLEPERF_UNWINDING_RESULT: Self =
70        Self(RecordType(SIMPLE_PERF_RECORD_UNWINDING_RESULT));
71    pub const SIMPLEPERF_TRACING_DATA: Self = Self(RecordType(SIMPLE_PERF_RECORD_TRACING_DATA));
72
73    pub fn try_from(record_type: RecordType) -> Option<Self> {
74        if record_type.is_user_type() {
75            Some(Self(record_type))
76        } else {
77            None
78        }
79    }
80
81    pub fn record_type(&self) -> RecordType {
82        self.0
83    }
84}
85
86impl From<UserRecordType> for RecordType {
87    fn from(record_type: UserRecordType) -> Self {
88        record_type.0
89    }
90}
91
92impl std::fmt::Debug for UserRecordType {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        match *self {
95            Self::PERF_HEADER_ATTR => "PERF_HEADER_ATTR".fmt(f),
96            Self::PERF_HEADER_EVENT_TYPE => "PERF_HEADER_EVENT_TYPE".fmt(f),
97            Self::PERF_HEADER_TRACING_DATA => "PERF_HEADER_TRACING_DATA".fmt(f),
98            Self::PERF_HEADER_BUILD_ID => "PERF_HEADER_BUILD_ID".fmt(f),
99            Self::PERF_FINISHED_ROUND => "PERF_FINISHED_ROUND".fmt(f),
100            Self::PERF_ID_INDEX => "PERF_ID_INDEX".fmt(f),
101            Self::PERF_AUXTRACE_INFO => "PERF_AUXTRACE_INFO".fmt(f),
102            Self::PERF_AUXTRACE => "PERF_AUXTRACE".fmt(f),
103            Self::PERF_AUXTRACE_ERROR => "PERF_AUXTRACE_ERROR".fmt(f),
104            Self::PERF_THREAD_MAP => "PERF_THREAD_MAP".fmt(f),
105            Self::PERF_CPU_MAP => "PERF_CPU_MAP".fmt(f),
106            Self::PERF_STAT_CONFIG => "PERF_STAT_CONFIG".fmt(f),
107            Self::PERF_STAT => "PERF_STAT".fmt(f),
108            Self::PERF_STAT_ROUND => "PERF_STAT_ROUND".fmt(f),
109            Self::PERF_EVENT_UPDATE => "PERF_EVENT_UPDATE".fmt(f),
110            Self::PERF_TIME_CONV => "PERF_TIME_CONV".fmt(f),
111            Self::PERF_HEADER_FEATURE => "PERF_HEADER_FEATURE".fmt(f),
112            Self::PERF_COMPRESSED => "PERF_COMPRESSED".fmt(f),
113            Self::PERF_COMPRESSED2 => "PERF_COMPRESSED2".fmt(f),
114            Self::SIMPLEPERF_KERNEL_SYMBOL => "SIMPLEPERF_KERNEL_SYMBOL".fmt(f),
115            Self::SIMPLEPERF_DSO => "SIMPLEPERF_DSO".fmt(f),
116            Self::SIMPLEPERF_SYMBOL => "SIMPLEPERF_SYMBOL".fmt(f),
117            Self::SIMPLEPERF_SPLIT => "SIMPLEPERF_SPLIT".fmt(f),
118            Self::SIMPLEPERF_SPLIT_END => "SIMPLEPERF_SPLIT_END".fmt(f),
119            Self::SIMPLEPERF_EVENT_ID => "SIMPLEPERF_EVENT_ID".fmt(f),
120            Self::SIMPLEPERF_CALLCHAIN => "SIMPLEPERF_CALLCHAIN".fmt(f),
121            Self::SIMPLEPERF_UNWINDING_RESULT => "SIMPLEPERF_UNWINDING_RESULT".fmt(f),
122            Self::SIMPLEPERF_TRACING_DATA => "SIMPLEPERF_TRACING_DATA".fmt(f),
123            other => f.write_fmt(format_args!("Unknown UserRecordType {}", other.0 .0)),
124        }
125    }
126}
127
128/// A raw user record.
129///
130/// Can be turned into a parsed [`UserRecord`] using [`RawUserRecord::parse`].
131#[derive(Debug, Clone)]
132pub struct RawUserRecord<'a> {
133    pub record_type: UserRecordType,
134    pub endian: Endianness,
135    pub misc: u16,
136    pub data: RawData<'a>,
137}
138
139impl<'a> RawUserRecord<'a> {
140    pub fn parse(&self) -> Result<UserRecord<'a>, std::io::Error> {
141        match self.endian {
142            Endianness::LittleEndian => self.parse_impl::<LittleEndian>(),
143            Endianness::BigEndian => self.parse_impl::<BigEndian>(),
144        }
145    }
146
147    pub fn parse_impl<T: ByteOrder>(&self) -> Result<UserRecord<'a>, std::io::Error> {
148        let record_type = self.record_type;
149
150        let record = match record_type {
151            UserRecordType::PERF_HEADER_ATTR => {
152                UserRecord::HeaderAttr(HeaderAttr::parse::<T>(self.data)?)
153            }
154            UserRecordType::PERF_THREAD_MAP => {
155                UserRecord::ThreadMap(ThreadMap::parse::<T>(self.data)?)
156            }
157            UserRecordType::PERF_HEADER_FEATURE => {
158                UserRecord::HeaderFeature(HeaderFeature::parse::<T>(self.data)?)
159            }
160            // UserRecordType::PERF_HEADER_EVENT_TYPE => {},
161            // UserRecordType::PERF_HEADER_TRACING_DATA => {},
162            // UserRecordType::PERF_HEADER_BUILD_ID => {},
163            // UserRecordType::PERF_FINISHED_ROUND => {},
164            // UserRecordType::PERF_ID_INDEX => {},
165            // UserRecordType::PERF_AUXTRACE_INFO => {},
166            UserRecordType::PERF_AUXTRACE => UserRecord::Auxtrace(Auxtrace::parse::<T>(self.data)?),
167            // UserRecordType::PERF_AUXTRACE_ERROR => {},
168            // UserRecordType::PERF_CPU_MAP => {},
169            // UserRecordType::PERF_STAT_CONFIG => {},
170            // UserRecordType::PERF_STAT => {},
171            // UserRecordType::PERF_STAT_ROUND => {},
172            // UserRecordType::PERF_EVENT_UPDATE => {},
173            // UserRecordType::PERF_TIME_CONV => {},
174            // UserRecordType::PERF_COMPRESSED => {},
175            // UserRecordType::SIMPLEPERF_KERNEL_SYMBOL => {},
176            // UserRecordType::SIMPLEPERF_DSO => {},
177            // UserRecordType::SIMPLEPERF_SYMBOL => {},
178            // UserRecordType::SIMPLEPERF_SPLIT => {},
179            // UserRecordType::SIMPLEPERF_SPLIT_END => {},
180            // UserRecordType::SIMPLEPERF_EVENT_ID => {},
181            // UserRecordType::SIMPLEPERF_CALLCHAIN => {},
182            // UserRecordType::SIMPLEPERF_UNWINDING_RESULT => {},
183            // UserRecordType::SIMPLEPERF_TRACING_DATA => {},
184            _ => UserRecord::Raw(self.clone()),
185        };
186        Ok(record)
187    }
188}
189
190/// PERF_RECORD_HEADER_ATTR - Contains event attribute and associated event IDs
191///
192/// Used in pipe mode to transmit event attribute information that would
193/// otherwise be in the attrs section of a regular perf.data file.
194#[derive(Debug, Clone)]
195pub struct HeaderAttr {
196    pub attr: PerfEventAttr,
197    pub ids: Vec<u64>,
198}
199
200impl HeaderAttr {
201    pub fn parse<T: ByteOrder>(data: RawData) -> Result<Self, std::io::Error> {
202        let mut cursor = std::io::Cursor::new(data.as_slice());
203
204        // Parse the perf_event_attr
205        let (attr, _attr_size) = PerfEventAttr::parse::<_, T>(&mut cursor)?;
206
207        // Remaining data is the array of event IDs
208        let mut ids = Vec::new();
209        while cursor.position() < data.len() as u64 {
210            ids.push(cursor.read_u64::<T>()?);
211        }
212
213        Ok(Self { attr, ids })
214    }
215}
216
217/// PERF_RECORD_HEADER_FEATURE - Contains feature section data
218///
219/// Used in pipe mode to transmit feature data that would otherwise be in
220/// the feature sections at the end of a regular perf.data file.
221#[derive(Debug, Clone)]
222pub struct HeaderFeature {
223    pub feature: Feature,
224    pub data: Vec<u8>,
225}
226
227impl HeaderFeature {
228    pub fn parse<T: ByteOrder>(data: RawData) -> Result<Self, std::io::Error> {
229        let mut cursor = std::io::Cursor::new(data.as_slice());
230
231        // First 8 bytes is the feature type
232        let feature_type = cursor.read_u64::<T>()? as u32;
233        let feature = Feature(feature_type);
234
235        // Remaining data is the feature data itself
236        let start_pos = cursor.position() as usize;
237        let feature_data = data.as_slice()[start_pos..].to_vec();
238
239        Ok(Self {
240            feature,
241            data: feature_data,
242        })
243    }
244}