linux_perf_event_reader/
common_data.rs

1use byteorder::{BigEndian, ByteOrder, LittleEndian};
2
3use crate::{Endianness, RawData, SampleFormat};
4
5use super::RecordParseInfo;
6
7#[derive(Clone, Debug, Default)]
8pub struct CommonData {
9    pub pid: Option<i32>,
10    pub tid: Option<i32>,
11    pub timestamp: Option<u64>,
12    pub id: Option<u64>,
13    pub stream_id: Option<u64>,
14    pub cpu: Option<u32>,
15}
16
17impl CommonData {
18    pub fn parse_sample(
19        data: RawData,
20        parse_info: &RecordParseInfo,
21    ) -> Result<Self, std::io::Error> {
22        match parse_info.endian {
23            Endianness::LittleEndian => Self::parse_sample_impl::<LittleEndian>(data, parse_info),
24            Endianness::BigEndian => Self::parse_sample_impl::<BigEndian>(data, parse_info),
25        }
26    }
27
28    pub fn parse_sample_impl<T: ByteOrder>(
29        data: RawData,
30        parse_info: &RecordParseInfo,
31    ) -> Result<Self, std::io::Error> {
32        let sample_format = parse_info.sample_format;
33
34        // { u64 id;       } && PERF_SAMPLE_IDENTIFIER
35        // { u64 ip;       } && PERF_SAMPLE_IP
36        // { u32 pid, tid; } && PERF_SAMPLE_TID
37        // { u64 time;     } && PERF_SAMPLE_TIME
38        // { u64 addr;     } && PERF_SAMPLE_ADDR
39        // { u64 id;       } && PERF_SAMPLE_ID
40        // { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
41        // { u32 cpu, res; } && PERF_SAMPLE_CPU
42        let mut cur = data;
43        let identifier = if sample_format.contains(SampleFormat::IDENTIFIER) {
44            Some(cur.read_u64::<T>()?)
45        } else {
46            None
47        };
48
49        if sample_format.contains(SampleFormat::IP) {
50            let _ip = cur.read_u64::<T>()?;
51        }
52
53        let (pid, tid) = if sample_format.contains(SampleFormat::TID) {
54            let pid = cur.read_i32::<T>()?;
55            let tid = cur.read_i32::<T>()?;
56            (Some(pid), Some(tid))
57        } else {
58            (None, None)
59        };
60
61        let timestamp = if sample_format.contains(SampleFormat::TIME) {
62            Some(cur.read_u64::<T>()?)
63        } else {
64            None
65        };
66
67        if sample_format.contains(SampleFormat::ADDR) {
68            let _addr = cur.read_u64::<T>()?;
69        }
70
71        let id = if sample_format.contains(SampleFormat::ID) {
72            Some(cur.read_u64::<T>()?)
73        } else {
74            None
75        };
76        let id = identifier.or(id);
77
78        let stream_id = if sample_format.contains(SampleFormat::STREAM_ID) {
79            Some(cur.read_u64::<T>()?)
80        } else {
81            None
82        };
83
84        let cpu = if sample_format.contains(SampleFormat::CPU) {
85            let cpu = cur.read_u32::<T>()?;
86            let _ = cur.read_u32::<T>()?; // Reserved field; is always zero.
87            Some(cpu)
88        } else {
89            None
90        };
91
92        Ok(CommonData {
93            pid,
94            tid,
95            timestamp,
96            id,
97            stream_id,
98            cpu,
99        })
100    }
101
102    pub fn parse_nonsample(
103        data: RawData,
104        parse_info: &RecordParseInfo,
105    ) -> Result<Self, std::io::Error> {
106        match parse_info.endian {
107            Endianness::LittleEndian => {
108                Self::parse_nonsample_impl::<LittleEndian>(data, parse_info)
109            }
110            Endianness::BigEndian => Self::parse_nonsample_impl::<BigEndian>(data, parse_info),
111        }
112    }
113
114    pub fn parse_nonsample_impl<T: ByteOrder>(
115        data: RawData,
116        parse_info: &RecordParseInfo,
117    ) -> Result<Self, std::io::Error> {
118        if let Some(common_data_offset_from_end) = parse_info.common_data_offset_from_end {
119            let common_data_offset_from_end = common_data_offset_from_end as usize;
120            let sample_format = parse_info.sample_format;
121
122            let mut cur = data;
123            let common_data_offset_from_start = cur
124                .len()
125                .checked_sub(common_data_offset_from_end)
126                .ok_or(std::io::ErrorKind::UnexpectedEof)?;
127            cur.skip(common_data_offset_from_start)?;
128
129            // struct sample_id {
130            //     { u32 pid, tid;  }   /* if PERF_SAMPLE_TID set */
131            //     { u64 timestamp; }   /* if PERF_SAMPLE_TIME set */
132            //     { u64 id;        }   /* if PERF_SAMPLE_ID set */
133            //     { u64 stream_id; }   /* if PERF_SAMPLE_STREAM_ID set  */
134            //     { u32 cpu, res;  }   /* if PERF_SAMPLE_CPU set */
135            //     { u64 identifier;}   /* if PERF_SAMPLE_IDENTIFIER set */
136            // };
137            let (pid, tid) = if sample_format.contains(SampleFormat::TID) {
138                let pid = cur.read_i32::<T>()?;
139                let tid = cur.read_i32::<T>()?;
140                (Some(pid), Some(tid))
141            } else {
142                (None, None)
143            };
144
145            let timestamp = if sample_format.contains(SampleFormat::TIME) {
146                Some(cur.read_u64::<T>()?)
147            } else {
148                None
149            };
150
151            let id = if sample_format.contains(SampleFormat::ID) {
152                Some(cur.read_u64::<T>()?)
153            } else {
154                None
155            };
156
157            let stream_id = if sample_format.contains(SampleFormat::STREAM_ID) {
158                Some(cur.read_u64::<T>()?)
159            } else {
160                None
161            };
162
163            let cpu = if sample_format.contains(SampleFormat::CPU) {
164                let cpu = cur.read_u32::<T>()?;
165                let _ = cur.read_u32::<T>()?; // Reserved field; is always zero.
166                Some(cpu)
167            } else {
168                None
169            };
170
171            let identifier = if sample_format.contains(SampleFormat::IDENTIFIER) {
172                Some(cur.read_u64::<T>()?)
173            } else {
174                None
175            };
176            let id = identifier.or(id);
177
178            Ok(CommonData {
179                pid,
180                tid,
181                timestamp,
182                id,
183                stream_id,
184                cpu,
185            })
186        } else {
187            Ok(Default::default())
188        }
189    }
190}