perf_event_open/sample/record/sample.rs
1use std::slice;
2
3use super::{RecordId, Task};
4use crate::count::Stat;
5use crate::ffi::{bindings as b, deref_offset};
6
7/// Sample.
8///
9/// Fields can be enabled via [`SampleFormat`][crate::config::SampleFormat].
10#[derive(Clone)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Sample {
13 /// Record IDs.
14 pub record_id: RecordId,
15
16 /// Counter statistics.
17 pub stat: Option<Stat>,
18 /// Sampling period.
19 pub period: Option<u64>,
20 /// Cgroup ID (for the perf event subsystem).
21 ///
22 /// To get the pathname of the cgroup, the ID should match to
23 /// [`Cgroup::id`][crate::sample::record::Cgroup::id].
24 pub cgroup: Option<u64>,
25 /// Call chain (stack backtrace).
26 pub call_chain: Option<Vec<u64>>,
27 /// User stack.
28 pub user_stack: Option<Vec<u8>>,
29
30 /// Data address.
31 ///
32 /// This is usually the address of a tracepoint, breakpoint, or software event;
33 /// otherwise the value is 0.
34 pub data_addr: Option<u64>,
35 /// Physical data address.
36 ///
37 /// Since `linux-4.14`: <https://github.com/torvalds/linux/commit/fc7ce9c74c3ad232b084d80148654f926d01ece7>
38 pub data_phys_addr: Option<u64>,
39 /// Page size of [data address][Self::data_addr].
40 ///
41 /// Since `linux-5.11`: <https://github.com/torvalds/linux/commit/8d97e71811aaafe4abf611dc24822fd6e73df1a1>
42 pub data_page_size: Option<u64>,
43 /// The source of data associated with the sampled instruction.
44 pub data_source: Option<DataSource>,
45
46 /// Code address (instruction pointer).
47 ///
48 /// The second member will be true if the instruction pointer points to the actual
49 /// instruction that triggered the event (0 [skid][crate::config::SampleSkid]).
50 pub code_addr: Option<(u64, bool)>,
51 /// Page size of [code address][Self::code_addr].
52 ///
53 /// Since `linux-5.11`: <https://github.com/torvalds/linux/commit/995f088efebe1eba0282a6ffa12411b37f8990c2>
54 pub code_page_size: Option<u64>,
55
56 /// Registers at sample time.
57 pub user_regs: Option<(Vec<u64>, Abi)>,
58 /// Registers at interrupt (event overflow).
59 pub intr_regs: Option<(Vec<u64>, Abi)>,
60
61 /// Raw data.
62 ///
63 /// This raw data is opaque with respect to the ABI. The ABI doesn't
64 /// make any promises with respect to the stability of its content,
65 /// it may vary depending on event, hardware, and kernel version.
66 pub raw: Option<Vec<u8>>,
67 /// LBR data.
68 ///
69 /// This provides a record of recent branches, as provided by
70 /// CPU branch sampling hardware (such as Intel LBR).
71 ///
72 /// Not all hardware supports this feature.
73 pub lbr: Option<Lbr>,
74 /// A snapshot of the AUX area.
75 pub aux: Option<Vec<u8>>,
76 /// The sources of any transactional memory aborts.
77 pub txn: Option<Txn>,
78 /// A hardware provided [weight][crate::sample::record::sample::Sample::weight]
79 /// value that expresses how costly the sampled event was.
80 ///
81 /// This allows the hardware to highlight expensive events in a profile.
82 pub weight: Option<Weight>,
83}
84
85impl Sample {
86 // https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L957
87 // struct {
88 // struct perf_event_header header;
89 // { u64 id; } && PERF_SAMPLE_IDENTIFIER
90 // { u64 ip; } && PERF_SAMPLE_IP
91 // { u32 pid, tid; } && PERF_SAMPLE_TID
92 // { u64 time; } && PERF_SAMPLE_TIME
93 // { u64 addr; } && PERF_SAMPLE_ADDR
94 // { u64 id; } && PERF_SAMPLE_ID
95 // { u64 stream_id; } && PERF_SAMPLE_STREAM_ID
96 // { u32 cpu, res; } && PERF_SAMPLE_CPU
97 // { u64 period; } && PERF_SAMPLE_PERIOD
98 // { struct read_format values; } && PERF_SAMPLE_READ
99 // {
100 // u64 nr,
101 // u64 ips[nr];
102 // } && PERF_SAMPLE_CALLCHAIN
103 // {
104 // u32 size;
105 // char data[size];
106 // } && PERF_SAMPLE_RAW
107 // {
108 // u64 nr;
109 // { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
110 // { u64 from, to, flags } lbr[nr];
111 // { u64 counters; } cntr[nr] && PERF_SAMPLE_BRANCH_COUNTERS
112 // } && PERF_SAMPLE_BRANCH_STACK
113 // {
114 // u64 abi; # enum perf_sample_regs_abi
115 // u64 regs[weight(mask)];
116 // } && PERF_SAMPLE_REGS_USER
117 // {
118 // u64 size;
119 // char data[size];
120 // u64 dyn_size;
121 // } && PERF_SAMPLE_STACK_USER
122 // union perf_sample_weight {
123 // u64 full; && PERF_SAMPLE_WEIGHT
124 // #if defined(__LITTLE_ENDIAN_BITFIELD)
125 // struct {
126 // u32 var1_dw;
127 // u16 var2_w;
128 // u16 var3_w;
129 // } && PERF_SAMPLE_WEIGHT_STRUCT
130 // #elif defined(__BIG_ENDIAN_BITFIELD)
131 // struct {
132 // u16 var3_w;
133 // u16 var2_w;
134 // u32 var1_dw;
135 // } && PERF_SAMPLE_WEIGHT_STRUCT
136 // #endif
137 // }
138 // { u64 data_src; } && PERF_SAMPLE_DATA_SRC
139 // { u64 transaction; } && PERF_SAMPLE_TRANSACTION
140 // {
141 // u64 abi; # enum perf_sample_regs_abi
142 // # https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7620
143 // { u64 regs[weight(mask)]; } # if abi != 0
144 // } && PERF_SAMPLE_REGS_INTR
145 // { u64 phys_addr; } && PERF_SAMPLE_PHYS_ADDR
146 // # https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7632
147 // { u64 cgroup; } && PERF_SAMPLE_CGROUP
148 // # About the order:
149 // # https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7635
150 // { u64 data_page_size; } && PERF_SAMPLE_DATA_PAGE_SIZE
151 // { u64 code_page_size; } && PERF_SAMPLE_CODE_PAGE_SIZE
152 // {
153 // u64 size;
154 // char data[size];
155 // } && PERF_SAMPLE_AUX
156 // };
157 pub(crate) unsafe fn from_ptr(
158 mut ptr: *const u8,
159 misc: u16,
160 read_format: u64,
161 sample_type: u64,
162 user_regs: usize,
163 intr_regs: usize,
164 branch_sample_type: u64,
165 ) -> Self {
166 macro_rules! when {
167 ($($feature: literal,)? $flag:ident, $ty:ty) => {{
168 $(#[cfg(feature = $feature)])?
169 let val = (sample_type & (b::$flag as u64) > 0).then(|| deref_offset::<$ty>(&mut ptr));
170 $(
171 #[cfg(not(feature = $feature))]
172 let val = None;
173 )?
174 val
175 }};
176 ($flag:ident) => {
177 sample_type & (b::$flag as u64) > 0
178 };
179 ($($feature: literal,)? $flag:ident, $then:expr) => {{
180 $(#[cfg(feature = $feature)])?
181 let val = (sample_type & (b::$flag as u64) > 0).then(|| $then);
182 $(
183 #[cfg(not(feature = $feature))]
184 let val = None;
185 )?
186 val
187 }};
188 }
189
190 // For `PERF_SAMPLE_IDENTIFIER`:
191 // `PERF_SAMPLE_IDENTIFIER` just duplicates the `PERF_SAMPLE_ID` at a fixed offset,
192 // it's useful to distinguish the sample format if multiple events share the same rb.
193 // Our design does not support redirecting samples to another rb (e.g., `PERF_FLAG_FD_OUTPUT`),
194 // and this is not a parser crate, so `PERF_SAMPLE_IDENTIFIER` is not needed.
195 // See:
196 // https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7342
197 // https://github.com/torvalds/linux/blob/v6.13/tools/perf/Documentation/perf.data-file-format.txt#L466
198 // https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L12808
199
200 let code_addr = when!(PERF_SAMPLE_IP, {
201 (
202 deref_offset(&mut ptr),
203 misc as u32 & b::PERF_RECORD_MISC_EXACT_IP > 0,
204 )
205 });
206 let task = when!(
207 PERF_SAMPLE_TID,
208 Task {
209 pid: deref_offset(&mut ptr),
210 tid: deref_offset(&mut ptr),
211 }
212 );
213 let time = when!(PERF_SAMPLE_TIME, u64);
214 let data_addr = when!(PERF_SAMPLE_ADDR, u64);
215 let id = when!(PERF_SAMPLE_ID, u64);
216 let stream_id = when!(PERF_SAMPLE_STREAM_ID, u64);
217 let cpu = when!(PERF_SAMPLE_CPU, {
218 let val = deref_offset(&mut ptr);
219 ptr = ptr.add(size_of::<u32>());
220 val
221 });
222 let period = when!(PERF_SAMPLE_PERIOD, u64);
223 let stat = when!(PERF_SAMPLE_READ, {
224 Stat::from_ptr_offset(&mut ptr, read_format)
225 });
226 let call_chain = when!(PERF_SAMPLE_CALLCHAIN, {
227 let len = deref_offset::<u64>(&mut ptr) as usize;
228 let ips = slice::from_raw_parts(ptr as *const u64, len);
229 ptr = ptr.add(len * size_of::<u64>());
230 ips.to_vec()
231 });
232 let raw = when!(PERF_SAMPLE_RAW, {
233 let len = deref_offset::<u32>(&mut ptr) as usize;
234 let bytes = slice::from_raw_parts(ptr, len);
235 ptr = ptr.add(len);
236 // https://github.com/torvalds/linux/blob/v6.13/include/linux/perf_event.h#L1303
237 ptr = ptr.add(ptr.align_offset(align_of::<u64>()));
238 bytes.to_vec()
239 });
240 let lbr = when!(PERF_SAMPLE_BRANCH_STACK, {
241 parse_lbr(&mut ptr, branch_sample_type)
242 })
243 .flatten();
244 let user_regs = when!(PERF_SAMPLE_REGS_USER, { parse_regs(&mut ptr, user_regs) }).flatten();
245 let user_stack = when!(PERF_SAMPLE_STACK_USER, {
246 let len = deref_offset::<u64>(&mut ptr) as usize;
247 let bytes = slice::from_raw_parts(ptr, len);
248 ptr = ptr.add(len);
249 let dyn_len = if len > 0 {
250 deref_offset::<u64>(&mut ptr) as usize
251 } else {
252 0
253 };
254 bytes[..dyn_len].to_vec()
255 });
256 #[cfg(feature = "linux-5.12")]
257 let weight = if when!(PERF_SAMPLE_WEIGHT) {
258 let full = Weight::Full(deref_offset(&mut ptr));
259 Some(full)
260 } else if when!(PERF_SAMPLE_WEIGHT_STRUCT) {
261 #[cfg(target_endian = "little")]
262 let vars = Weight::Vars {
263 var1: deref_offset(&mut ptr),
264 var2: deref_offset(&mut ptr),
265 var3: deref_offset(&mut ptr),
266 };
267 #[cfg(target_endian = "big")]
268 let vars = Weight::Vars {
269 var3: deref_offset(&mut ptr),
270 var2: deref_offset(&mut ptr),
271 var1: deref_offset(&mut ptr),
272 };
273 Some(vars)
274 } else {
275 None
276 };
277 #[cfg(not(feature = "linux-5.12"))]
278 let weight = when!(PERF_SAMPLE_WEIGHT, { Weight::Full(deref_offset(&mut ptr)) });
279 let data_source = when!(PERF_SAMPLE_DATA_SRC, { parse_data_source(&mut ptr) });
280 let txn = when!(PERF_SAMPLE_TRANSACTION, { parse_txn(&mut ptr) });
281 let intr_regs = when!(PERF_SAMPLE_REGS_INTR, { parse_regs(&mut ptr, intr_regs) }).flatten();
282 let data_phys_addr = when!("linux-4.14", PERF_SAMPLE_PHYS_ADDR, u64);
283 let cgroup = when!("linux-5.7", PERF_SAMPLE_CGROUP, u64);
284 let data_page_size = when!("linux-5.11", PERF_SAMPLE_DATA_PAGE_SIZE, u64);
285 let code_page_size = when!("linux-5.11", PERF_SAMPLE_CODE_PAGE_SIZE, u64);
286 let aux = when!("linux-5.5", PERF_SAMPLE_AUX, {
287 let len = deref_offset::<u64>(&mut ptr) as usize;
288 let bytes = slice::from_raw_parts(ptr, len as _);
289 bytes.to_vec()
290 });
291
292 Self {
293 record_id: RecordId {
294 id,
295 stream_id,
296 cpu,
297 task,
298 time,
299 },
300
301 stat,
302 period,
303 cgroup,
304 call_chain,
305 user_stack,
306
307 data_addr,
308 data_phys_addr,
309 data_page_size,
310 data_source,
311
312 code_addr,
313 code_page_size,
314
315 user_regs,
316 intr_regs,
317
318 raw,
319 lbr,
320 aux,
321 txn,
322 weight,
323 }
324 }
325}
326
327super::from!(Sample);
328
329super::debug!(Sample {
330 {record_id},
331 {stat?},
332 {period?},
333 {cgroup?},
334 {call_chain?},
335 {user_stack?},
336 {data_source?},
337 {data_addr?},
338 {data_phys_addr?},
339 {data_page_size?},
340 {code_addr?},
341 {code_page_size?},
342 {user_regs?},
343 {intr_regs?},
344 {raw?},
345 {lbr?},
346 {aux?},
347 {txn?},
348 {weight?},
349});
350
351unsafe fn parse_regs(ptr: &mut *const u8, len: usize) -> Option<(Vec<u64>, Abi)> {
352 let abi = deref_offset::<u64>(ptr) as u32;
353
354 // PERF_SAMPLE_REGS_USER: https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7589
355 // PERF_SAMPLE_REGS_INTR: https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7620
356 if abi == b::PERF_SAMPLE_REGS_ABI_NONE {
357 return None;
358 }
359
360 let regs = slice::from_raw_parts(*ptr as *const u64, len);
361 *ptr = ptr.add(len * size_of::<u64>());
362 let abi = match abi {
363 b::PERF_SAMPLE_REGS_ABI_32 => Abi::_32,
364 b::PERF_SAMPLE_REGS_ABI_64 => Abi::_64,
365 _ => unimplemented!(),
366 };
367
368 Some((regs.to_vec(), abi))
369}
370
371unsafe fn parse_lbr(ptr: &mut *const u8, branch_sample_type: u64) -> Option<Lbr> {
372 let len = deref_offset::<u64>(ptr) as usize;
373 // https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7575
374 if len == 0 {
375 return None;
376 }
377
378 // https://github.com/torvalds/linux/blob/v6.13/kernel/events/core.c#L7560
379 #[cfg(feature = "linux-5.7")]
380 let hw_index = (branch_sample_type & b::PERF_SAMPLE_BRANCH_HW_INDEX as u64 > 0)
381 .then(|| deref_offset::<u64>(ptr));
382 #[cfg(not(feature = "linux-5.7"))]
383 let _ = branch_sample_type;
384 #[cfg(not(feature = "linux-5.7"))]
385 let hw_index = None;
386
387 #[repr(C)]
388 struct Layout {
389 from: u64,
390 to: u64,
391 bits: u64,
392 }
393 fn to_entry(layout: &Layout, counter: Option<u64>) -> Entry {
394 let bits = layout.bits;
395
396 macro_rules! when {
397 ($flag:expr) => {
398 bits & $flag > 0
399 };
400 }
401
402 Entry {
403 counter,
404
405 from: layout.from,
406 to: layout.to,
407
408 // https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1439
409 mis: when!(0b1), // 0, 1 bit
410 pred: when!(0b10), // 1, 1 bit
411 in_tx: when!(0b100), // 2, 1 bit
412 abort: when!(0b1000), // 3, 1 bit
413 cycles: (bits >> 4) as _, // 4-19, 16 bits
414 #[cfg(feature = "linux-4.14")]
415 // 20-23, 4 bits
416 branch_type: match ((bits >> 20) & 0b1111) as _ {
417 b::PERF_BR_UNKNOWN => BranchType::Unknown,
418 b::PERF_BR_COND => BranchType::Cond,
419 b::PERF_BR_UNCOND => BranchType::Uncond,
420 b::PERF_BR_IND => BranchType::Ind,
421 b::PERF_BR_CALL => BranchType::Call,
422 b::PERF_BR_IND_CALL => BranchType::IndCall,
423 b::PERF_BR_RET => BranchType::Ret,
424 b::PERF_BR_SYSCALL => BranchType::Syscall,
425 b::PERF_BR_SYSRET => BranchType::Sysret,
426 b::PERF_BR_COND_CALL => BranchType::CondCall,
427 b::PERF_BR_COND_RET => BranchType::CondRet,
428 #[cfg(feature = "linux-5.18")]
429 b::PERF_BR_ERET => BranchType::Eret,
430 #[cfg(feature = "linux-5.18")]
431 b::PERF_BR_IRQ => BranchType::Irq,
432 #[cfg(feature = "linux-6.1")]
433 b::PERF_BR_SERROR => BranchType::SysErr,
434 #[cfg(feature = "linux-6.1")]
435 b::PERF_BR_NO_TX => BranchType::NoTx,
436 #[cfg(feature = "linux-6.1")]
437 // match new_type
438 // https://github.com/torvalds/linux/blob/v6.13/tools/perf/util/branch.c#L106
439 b::PERF_BR_EXTEND_ABI => match ((bits >> 26) & 0b1111) as _ {
440 b::PERF_BR_NEW_FAULT_DATA => BranchType::DataFault,
441 b::PERF_BR_NEW_FAULT_ALGN => BranchType::AlignFault,
442 b::PERF_BR_NEW_FAULT_INST => BranchType::InstrFault,
443 b::PERF_BR_NEW_ARCH_1 => BranchType::Arch1,
444 b::PERF_BR_NEW_ARCH_2 => BranchType::Arch2,
445 b::PERF_BR_NEW_ARCH_3 => BranchType::Arch3,
446 b::PERF_BR_NEW_ARCH_4 => BranchType::Arch4,
447 b::PERF_BR_NEW_ARCH_5 => BranchType::Arch5,
448 // For compatibility, not ABI.
449 _ => BranchType::Unknown,
450 },
451 // For compatibility, not ABI.
452 _ => BranchType::Unknown,
453 },
454 #[cfg(not(feature = "linux-4.14"))]
455 branch_type: BranchType::Unknown,
456 #[cfg(feature = "linux-6.1")]
457 // 24-25, 2 bits
458 branch_spec: match ((bits >> 24) & 0b11) as _ {
459 b::PERF_BR_SPEC_NA => BranchSpec::Na,
460 b::PERF_BR_SPEC_WRONG_PATH => BranchSpec::Wrong,
461 b::PERF_BR_NON_SPEC_CORRECT_PATH => BranchSpec::NoSpecCorrect,
462 b::PERF_BR_SPEC_CORRECT_PATH => BranchSpec::Correct,
463 _ => unreachable!(),
464 },
465 #[cfg(not(feature = "linux-6.1"))]
466 branch_spec: BranchSpec::Na,
467 // new_type: 26-29, 4 bits
468 #[cfg(feature = "linux-6.1")]
469 // 30-32, 3 bits
470 branch_priv: match ((bits >> 30) & 0b111) as _ {
471 b::PERF_BR_PRIV_UNKNOWN => BranchPriv::Unknown,
472 b::PERF_BR_PRIV_USER => BranchPriv::User,
473 b::PERF_BR_PRIV_KERNEL => BranchPriv::Kernel,
474 b::PERF_BR_PRIV_HV => BranchPriv::Hv,
475 // For compatibility, not ABI.
476 _ => BranchPriv::Unknown,
477 },
478 #[cfg(not(feature = "linux-6.1"))]
479 branch_priv: BranchPriv::Unknown,
480 // reserved: 33-63, 31 bits
481 }
482 }
483
484 let layouts = slice::from_raw_parts(*ptr as *const Layout, len).iter();
485 // https://github.com/torvalds/linux/commit/571d91dcadfa3cef499010b4eddb9b58b0da4d24
486 #[cfg(feature = "linux-6.8")]
487 let has_counters = branch_sample_type & b::PERF_SAMPLE_BRANCH_COUNTERS as u64 > 0;
488 #[cfg(not(feature = "linux-6.8"))]
489 let has_counters = false;
490 let entries = if has_counters {
491 *ptr = ptr.add(len * size_of::<Layout>());
492 layouts
493 .map(|it| to_entry(it, Some(deref_offset(ptr))))
494 .collect()
495 } else {
496 layouts.map(|it| to_entry(it, None)).collect()
497 };
498
499 Some(Lbr { hw_index, entries })
500}
501
502unsafe fn parse_txn(ptr: &mut *const u8) -> Txn {
503 let bits: u64 = deref_offset(ptr);
504 let code = ((bits & b::PERF_TXN_ABORT_MASK) >> b::PERF_TXN_ABORT_SHIFT) as u32;
505 macro_rules! when {
506 ($flag:ident) => {
507 bits & b::$flag > 0
508 };
509 }
510 Txn {
511 elision: when!(PERF_TXN_ELISION),
512 tx: when!(PERF_TXN_TRANSACTION),
513 is_sync: when!(PERF_TXN_SYNC),
514 is_async: when!(PERF_TXN_ASYNC),
515 retry: when!(PERF_TXN_RETRY),
516 conflict: when!(PERF_TXN_CONFLICT),
517 capacity_read: when!(PERF_TXN_CAPACITY_READ),
518 capacity_write: when!(PERF_TXN_CAPACITY_WRITE),
519 code,
520 }
521}
522
523unsafe fn parse_data_source(ptr: &mut *const u8) -> DataSource {
524 let bits: u64 = deref_offset(ptr);
525
526 // u64 (little-endian):
527 // mem_op 0-4 5 bits, type of opcode
528 // mem_lvl 5-18 14 bits, memory hierarchy level
529 // mem_snoop 19-23 5 bits, snoop mode
530 // mem_lock 24-25 2 bits, lock instr
531 // mem_dtlb 26-32 7 bits, tlb access
532 // mem_lvl_num 33-36 4 bits, memory hierarchy level number
533 // mem_remote 37 1 bit, remote
534 // mem_snoopx 38-39 2 bits, snoop mode, ext
535 // mem_blk 40-42 3 bits, access blocked
536 // mem_hops 43-45 3 bits, hop level
537 // mem_rsvd 46-63 18 bits, reserved
538
539 macro_rules! when {
540 ($shifted:expr, $flag:ident) => {
541 $shifted & (b::$flag as u64) > 0
542 };
543 }
544
545 let op = MemOp {
546 na: when!(bits, PERF_MEM_OP_NA),
547 load: when!(bits, PERF_MEM_OP_LOAD),
548 store: when!(bits, PERF_MEM_OP_STORE),
549 prefetch: when!(bits, PERF_MEM_OP_PFETCH),
550 exec: when!(bits, PERF_MEM_OP_EXEC),
551 };
552
553 let shifted = bits >> b::PERF_MEM_LVL_SHIFT;
554 let level = MemLevel {
555 na: when!(shifted, PERF_MEM_LVL_NA),
556 hit: when!(shifted, PERF_MEM_LVL_HIT),
557 miss: when!(shifted, PERF_MEM_LVL_MISS),
558 l1: when!(shifted, PERF_MEM_LVL_L1),
559 lfb: when!(shifted, PERF_MEM_LVL_LFB),
560 l2: when!(shifted, PERF_MEM_LVL_L2),
561 l3: when!(shifted, PERF_MEM_LVL_L3),
562 loc_ram: when!(shifted, PERF_MEM_LVL_LOC_RAM),
563 rem_ram1: when!(shifted, PERF_MEM_LVL_REM_RAM1),
564 rem_ram2: when!(shifted, PERF_MEM_LVL_REM_RAM2),
565 rem_cce1: when!(shifted, PERF_MEM_LVL_REM_CCE1),
566 rem_cce2: when!(shifted, PERF_MEM_LVL_REM_CCE2),
567 io: when!(shifted, PERF_MEM_LVL_IO),
568 unc: when!(shifted, PERF_MEM_LVL_UNC),
569 };
570
571 let shifted1 = bits >> b::PERF_MEM_SNOOP_SHIFT;
572 #[cfg(feature = "linux-4.14")]
573 let shifted2 = bits >> b::PERF_MEM_SNOOPX_SHIFT;
574 let snoop = MemSnoop {
575 na: when!(shifted1, PERF_MEM_SNOOP_NA),
576 none: when!(shifted1, PERF_MEM_SNOOP_NONE),
577 hit: when!(shifted1, PERF_MEM_SNOOP_HIT),
578 miss: when!(shifted1, PERF_MEM_SNOOP_MISS),
579 hit_m: when!(shifted1, PERF_MEM_SNOOP_HITM),
580 #[cfg(feature = "linux-4.14")]
581 fwd: when!(shifted2, PERF_MEM_SNOOPX_FWD),
582 #[cfg(not(feature = "linux-4.14"))]
583 fwd: false,
584 #[cfg(feature = "linux-6.1")]
585 peer: when!(shifted2, PERF_MEM_SNOOPX_PEER),
586 #[cfg(not(feature = "linux-6.1"))]
587 peer: false,
588 };
589
590 let shifted = bits >> b::PERF_MEM_LOCK_SHIFT;
591 let lock = MemLock {
592 na: when!(shifted, PERF_MEM_LOCK_NA),
593 locked: when!(shifted, PERF_MEM_LOCK_LOCKED),
594 };
595
596 let shifted = bits >> b::PERF_MEM_TLB_SHIFT;
597 let tlb = MemTlb {
598 na: when!(shifted, PERF_MEM_TLB_NA),
599 hit: when!(shifted, PERF_MEM_TLB_HIT),
600 miss: when!(shifted, PERF_MEM_TLB_MISS),
601 l1: when!(shifted, PERF_MEM_TLB_L1),
602 l2: when!(shifted, PERF_MEM_TLB_L2),
603 walker: when!(shifted, PERF_MEM_TLB_WK),
604 fault: when!(shifted, PERF_MEM_TLB_OS),
605 };
606
607 #[cfg(feature = "linux-4.14")]
608 let shifted = bits >> b::PERF_MEM_LVLNUM_SHIFT;
609 #[cfg(feature = "linux-4.14")]
610 let level2 = match (shifted & 0b1111) as u32 {
611 b::PERF_MEM_LVLNUM_L1 => MemLevel2::L1,
612 b::PERF_MEM_LVLNUM_L2 => MemLevel2::L2,
613 b::PERF_MEM_LVLNUM_L3 => MemLevel2::L3,
614 b::PERF_MEM_LVLNUM_L4 => MemLevel2::L4,
615 #[cfg(feature = "linux-6.11")]
616 b::PERF_MEM_LVLNUM_L2_MHB => MemLevel2::L2Mhb,
617 #[cfg(feature = "linux-6.11")]
618 b::PERF_MEM_LVLNUM_MSC => MemLevel2::Msc,
619 #[cfg(feature = "linux-6.6")]
620 b::PERF_MEM_LVLNUM_UNC => MemLevel2::Unc,
621 #[cfg(feature = "linux-6.1")]
622 b::PERF_MEM_LVLNUM_CXL => MemLevel2::Cxl,
623 #[cfg(feature = "linux-6.1")]
624 b::PERF_MEM_LVLNUM_IO => MemLevel2::Io,
625 b::PERF_MEM_LVLNUM_ANY_CACHE => MemLevel2::AnyCache,
626 b::PERF_MEM_LVLNUM_LFB => MemLevel2::Lfb,
627 b::PERF_MEM_LVLNUM_RAM => MemLevel2::Ram,
628 b::PERF_MEM_LVLNUM_PMEM => MemLevel2::Pmem,
629 b::PERF_MEM_LVLNUM_NA => MemLevel2::Na,
630 // For compatibility, not ABI.
631 _ => MemLevel2::Unknown,
632 };
633 #[cfg(not(feature = "linux-4.14"))]
634 let level2 = MemLevel2::Unknown;
635
636 #[cfg(feature = "linux-4.14")]
637 let remote = (bits >> b::PERF_MEM_REMOTE_SHIFT) & 1 > 0;
638 #[cfg(not(feature = "linux-4.14"))]
639 let remote = false;
640
641 #[cfg(feature = "linux-5.12")]
642 let shifted = bits >> b::PERF_MEM_BLK_SHIFT;
643 #[cfg(feature = "linux-5.12")]
644 let block = MemBlock {
645 na: when!(shifted, PERF_MEM_BLK_NA),
646 data: when!(shifted, PERF_MEM_BLK_DATA),
647 addr: when!(shifted, PERF_MEM_BLK_ADDR),
648 };
649 #[cfg(not(feature = "linux-5.12"))]
650 let block = MemBlock {
651 na: false,
652 data: false,
653 addr: false,
654 };
655
656 #[cfg(feature = "linux-5.16")]
657 let shifted = bits >> b::PERF_MEM_HOPS_SHIFT;
658 #[cfg(feature = "linux-5.16")]
659 let hops = match (shifted & 0b111) as u32 {
660 b::PERF_MEM_HOPS_0 => MemHop::Core,
661 #[cfg(feature = "linux-5.17")]
662 b::PERF_MEM_HOPS_1 => MemHop::Node,
663 #[cfg(feature = "linux-5.17")]
664 b::PERF_MEM_HOPS_2 => MemHop::Socket,
665 #[cfg(feature = "linux-5.17")]
666 b::PERF_MEM_HOPS_3 => MemHop::Board,
667 // For compatibility, not ABI.
668 _ => MemHop::Unknown,
669 };
670 #[cfg(not(feature = "linux-5.16"))]
671 let hops = MemHop::Unknown;
672
673 DataSource {
674 op,
675 level,
676 snoop,
677 lock,
678 tlb,
679 level2,
680 remote,
681 block,
682 hops,
683 }
684}
685
686/// LBR data.
687#[derive(Clone)]
688#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
689pub struct Lbr {
690 /// The index in the underlying hardware buffer of the most recently
691 /// captured taken branch.
692 ///
693 /// It is very useful for reconstructing the call stack.
694 /// For example, in Intel LBR call stack mode, the depth of reconstructed
695 /// LBR call stack limits to the number of LBR registers. With the low level
696 /// index information, perf tool may stitch the stacks of two samples.
697 /// The reconstructed LBR call stack can break the hardware limitation.
698 ///
699 /// Since `linux-5.7`: <https://github.com/torvalds/linux/commit/bbfd5e4fab63703375eafaf241a0c696024a59e1>
700 pub hw_index: Option<u64>,
701
702 /// LBR entries.
703 pub entries: Vec<Entry>,
704}
705
706super::debug!(Lbr {
707 {hw_index?},
708 {entries},
709});
710
711// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1436
712/// LBR entry.
713#[derive(Clone, Debug)]
714#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
715pub struct Entry {
716 pub from: u64,
717 pub to: u64,
718
719 pub mis: bool,
720 pub pred: bool,
721 pub in_tx: bool,
722 pub abort: bool,
723 pub cycles: u16,
724
725 /// Since `linux-4.14`: <https://github.com/torvalds/linux/commit/eb0baf8a0d9259d168523b8e7c436b55ade7c546>
726 pub branch_type: BranchType,
727 /// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/93315e46b000fc80fff5d53c3f444417fb3df6de>
728 pub branch_spec: BranchSpec,
729 /// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/5402d25aa5710d240040f73fb13d7d5c303ef071>
730 pub branch_priv: BranchPriv,
731
732 // https://github.com/torvalds/linux/commit/571d91dcadfa3cef499010b4eddb9b58b0da4d24
733 /// This counter may store the occurrences of several events.
734 ///
735 /// Since `linux-6.8`: <https://github.com/torvalds/linux/commit/571d91dcadfa3cef499010b4eddb9b58b0da4d24>
736 pub counter: Option<u64>,
737}
738
739/// Branch types.
740///
741/// Since `linux-4.14`: <https://github.com/torvalds/linux/commit/eb0baf8a0d9259d168523b8e7c436b55ade7c546>
742#[derive(Clone, Debug)]
743#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
744pub enum BranchType {
745 // PERF_BR_*
746 // https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L248
747
748 // PERF_BR_UNKNOWN
749 /// Unknown.
750 Unknown,
751 // PERF_BR_COND
752 /// Conditional.
753 Cond,
754 // PERF_BR_UNCOND
755 /// Unconditional.
756 Uncond,
757 // PERF_BR_IND
758 /// Indirect.
759 Ind,
760 // PERF_BR_CALL
761 /// Function call.
762 Call,
763 // PERF_BR_IND_CALL
764 /// Indirect function call.
765 IndCall,
766 // PERF_BR_RET
767 /// Function return.
768 Ret,
769 // PERF_BR_SYSCALL
770 /// Syscall.
771 Syscall,
772 // PERF_BR_SYSRET
773 /// Syscall return.
774 Sysret,
775 // PERF_BR_COND_CALL
776 /// Conditional function call.
777 CondCall,
778 // PERF_BR_COND_RET
779 /// Conditional function return.
780 CondRet,
781 // PERF_BR_ERET
782 /// Exception return.
783 /// Since `linux-5.18`: <https://github.com/torvalds/linux/commit/cedd3614e5d9c80908099c19f8716714ce0610b1>
784 Eret,
785 // PERF_BR_IRQ
786 /// IRQ.
787 /// Since `linux-5.18`: <https://github.com/torvalds/linux/commit/cedd3614e5d9c80908099c19f8716714ce0610b1>
788 Irq,
789 // PERF_BR_SERROR
790 /// System error.
791 /// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/a724ec82966d57e4b5d36341d3e3dc1a3c011564>
792 SysErr,
793 // PERF_BR_NO_TX
794 /// Not in transaction.
795 /// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/a724ec82966d57e4b5d36341d3e3dc1a3c011564>
796 NoTx,
797
798 // PERF_BR_NEW_*
799 // https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L279
800
801 // PERF_BR_NEW_FAULT_DATA
802 /// Data fault.
803 DataFault,
804 // PERF_BR_NEW_FAULT_ALGN
805 /// Alignment fault.
806 AlignFault,
807 // PERF_BR_NEW_FAULT_INST
808 /// Instruction fault.
809 InstrFault,
810
811 // PERF_BR_NEW_ARCH_1
812 /// Architecture specific.
813 Arch1,
814 // PERF_BR_NEW_ARCH_2
815 /// Architecture specific.
816 Arch2,
817 // PERF_BR_NEW_ARCH_3
818 /// Architecture specific.
819 Arch3,
820 // PERF_BR_NEW_ARCH_4
821 /// Architecture specific.
822 Arch4,
823 // PERF_BR_NEW_ARCH_5
824 /// Architecture specific.
825 Arch5,
826}
827
828// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L271
829/// Branch speculation outcome classification.
830///
831/// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/93315e46b000fc80fff5d53c3f444417fb3df6de>
832#[derive(Clone, Debug)]
833#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
834pub enum BranchSpec {
835 // PERF_BR_SPEC_NA
836 /// Not available.
837 Na,
838 // PERF_BR_SPEC_WRONG_PATH
839 /// Speculative but on wrong path.
840 Wrong,
841 // PERF_BR_SPEC_CORRECT_PATH
842 /// Speculative and on correct path.
843 Correct,
844 // PERF_BR_NON_SPEC_CORRECT_PATH
845 /// Non-speculative but on correct path.
846 NoSpecCorrect,
847}
848
849// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L291
850/// Branch privilege levels.
851///
852/// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/5402d25aa5710d240040f73fb13d7d5c303ef071>
853#[derive(Clone, Debug)]
854#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
855pub enum BranchPriv {
856 // PERF_BR_PRIV_UNKNOWN
857 Unknown,
858 // PERF_BR_PRIV_USER
859 User,
860 // PERF_BR_PRIV_KERNEL
861 Kernel,
862 // PERF_BR_PRIV_HV
863 Hv,
864}
865
866/// Sampling weight.
867#[derive(Clone, Debug)]
868#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
869pub enum Weight {
870 Full(u64),
871 Vars { var1: u32, var2: u16, var3: u16 },
872}
873
874// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L322
875/// The sources of any transactional memory aborts.
876///
877#[derive(Clone, Debug)]
878#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
879pub struct Txn {
880 // PERF_TXN_ELISION
881 /// From elision.
882 pub elision: bool,
883 // PERF_TXN_TRANSACTION
884 /// From transaction.
885 pub tx: bool,
886 // PERF_TXN_SYNC
887 /// Aborts caused by current thread.
888 pub is_sync: bool,
889 // PERF_TXN_ASYNC
890 /// Aborts caused by other theads.
891 pub is_async: bool,
892 // PERF_TXN_RETRY
893 /// Retryable transaction.
894 pub retry: bool,
895 // PERF_TXN_CONFLICT
896 /// Conflicts with other threads.
897 pub conflict: bool,
898 // PERF_TXN_CAPACITY_READ
899 /// Transaction write capacity overflow.
900 pub capacity_read: bool,
901 // PERF_TXN_CAPACITY_WRITE
902 /// Transaction read capacity overflow.
903 pub capacity_write: bool,
904 // (flags & PERF_TXN_ABORT_MASK) >> PERF_TXN_ABORT_SHIFT
905 /// User-specified abort code.
906 pub code: u32,
907}
908
909// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1286
910/// The source of data associated with the sampled instruction.
911///
912#[derive(Clone, Debug)]
913#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
914pub struct DataSource {
915 /// Type of opcode.
916 pub op: MemOp,
917 /// Memory hierarchy levels.
918 pub level: MemLevel,
919 /// Snoop mode.
920 pub snoop: MemSnoop,
921 /// Locked instruction.
922 pub lock: MemLock,
923 /// TLB access.
924 pub tlb: MemTlb,
925 /// Memory hierarchy levels (V2).
926 ///
927 /// Since `linux-4.14`: <https://github.com/torvalds/linux/commit/6ae5fa61d27dcb055f4198bcf6c8dbbf1bb33f52>
928 pub level2: MemLevel2,
929 /// This can be combined with the memory hierarchy levels to signify a remote cache.
930 ///
931 /// Since `linux-4.14`: <https://github.com/torvalds/linux/commit/6ae5fa61d27dcb055f4198bcf6c8dbbf1bb33f52>
932 pub remote: bool,
933 /// Access blocked.
934 ///
935 /// Since `linux-5.12`: <https://github.com/torvalds/linux/commit/61b985e3e775a3a75fda04ce7ef1b1aefc4758bc>
936 pub block: MemBlock,
937 /// Hop level.
938 ///
939 /// Since `linux-5.16`: <https://github.com/torvalds/linux/commit/fec9cc6175d0ec1e13efe12be491d9bd4de62f80>
940 pub hops: MemHop,
941}
942
943// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1324
944/// Type of opcode.
945#[derive(Clone, Debug)]
946#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
947pub struct MemOp {
948 // PERF_MEM_OP_NA
949 /// Not available.
950 pub na: bool,
951 // PERF_MEM_OP_LOAD
952 /// Load instruction.
953 pub load: bool,
954 // PERF_MEM_OP_STORE
955 /// Store instruction.
956 pub store: bool,
957 // PERF_MEM_OP_PFETCH
958 /// Prefetch.
959 pub prefetch: bool,
960 // PERF_MEM_OP_EXEC
961 /// Code execution.
962 pub exec: bool,
963}
964
965// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1338
966/// Memory hierarchy levels.
967///
968/// This is being deprecated in favour of [`MemLevel2`].
969#[derive(Clone, Debug)]
970#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
971pub struct MemLevel {
972 // PERF_MEM_LVL_NA
973 /// Not available.
974 pub na: bool,
975 // PERF_MEM_LVL_HIT
976 /// Hit level.
977 pub hit: bool,
978 // PERF_MEM_LVL_MISS
979 /// Miss level.
980 pub miss: bool,
981 // PERF_MEM_LVL_L1
982 /// L1.
983 pub l1: bool,
984 // PERF_MEM_LVL_LFB
985 /// Line fill buffer.
986 pub lfb: bool,
987 // PERF_MEM_LVL_L2
988 /// L2.
989 pub l2: bool,
990 // PERF_MEM_LVL_L3
991 /// L3.
992 pub l3: bool,
993 // PERF_MEM_LVL_LOC_RAM
994 /// Local DRAM.
995 pub loc_ram: bool,
996 // PERF_MEM_LVL_REM_RAM1
997 /// Remote DRAM (1 hop).
998 pub rem_ram1: bool,
999 // PERF_MEM_LVL_REM_RAM2
1000 /// Remote DRAM (2 hops).
1001 pub rem_ram2: bool,
1002 // PERF_MEM_LVL_REM_CCE1
1003 /// Remote cache (1 hop).
1004 pub rem_cce1: bool,
1005 // PERF_MEM_LVL_REM_CCE2
1006 /// Remote cache (2 hops).
1007 pub rem_cce2: bool,
1008 // PERF_MEM_LVL_IO
1009 /// I/O memory.
1010 pub io: bool,
1011 // PERF_MEM_LVL_UNC
1012 /// Uncached memory.
1013 pub unc: bool,
1014}
1015
1016// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1376
1017/// Snoop mode.
1018#[derive(Clone, Debug)]
1019#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1020pub struct MemSnoop {
1021 // PERF_MEM_SNOOP_NA
1022 /// Not available.
1023 pub na: bool,
1024 // PERF_MEM_SNOOP_NONE
1025 /// No snoop.
1026 pub none: bool,
1027 // PERF_MEM_SNOOP_HIT
1028 /// Snoop hit.
1029 pub hit: bool,
1030 // PERF_MEM_SNOOP_MISS
1031 /// Snoop miss.
1032 pub miss: bool,
1033 // PERF_MEM_SNOOP_HITM
1034 /// Snoop hit modified.
1035 pub hit_m: bool,
1036 // PERF_MEM_SNOOPX_FWD
1037 /// Forward.
1038 /// Since `linux-4.14`: <https://github.com/torvalds/linux/commit/6ae5fa61d27dcb055f4198bcf6c8dbbf1bb33f52>
1039 pub fwd: bool,
1040 // PERF_MEM_SNOOPX_PEER
1041 /// Transfer from peer.
1042 ///
1043 /// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/cfef80bad4cf79cdc964a53c98254dfa462be83f>
1044 ///
1045 /// NOTE: This feature was first available in the perf tool in Linux 6.0,
1046 /// so it seems we should enable it in feature `linux-6.0`:
1047 /// <https://github.com/torvalds/linux/commit/2e21bcf0514a3623b41962bf424dec061c02ebc6>
1048 pub peer: bool,
1049}
1050
1051// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1388
1052/// Locked instruction.
1053#[derive(Clone, Debug)]
1054#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1055pub struct MemLock {
1056 // PERF_MEM_LOCK_NA
1057 /// Not available.
1058 pub na: bool,
1059 // PERF_MEM_LOCK_LOCKED
1060 /// Locked transaction.
1061 pub locked: bool,
1062}
1063
1064// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1393
1065/// TLB access.
1066#[derive(Clone, Debug)]
1067#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1068pub struct MemTlb {
1069 // PERF_MEM_TLB_NA
1070 /// Not available.
1071 pub na: bool,
1072 // PERF_MEM_TLB_HIT
1073 /// Hit level.
1074 pub hit: bool,
1075 // PERF_MEM_TLB_MISS
1076 /// Miss level.
1077 pub miss: bool,
1078 // PERF_MEM_TLB_L1
1079 /// L1.
1080 pub l1: bool,
1081 // PERF_MEM_TLB_L2
1082 /// L2.
1083 pub l2: bool,
1084 // PERF_MEM_TLB_WK
1085 /// Hardware walker.
1086 pub walker: bool,
1087 // PERF_MEM_TLB_OS
1088 /// OS fault handler.
1089 pub fault: bool,
1090}
1091
1092// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1357
1093/// Memory hierarchy levels (V2).
1094///
1095/// Since `linux-4.14`: <https://github.com/torvalds/linux/commit/6ae5fa61d27dcb055f4198bcf6c8dbbf1bb33f52>
1096#[derive(Clone, Debug)]
1097#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1098pub enum MemLevel2 {
1099 // PERF_MEM_LVLNUM_L1
1100 /// L1.
1101 L1,
1102 // PERF_MEM_LVLNUM_L2
1103 /// L2.
1104 L2,
1105 // PERF_MEM_LVLNUM_L3
1106 /// L3.
1107 L3,
1108 // PERF_MEM_LVLNUM_L4
1109 /// L4.
1110 L4,
1111 // PERF_MEM_LVLNUM_L2_MHB
1112 /// L2 miss handling buffer.
1113 ///
1114 /// Since `linux-6.11`: <https://github.com/torvalds/linux/commit/608f6976c309793ceea37292c54b057dab091944>
1115 L2Mhb,
1116 // PERF_MEM_LVLNUM_MSC
1117 /// Memory-side cache.
1118 ///
1119 /// Since `linux-6.11`: <https://github.com/torvalds/linux/commit/608f6976c309793ceea37292c54b057dab091944>
1120 Msc,
1121 // PERF_MEM_LVLNUM_UNC
1122 /// Uncached.
1123 ///
1124 /// Since `linux-6.6`: <https://github.com/torvalds/linux/commit/526fffabc5fb63e80eb890c74b6570df2570c87f>
1125 Unc,
1126 // PERF_MEM_LVLNUM_CXL
1127 /// CXL.
1128 ///
1129 /// Since `linux-6.1`:
1130 /// <https://github.com/torvalds/linux/commit/cb6c18b5a41622c7a439508f7421f8766a91cb87>
1131 /// <https://github.com/torvalds/linux/commit/ee3e88dfec23153d0675b5d00522297b9adf657c>
1132 Cxl,
1133 // PERF_MEM_LVLNUM_IO
1134 /// I/O.
1135 ///
1136 /// Since `linux-6.1`: <https://github.com/torvalds/linux/commit/ee3e88dfec23153d0675b5d00522297b9adf657c>
1137 Io,
1138 // PERF_MEM_LVLNUM_ANY_CACHE
1139 /// Any cache.
1140 AnyCache,
1141 // PERF_MEM_LVLNUM_LFB
1142 /// LFB / L1 Miss Handling Buffer.
1143 Lfb,
1144 // PERF_MEM_LVLNUM_RAM
1145 /// RAM.
1146 Ram,
1147 // PERF_MEM_LVLNUM_PMEM
1148 /// PMEM.
1149 Pmem,
1150 // PERF_MEM_LVLNUM_NA
1151 /// Not available.
1152 Na,
1153 /// Unknown.
1154 ///
1155 /// This is for compatibility, not ABI.
1156 Unknown,
1157}
1158
1159// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1403
1160/// Access blocked.
1161///
1162/// Since `linux-5.12`: <https://github.com/torvalds/linux/commit/61b985e3e775a3a75fda04ce7ef1b1aefc4758bc>
1163#[derive(Clone, Debug)]
1164#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1165pub struct MemBlock {
1166 // PERF_MEM_BLK_NA
1167 /// Not available.
1168 pub na: bool,
1169
1170 // PERF_MEM_BLK_DATA
1171 /// Data could not be forwarded.
1172 pub data: bool,
1173
1174 // PERF_MEM_BLK_ADDR
1175 /// Address conflict.
1176 pub addr: bool,
1177}
1178
1179// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1409
1180// https://github.com/torvalds/linux/blob/v6.13/tools/perf/util/mem-events.c#L385
1181/// Hop levels.
1182///
1183/// Since `linux-5.16`: <https://github.com/torvalds/linux/commit/fec9cc6175d0ec1e13efe12be491d9bd4de62f80>
1184#[derive(Clone, Debug)]
1185#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1186pub enum MemHop {
1187 // PERF_MEM_HOPS_0
1188 /// Remote core, same node.
1189 Core,
1190 // PERF_MEM_HOPS_1
1191 /// Remote node, same socket.
1192 ///
1193 /// Since `linux-5.17`: <https://github.com/torvalds/linux/commit/cb1c4aba055f928ffae0c868e8dfe08eeab302e7>
1194 Node,
1195 // PERF_MEM_HOPS_2
1196 /// Remote socket, same board.
1197 ///
1198 /// Since `linux-5.17`: <https://github.com/torvalds/linux/commit/cb1c4aba055f928ffae0c868e8dfe08eeab302e7>
1199 Socket,
1200 // PERF_MEM_HOPS_3
1201 /// Remote board.
1202 ///
1203 /// Since `linux-5.17`: <https://github.com/torvalds/linux/commit/cb1c4aba055f928ffae0c868e8dfe08eeab302e7>
1204 Board,
1205 /// Unknown.
1206 ///
1207 /// This is for compatibility, not ABI.
1208 Unknown,
1209}
1210
1211/// Type of ABI.
1212#[derive(Clone, Debug)]
1213#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1214pub enum Abi {
1215 /// 32-bit ABI.
1216 _32,
1217 /// 64-bit ABI.
1218 _64,
1219}