linux_perf_event_reader/
sample.rs1use byteorder::ByteOrder;
2
3use crate::{BranchSampleFormat, CpuMode, RawData, RawDataU64, ReadFormat, SampleFormat};
4
5use super::{RecordParseInfo, Regs};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct SampleRecord<'a> {
9 pub id: Option<u64>,
10 pub addr: Option<u64>,
11 pub stream_id: Option<u64>,
12 pub raw: Option<RawData<'a>>,
13 pub ip: Option<u64>,
14 pub timestamp: Option<u64>,
15 pub pid: Option<i32>,
16 pub tid: Option<i32>,
17 pub cpu: Option<u32>,
18 pub period: Option<u64>,
19 pub user_regs: Option<Regs<'a>>,
20 pub user_stack: Option<(RawData<'a>, u64)>,
21 pub callchain: Option<RawDataU64<'a>>,
22 pub phys_addr: Option<u64>,
23 pub data_page_size: Option<u64>,
24 pub code_page_size: Option<u64>,
25 pub intr_regs: Option<Regs<'a>>,
26 pub cpu_mode: CpuMode,
27}
28
29impl<'a> SampleRecord<'a> {
30 pub fn parse<T: ByteOrder>(
31 data: RawData<'a>,
32 misc: u16,
33 parse_info: &RecordParseInfo,
34 ) -> Result<Self, std::io::Error> {
35 let sample_format = parse_info.sample_format;
36 let branch_sample_format = parse_info.branch_sample_format;
37 let read_format = parse_info.read_format;
38 let sample_regs_user = parse_info.sample_regs_user;
39 let user_regs_count = parse_info.user_regs_count;
40 let sample_regs_intr = parse_info.sample_regs_intr;
41 let intr_regs_count = parse_info.intr_regs_count;
42 let cpu_mode = CpuMode::from_misc(misc);
43 let mut cur = data;
44
45 let identifier = if sample_format.contains(SampleFormat::IDENTIFIER) {
46 Some(cur.read_u64::<T>()?)
47 } else {
48 None
49 };
50
51 let ip = if sample_format.contains(SampleFormat::IP) {
52 Some(cur.read_u64::<T>()?)
53 } else {
54 None
55 };
56
57 let (pid, tid) = if sample_format.contains(SampleFormat::TID) {
58 let pid = cur.read_i32::<T>()?;
59 let tid = cur.read_i32::<T>()?;
60 (Some(pid), Some(tid))
61 } else {
62 (None, None)
63 };
64
65 let timestamp = if sample_format.contains(SampleFormat::TIME) {
66 Some(cur.read_u64::<T>()?)
67 } else {
68 None
69 };
70
71 let addr = if sample_format.contains(SampleFormat::ADDR) {
72 Some(cur.read_u64::<T>()?)
73 } else {
74 None
75 };
76
77 let id = if sample_format.contains(SampleFormat::ID) {
78 Some(cur.read_u64::<T>()?)
79 } else {
80 None
81 };
82 let id = identifier.or(id);
83
84 let stream_id = if sample_format.contains(SampleFormat::STREAM_ID) {
85 Some(cur.read_u64::<T>()?)
86 } else {
87 None
88 };
89
90 let cpu = if sample_format.contains(SampleFormat::CPU) {
91 let cpu = cur.read_u32::<T>()?;
92 let _reserved = cur.read_u32::<T>()?;
93 Some(cpu)
94 } else {
95 None
96 };
97
98 let period = if sample_format.contains(SampleFormat::PERIOD) {
99 let period = cur.read_u64::<T>()?;
100 Some(period)
101 } else {
102 None
103 };
104
105 if sample_format.contains(SampleFormat::READ) {
106 if read_format.contains(ReadFormat::GROUP) {
107 let _value = cur.read_u64::<T>()?;
108 if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) {
109 let _time_enabled = cur.read_u64::<T>()?;
110 }
111 if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) {
112 let _time_running = cur.read_u64::<T>()?;
113 }
114 if read_format.contains(ReadFormat::ID) {
115 let _id = cur.read_u64::<T>()?;
116 }
117 } else {
118 let nr = cur.read_u64::<T>()?;
119 if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) {
120 let _time_enabled = cur.read_u64::<T>()?;
121 }
122 if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) {
123 let _time_running = cur.read_u64::<T>()?;
124 }
125 for _ in 0..nr {
126 let _value = cur.read_u64::<T>()?;
127 if read_format.contains(ReadFormat::ID) {
128 let _id = cur.read_u64::<T>()?;
129 }
130 }
131 }
132 }
133
134 let callchain = if sample_format.contains(SampleFormat::CALLCHAIN) {
135 let callchain_length = cur.read_u64::<T>()?;
136 let callchain =
137 cur.split_off_prefix(callchain_length as usize * std::mem::size_of::<u64>())?;
138 Some(RawDataU64::from_raw_data::<T>(callchain))
139 } else {
140 None
141 };
142
143 let raw = if sample_format.contains(SampleFormat::RAW) {
144 let size = cur.read_u32::<T>()?;
145 Some(cur.split_off_prefix(size as usize)?)
146 } else {
147 None
148 };
149
150 if sample_format.contains(SampleFormat::BRANCH_STACK) {
151 let nr = cur.read_u64::<T>()?;
152 if branch_sample_format.contains(BranchSampleFormat::HW_INDEX) {
153 let _hw_idx = cur.read_u64::<T>()?;
154 }
155 for _ in 0..nr {
156 let _from = cur.read_u64::<T>()?;
157 let _to = cur.read_u64::<T>()?;
158 let _flags = cur.read_u64::<T>()?;
159 }
160 }
161
162 let user_regs = if sample_format.contains(SampleFormat::REGS_USER) {
163 let regs_abi = cur.read_u64::<T>()?;
164 if regs_abi == 0 {
165 None
166 } else {
167 let regs_data =
168 cur.split_off_prefix(user_regs_count as usize * std::mem::size_of::<u64>())?;
169 let raw_regs = RawDataU64::from_raw_data::<T>(regs_data);
170 let user_regs = Regs::new(sample_regs_user, raw_regs);
171 Some(user_regs)
172 }
173 } else {
174 None
175 };
176
177 let user_stack = if sample_format.contains(SampleFormat::STACK_USER) {
178 let stack_size = cur.read_u64::<T>()?;
179 let stack = cur.split_off_prefix(stack_size as usize)?;
180
181 let dynamic_size = if stack_size != 0 {
182 cur.read_u64::<T>()?
183 } else {
184 0
185 };
186 Some((stack, dynamic_size))
187 } else {
188 None
189 };
190
191 if sample_format.contains(SampleFormat::WEIGHT) {
192 let _weight = cur.read_u64::<T>()?;
193 }
194
195 if sample_format.contains(SampleFormat::DATA_SRC) {
196 let _data_src = cur.read_u64::<T>()?;
197 }
198
199 if sample_format.contains(SampleFormat::TRANSACTION) {
200 let _transaction = cur.read_u64::<T>()?;
201 }
202
203 let intr_regs = if sample_format.contains(SampleFormat::REGS_INTR) {
204 let regs_abi = cur.read_u64::<T>()?;
205 if regs_abi == 0 {
206 None
207 } else {
208 let regs_data =
209 cur.split_off_prefix(intr_regs_count as usize * std::mem::size_of::<u64>())?;
210 let raw_regs = RawDataU64::from_raw_data::<T>(regs_data);
211 let intr_regs = Regs::new(sample_regs_intr, raw_regs);
212 Some(intr_regs)
213 }
214 } else {
215 None
216 };
217
218 let phys_addr = if sample_format.contains(SampleFormat::PHYS_ADDR) {
219 Some(cur.read_u64::<T>()?)
220 } else {
221 None
222 };
223
224 if sample_format.contains(SampleFormat::AUX) {
225 let size = cur.read_u64::<T>()?;
226 cur.skip(size as usize)?;
227 }
228
229 let data_page_size = if sample_format.contains(SampleFormat::DATA_PAGE_SIZE) {
230 Some(cur.read_u64::<T>()?)
231 } else {
232 None
233 };
234
235 let code_page_size = if sample_format.contains(SampleFormat::CODE_PAGE_SIZE) {
236 Some(cur.read_u64::<T>()?)
237 } else {
238 None
239 };
240
241 Ok(Self {
242 id,
243 ip,
244 addr,
245 stream_id,
246 raw,
247 user_regs,
248 user_stack,
249 callchain,
250 cpu,
251 timestamp,
252 pid,
253 tid,
254 period,
255 intr_regs,
256 phys_addr,
257 data_page_size,
258 code_page_size,
259 cpu_mode,
260 })
261 }
262}