perf_event_data/records/
read.rs

1use crate::error::ParseError;
2use crate::prelude::*;
3use std::borrow::Cow;
4use std::fmt;
5use std::iter::FusedIterator;
6
7/// READ events happen when the kernel records the counters on its own.
8///
9/// This only happens when `inherit_stat` is enabled.
10///
11/// This struct corresponds to `PERF_RECORD_READ`. See the [manpage] for more
12/// documentation.
13///
14/// [manpage]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
15#[derive(Clone, Debug)]
16pub struct Read {
17    /// The process ID.
18    pub pid: u32,
19
20    /// The thread ID.
21    pub tid: u32,
22
23    /// The value read from the counter during task switch.
24    pub values: ReadValue,
25}
26
27/// Data read from a counter.
28#[derive(Clone)]
29pub struct ReadValue {
30    read_format: ReadFormat,
31    value: u64,
32    time_enabled: u64,
33    time_running: u64,
34    id: u64,
35    lost: u64,
36}
37
38impl ReadValue {
39    /// Create a `ReadValue` from a `ReadGroup` and its entry within that group.
40    pub fn from_group_and_entry(group: &ReadGroup<'_>, entry: &GroupEntry) -> Self {
41        Self {
42            read_format: group.read_format - ReadFormat::GROUP,
43            value: entry.value,
44            time_enabled: group.time_enabled,
45            time_running: group.time_running,
46            id: entry.id,
47            lost: entry.lost,
48        }
49    }
50
51    /// The value of the counter.
52    pub fn value(&self) -> u64 {
53        self.value
54    }
55
56    /// The duration for which this event was enabled, in nanoseconds.
57    pub fn time_enabled(&self) -> Option<u64> {
58        self.read_format
59            .contains(ReadFormat::TOTAL_TIME_ENABLED)
60            .then_some(self.time_enabled)
61    }
62
63    /// The duration for which this event was running, in nanoseconds.
64    ///
65    /// This will be less than `time_enabled` if the kernel ended up having to
66    /// multiplex multiple counters on the CPU.
67    pub fn time_running(&self) -> Option<u64> {
68        self.read_format
69            .contains(ReadFormat::TOTAL_TIME_RUNNING)
70            .then_some(self.time_running)
71    }
72
73    /// The kernel-assigned unique ID for the counter.
74    pub fn id(&self) -> Option<u64> {
75        self.read_format.contains(ReadFormat::ID).then_some(self.id)
76    }
77
78    /// The number of lost samples of this event.
79    pub fn lost(&self) -> Option<u64> {
80        self.read_format
81            .contains(ReadFormat::LOST)
82            .then_some(self.lost)
83    }
84}
85
86impl TryFrom<ReadGroup<'_>> for ReadValue {
87    type Error = TryFromGroupError;
88
89    fn try_from(value: ReadGroup<'_>) -> Result<Self, Self::Error> {
90        let mut entries = value.entries();
91        let entry = entries.next().ok_or(TryFromGroupError(()))?;
92
93        if entries.next().is_some() {
94            return Err(TryFromGroupError(()));
95        }
96
97        Ok(Self {
98            read_format: value.read_format - ReadFormat::GROUP,
99            value: entry.value(),
100            time_enabled: value.time_enabled,
101            time_running: value.time_running,
102            id: entry.id,
103            lost: entry.lost,
104        })
105    }
106}
107
108impl fmt::Debug for ReadValue {
109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        let read_format = self.read_format;
111        let mut dbg = debug_if! {
112            f.debug_struct("SingleRead") => {
113                value => self.value,
114                time_enabled if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) => self.time_enabled,
115                time_running if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) => self.time_running,
116                id if read_format.contains(ReadFormat::ID) => self.id,
117                lost if read_format.contains(ReadFormat::LOST) => self.lost,
118
119            }
120        };
121
122        dbg.finish_non_exhaustive()
123    }
124}
125
126/// The values read from a group of counters.
127#[derive(Clone)]
128pub struct ReadGroup<'a> {
129    read_format: ReadFormat,
130    time_enabled: u64,
131    time_running: u64,
132    data: Cow<'a, [u64]>,
133}
134
135impl<'a> ReadGroup<'a> {
136    /// The number of counters contained within this group.
137    pub fn len(&self) -> usize {
138        self.entries().count()
139    }
140
141    /// Whether this group has any counters at all.
142    pub fn is_empty(&self) -> bool {
143        self.len() == 0
144    }
145
146    /// Convert all the borrowed data in this `ReadGroup` into owned data.
147    pub fn into_owned(self) -> ReadGroup<'static> {
148        ReadGroup {
149            data: self.data.into_owned().into(),
150            ..self
151        }
152    }
153
154    /// The duration for which this event was enabled, in nanoseconds.
155    pub fn time_enabled(&self) -> Option<u64> {
156        self.read_format
157            .contains(ReadFormat::TOTAL_TIME_ENABLED)
158            .then_some(self.time_enabled)
159    }
160
161    /// The duration for which this event was running, in nanoseconds.
162    ///
163    /// This will be less than `time_enabled` if the kernel ended up having to
164    /// multiplex multiple counters on the CPU.
165    pub fn time_running(&self) -> Option<u64> {
166        self.read_format
167            .contains(ReadFormat::TOTAL_TIME_RUNNING)
168            .then_some(self.time_running)
169    }
170
171    /// Get a group entry by its index.
172    pub fn get(&self, index: usize) -> Option<GroupEntry> {
173        self.entries().nth(index)
174    }
175
176    /// Get a group entry by its counter id.
177    pub fn get_by_id(&self, id: u64) -> Option<GroupEntry> {
178        if !self.read_format.contains(ReadFormat::ID) {
179            return None;
180        }
181
182        self.entries().find(|entry| entry.id() == Some(id))
183    }
184
185    /// Iterate over the entries contained within this `GroupRead`.
186    pub fn entries(&self) -> GroupIter {
187        GroupIter::new(self)
188    }
189}
190
191impl<'a> From<ReadValue> for ReadGroup<'a> {
192    fn from(value: ReadValue) -> Self {
193        let mut data = Vec::with_capacity(3);
194        data.push(value.value());
195        data.extend(value.id());
196        data.extend(value.lost());
197
198        Self {
199            read_format: value.read_format | ReadFormat::GROUP,
200            time_enabled: value.time_enabled,
201            time_running: value.time_running,
202            data: Cow::Owned(data),
203        }
204    }
205}
206
207impl fmt::Debug for ReadGroup<'_> {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        struct Entries<'a>(GroupIter<'a>);
210
211        impl fmt::Debug for Entries<'_> {
212            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213                f.debug_list().entries(self.0.clone()).finish()
214            }
215        }
216
217        let read_format = self.read_format;
218        let mut dbg = debug_if! {
219            f.debug_struct("GroupRead") => {
220                time_enabled if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) => self.time_enabled,
221                time_running if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) => self.time_running,
222                entries => Entries(self.entries()),
223            }
224        };
225
226        dbg.finish_non_exhaustive()
227    }
228}
229
230/// The values read from a single perf event counter.
231///
232/// This will always include the counter value. The other fields are optional
233/// depending on how the counter's `read_format` was configured.
234#[derive(Copy, Clone)]
235pub struct GroupEntry {
236    read_format: ReadFormat,
237    value: u64,
238    id: u64,
239    lost: u64,
240}
241
242impl GroupEntry {
243    /// The value of the counter.
244    pub fn value(&self) -> u64 {
245        self.value
246    }
247
248    /// The kernel-assigned unique ID for the counter.
249    pub fn id(&self) -> Option<u64> {
250        self.read_format.contains(ReadFormat::ID).then_some(self.id)
251    }
252
253    /// The number of lost samples of this event.
254    pub fn lost(&self) -> Option<u64> {
255        self.read_format
256            .contains(ReadFormat::LOST)
257            .then_some(self.lost)
258    }
259
260    fn new(config: ReadFormat, slice: &[u64]) -> Self {
261        let mut iter = slice.iter().copied();
262        let mut read = || {
263            iter.next()
264                .expect("slice was not the correct size for the configured read_format")
265        };
266
267        Self {
268            read_format: config,
269            value: read(),
270            id: config.contains(ReadFormat::ID).then(&mut read).unwrap_or(0),
271            lost: config
272                .contains(ReadFormat::LOST)
273                .then(&mut read)
274                .unwrap_or(0),
275        }
276    }
277}
278
279impl fmt::Debug for GroupEntry {
280    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281        let read_format = self.read_format;
282
283        let mut dbg = debug_if! {
284            f.debug_struct("GroupEntry") => {
285                value => self.value(),
286                id if read_format.contains(ReadFormat::ID) => self.id,
287                lost if read_format.contains(ReadFormat::LOST) => self.lost,
288            }
289        };
290
291        dbg.finish_non_exhaustive()
292    }
293}
294
295/// Iterator over the entries of a group.
296///
297/// See [`ReadGroup::entries`].
298#[derive(Clone)]
299pub struct GroupIter<'a> {
300    iter: std::slice::ChunksExact<'a, u64>,
301    read_format: ReadFormat,
302}
303
304impl<'a> GroupIter<'a> {
305    fn new(group: &'a ReadGroup) -> Self {
306        let read_format = group.read_format;
307
308        Self {
309            iter: group.data.chunks_exact(read_format.element_len()),
310            read_format,
311        }
312    }
313}
314
315impl<'a> Iterator for GroupIter<'a> {
316    type Item = GroupEntry;
317
318    fn next(&mut self) -> Option<Self::Item> {
319        Some(GroupEntry::new(self.read_format, self.iter.next()?))
320    }
321
322    fn size_hint(&self) -> (usize, Option<usize>) {
323        self.iter.size_hint()
324    }
325
326    fn count(self) -> usize {
327        self.iter.count()
328    }
329
330    fn nth(&mut self, n: usize) -> Option<Self::Item> {
331        Some(GroupEntry::new(self.read_format, self.iter.nth(n)?))
332    }
333
334    fn last(self) -> Option<Self::Item> {
335        Some(GroupEntry::new(self.read_format, self.iter.last()?))
336    }
337}
338
339impl<'a> DoubleEndedIterator for GroupIter<'a> {
340    fn next_back(&mut self) -> Option<Self::Item> {
341        Some(GroupEntry::new(self.read_format, self.iter.next_back()?))
342    }
343
344    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
345        Some(GroupEntry::new(self.read_format, self.iter.nth_back(n)?))
346    }
347}
348
349impl<'a> ExactSizeIterator for GroupIter<'a> {
350    #[inline]
351    fn len(&self) -> usize {
352        self.iter.len()
353    }
354}
355
356impl<'a> FusedIterator for GroupIter<'a> {}
357
358impl<'p> Parse<'p> for ReadValue {
359    fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
360    where
361        E: Endian,
362        B: ParseBuf<'p>,
363    {
364        let read_format = p.config().read_format();
365
366        if read_format.contains(ReadFormat::GROUP) {
367            return Err(ParseError::custom(
368                ErrorKind::UnsupportedConfig,
369                "attempted to parse a SingleRead with a config that has GROUP set in read_format",
370            ));
371        }
372
373        if !(read_format - ReadFormat::all()).is_empty() {
374            return Err(ParseError::custom(
375                ErrorKind::UnsupportedConfig,
376                "read_format contains unsupported flags",
377            ));
378        }
379
380        Ok(Self {
381            read_format,
382            value: p.parse()?,
383            time_enabled: p
384                .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_ENABLED))?
385                .unwrap_or(0),
386            time_running: p
387                .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_RUNNING))?
388                .unwrap_or(0),
389            id: p
390                .parse_if(read_format.contains(ReadFormat::ID))?
391                .unwrap_or(0),
392            lost: p
393                .parse_if(read_format.contains(ReadFormat::LOST))?
394                .unwrap_or(0),
395        })
396    }
397}
398
399impl<'p> Parse<'p> for ReadGroup<'p> {
400    fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
401    where
402        E: Endian,
403        B: ParseBuf<'p>,
404    {
405        let read_format = p.config().read_format();
406
407        if !read_format.contains(ReadFormat::GROUP) {
408            return Err(ParseError::custom(
409                ErrorKind::UnsupportedConfig,
410                "attempted to parse a GroupRead with a config that does not have GROUP set in read_format"
411            ));
412        }
413
414        if !(read_format - ReadFormat::all()).is_empty() {
415            return Err(ParseError::custom(
416                ErrorKind::UnsupportedConfig,
417                "read_format contains unsupported flags",
418            ));
419        }
420
421        let nr = p.parse_u64()? as usize;
422        let time_enabled = p
423            .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_ENABLED))?
424            .unwrap_or(0);
425        let time_running = p
426            .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_RUNNING))?
427            .unwrap_or(0);
428
429        let element_len = read_format.element_len();
430        let data_len = nr //
431            .checked_mul(element_len)
432            .ok_or_else(|| {
433                ParseError::custom(
434                    ErrorKind::InvalidRecord,
435                    "number of elements in group read was too large for data type",
436                )
437            })?;
438        let data = unsafe { p.parse_slice(data_len)? };
439
440        Ok(Self {
441            read_format,
442            time_enabled,
443            time_running,
444            data,
445        })
446    }
447}
448
449impl<'p> Parse<'p> for Read {
450    fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
451    where
452        E: Endian,
453        B: ParseBuf<'p>,
454    {
455        Ok(Self {
456            pid: p.parse()?,
457            tid: p.parse()?,
458            values: p.parse()?,
459        })
460    }
461}
462
463/// Error when attempting to convert [`ReadGroup`] to a [`ReadValue`].
464#[derive(Clone, Debug)]
465pub struct TryFromGroupError(());
466
467impl fmt::Display for TryFromGroupError {
468    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469        f.write_str("can only convert groups with a single element to ReadValues")
470    }
471}
472
473impl std::error::Error for TryFromGroupError {}