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}