use std::slice;
use super::{RecordId, Task};
use crate::count::Stat;
use crate::ffi::{bindings as b, deref_offset};
#[derive(Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Sample {
pub record_id: RecordId,
pub stat: Option<Stat>,
pub period: Option<u64>,
pub cgroup: Option<u64>,
pub call_chain: Option<Vec<u64>>,
pub user_stack: Option<Vec<u8>>,
pub data_addr: Option<u64>,
pub data_phys_addr: Option<u64>,
pub data_page_size: Option<u64>,
pub data_source: Option<DataSource>,
pub code_addr: Option<(u64, bool)>,
pub code_page_size: Option<u64>,
pub user_regs: Option<(Vec<u64>, Abi)>,
pub intr_regs: Option<(Vec<u64>, Abi)>,
pub raw: Option<Vec<u8>>,
pub lbr: Option<Lbr>,
pub aux: Option<Vec<u8>>,
pub txn: Option<Txn>,
pub weight: Option<Weight>,
}
impl Sample {
pub(crate) unsafe fn from_ptr(
mut ptr: *const u8,
misc: u16,
read_format: u64,
sample_type: u64,
user_regs: usize,
intr_regs: usize,
branch_sample_type: u64,
) -> Self {
macro_rules! when {
($($feature: literal,)? $flag:ident, $ty:ty) => {{
$(#[cfg(feature = $feature)])?
let val = (sample_type & (b::$flag as u64) > 0).then(|| deref_offset::<$ty>(&mut ptr));
$(
#[cfg(not(feature = $feature))]
let val = None;
)?
val
}};
($flag:ident) => {
sample_type & (b::$flag as u64) > 0
};
($($feature: literal,)? $flag:ident, $then:expr) => {{
$(#[cfg(feature = $feature)])?
let val = (sample_type & (b::$flag as u64) > 0).then(|| $then);
$(
#[cfg(not(feature = $feature))]
let val = None;
)?
val
}};
}
let code_addr = when!(PERF_SAMPLE_IP, {
(
deref_offset(&mut ptr),
misc as u32 & b::PERF_RECORD_MISC_EXACT_IP > 0,
)
});
let task = when!(
PERF_SAMPLE_TID,
Task {
pid: deref_offset(&mut ptr),
tid: deref_offset(&mut ptr),
}
);
let time = when!(PERF_SAMPLE_TIME, u64);
let data_addr = when!(PERF_SAMPLE_ADDR, u64);
let id = when!(PERF_SAMPLE_ID, u64);
let stream_id = when!(PERF_SAMPLE_STREAM_ID, u64);
let cpu = when!(PERF_SAMPLE_CPU, {
let val = deref_offset(&mut ptr);
ptr = ptr.add(size_of::<u32>());
val
});
let period = when!(PERF_SAMPLE_PERIOD, u64);
let stat = when!(PERF_SAMPLE_READ, {
Stat::from_ptr_offset(&mut ptr, read_format)
});
let call_chain = when!(PERF_SAMPLE_CALLCHAIN, {
let len = deref_offset::<u64>(&mut ptr) as usize;
let ips = slice::from_raw_parts(ptr as *const u64, len);
ptr = ptr.add(len * size_of::<u64>());
ips.to_vec()
});
let raw = when!(PERF_SAMPLE_RAW, {
let len = deref_offset::<u32>(&mut ptr) as usize;
let bytes = slice::from_raw_parts(ptr, len);
ptr = ptr.add(len);
ptr = ptr.add(ptr.align_offset(align_of::<u64>()));
bytes.to_vec()
});
let lbr = when!(PERF_SAMPLE_BRANCH_STACK, {
parse_lbr(&mut ptr, branch_sample_type)
})
.flatten();
let user_regs = when!(PERF_SAMPLE_REGS_USER, { parse_regs(&mut ptr, user_regs) }).flatten();
let user_stack = when!(PERF_SAMPLE_STACK_USER, {
let len = deref_offset::<u64>(&mut ptr) as usize;
let bytes = slice::from_raw_parts(ptr, len);
ptr = ptr.add(len);
let dyn_len = if len > 0 {
deref_offset::<u64>(&mut ptr) as usize
} else {
0
};
bytes[..dyn_len].to_vec()
});
#[cfg(feature = "linux-5.12")]
let weight = if when!(PERF_SAMPLE_WEIGHT) {
let full = Weight::Full(deref_offset(&mut ptr));
Some(full)
} else if when!(PERF_SAMPLE_WEIGHT_STRUCT) {
#[cfg(target_endian = "little")]
let vars = Weight::Vars {
var1: deref_offset(&mut ptr),
var2: deref_offset(&mut ptr),
var3: deref_offset(&mut ptr),
};
#[cfg(target_endian = "big")]
let vars = Weight::Vars {
var3: deref_offset(&mut ptr),
var2: deref_offset(&mut ptr),
var1: deref_offset(&mut ptr),
};
Some(vars)
} else {
None
};
#[cfg(not(feature = "linux-5.12"))]
let weight = when!(PERF_SAMPLE_WEIGHT, { Weight::Full(deref_offset(&mut ptr)) });
let data_source = when!(PERF_SAMPLE_DATA_SRC, { parse_data_source(&mut ptr) });
let txn = when!(PERF_SAMPLE_TRANSACTION, { parse_txn(&mut ptr) });
let intr_regs = when!(PERF_SAMPLE_REGS_INTR, { parse_regs(&mut ptr, intr_regs) }).flatten();
let data_phys_addr = when!("linux-4.14", PERF_SAMPLE_PHYS_ADDR, u64);
let cgroup = when!("linux-5.7", PERF_SAMPLE_CGROUP, u64);
let data_page_size = when!("linux-5.11", PERF_SAMPLE_DATA_PAGE_SIZE, u64);
let code_page_size = when!("linux-5.11", PERF_SAMPLE_CODE_PAGE_SIZE, u64);
let aux = when!("linux-5.5", PERF_SAMPLE_AUX, {
let len = deref_offset::<u64>(&mut ptr) as usize;
let bytes = slice::from_raw_parts(ptr, len as _);
bytes.to_vec()
});
Self {
record_id: RecordId {
id,
stream_id,
cpu,
task,
time,
},
stat,
period,
cgroup,
call_chain,
user_stack,
data_addr,
data_phys_addr,
data_page_size,
data_source,
code_addr,
code_page_size,
user_regs,
intr_regs,
raw,
lbr,
aux,
txn,
weight,
}
}
}
super::from!(Sample);
super::debug!(Sample {
{record_id},
{stat?},
{period?},
{cgroup?},
{call_chain?},
{user_stack?},
{data_source?},
{data_addr?},
{data_phys_addr?},
{data_page_size?},
{code_addr?},
{code_page_size?},
{user_regs?},
{intr_regs?},
{raw?},
{lbr?},
{aux?},
{txn?},
{weight?},
});
unsafe fn parse_regs(ptr: &mut *const u8, len: usize) -> Option<(Vec<u64>, Abi)> {
let abi = deref_offset::<u64>(ptr) as u32;
if abi == b::PERF_SAMPLE_REGS_ABI_NONE {
return None;
}
let regs = slice::from_raw_parts(*ptr as *const u64, len);
*ptr = ptr.add(len * size_of::<u64>());
let abi = match abi {
b::PERF_SAMPLE_REGS_ABI_32 => Abi::_32,
b::PERF_SAMPLE_REGS_ABI_64 => Abi::_64,
_ => return None,
};
Some((regs.to_vec(), abi))
}
unsafe fn parse_lbr(ptr: &mut *const u8, branch_sample_type: u64) -> Option<Lbr> {
let len = deref_offset::<u64>(ptr) as usize;
if len == 0 {
return None;
}
#[cfg(feature = "linux-5.7")]
let hw_index = (branch_sample_type & b::PERF_SAMPLE_BRANCH_HW_INDEX as u64 > 0)
.then(|| deref_offset::<u64>(ptr));
#[cfg(not(feature = "linux-5.7"))]
let _ = branch_sample_type;
#[cfg(not(feature = "linux-5.7"))]
let hw_index = None;
#[repr(C)]
struct Layout {
from: u64,
to: u64,
bits: u64,
}
fn to_entry(layout: &Layout, counter: Option<u64>) -> Entry {
let bits = layout.bits;
macro_rules! when {
($flag:expr) => {
bits & $flag > 0
};
}
Entry {
counter,
from: layout.from,
to: layout.to,
mis: when!(0b1), pred: when!(0b10), in_tx: when!(0b100), abort: when!(0b1000), cycles: (bits >> 4) as _, #[cfg(feature = "linux-4.14")]
branch_type: match ((bits >> 20) & 0b1111) as _ {
b::PERF_BR_UNKNOWN => BranchType::Unknown,
b::PERF_BR_COND => BranchType::Cond,
b::PERF_BR_UNCOND => BranchType::Uncond,
b::PERF_BR_IND => BranchType::Ind,
b::PERF_BR_CALL => BranchType::Call,
b::PERF_BR_IND_CALL => BranchType::IndCall,
b::PERF_BR_RET => BranchType::Ret,
b::PERF_BR_SYSCALL => BranchType::Syscall,
b::PERF_BR_SYSRET => BranchType::Sysret,
b::PERF_BR_COND_CALL => BranchType::CondCall,
b::PERF_BR_COND_RET => BranchType::CondRet,
#[cfg(feature = "linux-5.18")]
b::PERF_BR_ERET => BranchType::Eret,
#[cfg(feature = "linux-5.18")]
b::PERF_BR_IRQ => BranchType::Irq,
#[cfg(feature = "linux-6.1")]
b::PERF_BR_SERROR => BranchType::SysErr,
#[cfg(feature = "linux-6.1")]
b::PERF_BR_NO_TX => BranchType::NoTx,
#[cfg(feature = "linux-6.1")]
b::PERF_BR_EXTEND_ABI => match ((bits >> 26) & 0b1111) as _ {
b::PERF_BR_NEW_FAULT_DATA => BranchType::DataFault,
b::PERF_BR_NEW_FAULT_ALGN => BranchType::AlignFault,
b::PERF_BR_NEW_FAULT_INST => BranchType::InstrFault,
b::PERF_BR_NEW_ARCH_1 => BranchType::Arch1,
b::PERF_BR_NEW_ARCH_2 => BranchType::Arch2,
b::PERF_BR_NEW_ARCH_3 => BranchType::Arch3,
b::PERF_BR_NEW_ARCH_4 => BranchType::Arch4,
b::PERF_BR_NEW_ARCH_5 => BranchType::Arch5,
_ => BranchType::Unknown,
},
_ => BranchType::Unknown,
},
#[cfg(not(feature = "linux-4.14"))]
branch_type: BranchType::Unknown,
#[cfg(feature = "linux-6.1")]
branch_spec: match ((bits >> 24) & 0b11) as _ {
b::PERF_BR_SPEC_NA => BranchSpec::Na,
b::PERF_BR_SPEC_WRONG_PATH => BranchSpec::Wrong,
b::PERF_BR_NON_SPEC_CORRECT_PATH => BranchSpec::NoSpecCorrect,
b::PERF_BR_SPEC_CORRECT_PATH => BranchSpec::Correct,
#[cfg(debug_assertions)]
_ => unreachable!(),
#[cfg(not(debug_assertions))]
_ => unsafe { std::hint::unreachable_unchecked() },
},
#[cfg(not(feature = "linux-6.1"))]
branch_spec: BranchSpec::Na,
#[cfg(feature = "linux-6.1")]
branch_priv: match ((bits >> 30) & 0b111) as _ {
b::PERF_BR_PRIV_UNKNOWN => BranchPriv::Unknown,
b::PERF_BR_PRIV_USER => BranchPriv::User,
b::PERF_BR_PRIV_KERNEL => BranchPriv::Kernel,
b::PERF_BR_PRIV_HV => BranchPriv::Hv,
_ => BranchPriv::Unknown,
},
#[cfg(not(feature = "linux-6.1"))]
branch_priv: BranchPriv::Unknown,
}
}
let layouts = slice::from_raw_parts(*ptr as *const Layout, len).iter();
*ptr = ptr.add(len * size_of::<Layout>());
#[cfg(feature = "linux-6.8")]
let has_counters = branch_sample_type & b::PERF_SAMPLE_BRANCH_COUNTERS as u64 > 0;
#[cfg(not(feature = "linux-6.8"))]
let has_counters = false;
let entries = if has_counters {
layouts
.map(|it| to_entry(it, Some(deref_offset(ptr))))
.collect()
} else {
layouts.map(|it| to_entry(it, None)).collect()
};
Some(Lbr { hw_index, entries })
}
unsafe fn parse_txn(ptr: &mut *const u8) -> Txn {
let bits: u64 = deref_offset(ptr);
let code = ((bits & b::PERF_TXN_ABORT_MASK) >> b::PERF_TXN_ABORT_SHIFT) as u32;
macro_rules! when {
($flag:ident) => {
bits & b::$flag > 0
};
}
Txn {
elision: when!(PERF_TXN_ELISION),
tx: when!(PERF_TXN_TRANSACTION),
is_sync: when!(PERF_TXN_SYNC),
is_async: when!(PERF_TXN_ASYNC),
retry: when!(PERF_TXN_RETRY),
conflict: when!(PERF_TXN_CONFLICT),
capacity_read: when!(PERF_TXN_CAPACITY_READ),
capacity_write: when!(PERF_TXN_CAPACITY_WRITE),
code,
}
}
unsafe fn parse_data_source(ptr: &mut *const u8) -> DataSource {
let bits: u64 = deref_offset(ptr);
macro_rules! when {
($shifted:expr, $flag:ident) => {
$shifted & (b::$flag as u64) > 0
};
}
let op = MemOp {
na: when!(bits, PERF_MEM_OP_NA),
load: when!(bits, PERF_MEM_OP_LOAD),
store: when!(bits, PERF_MEM_OP_STORE),
prefetch: when!(bits, PERF_MEM_OP_PFETCH),
exec: when!(bits, PERF_MEM_OP_EXEC),
};
let shifted = bits >> b::PERF_MEM_LVL_SHIFT;
let level = MemLevel {
na: when!(shifted, PERF_MEM_LVL_NA),
hit: when!(shifted, PERF_MEM_LVL_HIT),
miss: when!(shifted, PERF_MEM_LVL_MISS),
l1: when!(shifted, PERF_MEM_LVL_L1),
lfb: when!(shifted, PERF_MEM_LVL_LFB),
l2: when!(shifted, PERF_MEM_LVL_L2),
l3: when!(shifted, PERF_MEM_LVL_L3),
loc_ram: when!(shifted, PERF_MEM_LVL_LOC_RAM),
rem_ram1: when!(shifted, PERF_MEM_LVL_REM_RAM1),
rem_ram2: when!(shifted, PERF_MEM_LVL_REM_RAM2),
rem_cce1: when!(shifted, PERF_MEM_LVL_REM_CCE1),
rem_cce2: when!(shifted, PERF_MEM_LVL_REM_CCE2),
io: when!(shifted, PERF_MEM_LVL_IO),
unc: when!(shifted, PERF_MEM_LVL_UNC),
};
let shifted1 = bits >> b::PERF_MEM_SNOOP_SHIFT;
#[cfg(feature = "linux-4.14")]
let shifted2 = bits >> b::PERF_MEM_SNOOPX_SHIFT;
let snoop = MemSnoop {
na: when!(shifted1, PERF_MEM_SNOOP_NA),
none: when!(shifted1, PERF_MEM_SNOOP_NONE),
hit: when!(shifted1, PERF_MEM_SNOOP_HIT),
miss: when!(shifted1, PERF_MEM_SNOOP_MISS),
hit_m: when!(shifted1, PERF_MEM_SNOOP_HITM),
#[cfg(feature = "linux-4.14")]
fwd: when!(shifted2, PERF_MEM_SNOOPX_FWD),
#[cfg(not(feature = "linux-4.14"))]
fwd: false,
#[cfg(feature = "linux-6.1")]
peer: when!(shifted2, PERF_MEM_SNOOPX_PEER),
#[cfg(not(feature = "linux-6.1"))]
peer: false,
};
let shifted = bits >> b::PERF_MEM_LOCK_SHIFT;
let lock = MemLock {
na: when!(shifted, PERF_MEM_LOCK_NA),
locked: when!(shifted, PERF_MEM_LOCK_LOCKED),
};
let shifted = bits >> b::PERF_MEM_TLB_SHIFT;
let tlb = MemTlb {
na: when!(shifted, PERF_MEM_TLB_NA),
hit: when!(shifted, PERF_MEM_TLB_HIT),
miss: when!(shifted, PERF_MEM_TLB_MISS),
l1: when!(shifted, PERF_MEM_TLB_L1),
l2: when!(shifted, PERF_MEM_TLB_L2),
walker: when!(shifted, PERF_MEM_TLB_WK),
fault: when!(shifted, PERF_MEM_TLB_OS),
};
#[cfg(feature = "linux-4.14")]
let shifted = bits >> b::PERF_MEM_LVLNUM_SHIFT;
#[cfg(feature = "linux-4.14")]
let level2 = match (shifted & 0b1111) as u32 {
b::PERF_MEM_LVLNUM_L1 => MemLevel2::L1,
b::PERF_MEM_LVLNUM_L2 => MemLevel2::L2,
b::PERF_MEM_LVLNUM_L3 => MemLevel2::L3,
b::PERF_MEM_LVLNUM_L4 => MemLevel2::L4,
#[cfg(feature = "linux-6.11")]
b::PERF_MEM_LVLNUM_L2_MHB => MemLevel2::L2Mhb,
#[cfg(feature = "linux-6.11")]
b::PERF_MEM_LVLNUM_MSC => MemLevel2::Msc,
#[cfg(feature = "linux-6.6")]
b::PERF_MEM_LVLNUM_UNC => MemLevel2::Unc,
#[cfg(feature = "linux-6.1")]
b::PERF_MEM_LVLNUM_CXL => MemLevel2::Cxl,
#[cfg(feature = "linux-6.1")]
b::PERF_MEM_LVLNUM_IO => MemLevel2::Io,
b::PERF_MEM_LVLNUM_ANY_CACHE => MemLevel2::AnyCache,
b::PERF_MEM_LVLNUM_LFB => MemLevel2::Lfb,
b::PERF_MEM_LVLNUM_RAM => MemLevel2::Ram,
b::PERF_MEM_LVLNUM_PMEM => MemLevel2::Pmem,
b::PERF_MEM_LVLNUM_NA => MemLevel2::Na,
_ => MemLevel2::Unknown,
};
#[cfg(not(feature = "linux-4.14"))]
let level2 = MemLevel2::Unknown;
#[cfg(feature = "linux-4.14")]
let remote = (bits >> b::PERF_MEM_REMOTE_SHIFT) & 1 > 0;
#[cfg(not(feature = "linux-4.14"))]
let remote = false;
#[cfg(feature = "linux-5.12")]
let shifted = bits >> b::PERF_MEM_BLK_SHIFT;
#[cfg(feature = "linux-5.12")]
let block = MemBlock {
na: when!(shifted, PERF_MEM_BLK_NA),
data: when!(shifted, PERF_MEM_BLK_DATA),
addr: when!(shifted, PERF_MEM_BLK_ADDR),
};
#[cfg(not(feature = "linux-5.12"))]
let block = MemBlock {
na: false,
data: false,
addr: false,
};
#[cfg(feature = "linux-5.16")]
let shifted = bits >> b::PERF_MEM_HOPS_SHIFT;
#[cfg(feature = "linux-5.16")]
let hops = match (shifted & 0b111) as u32 {
b::PERF_MEM_HOPS_0 => MemHop::Core,
#[cfg(feature = "linux-5.17")]
b::PERF_MEM_HOPS_1 => MemHop::Node,
#[cfg(feature = "linux-5.17")]
b::PERF_MEM_HOPS_2 => MemHop::Socket,
#[cfg(feature = "linux-5.17")]
b::PERF_MEM_HOPS_3 => MemHop::Board,
_ => MemHop::Unknown,
};
#[cfg(not(feature = "linux-5.16"))]
let hops = MemHop::Unknown;
DataSource {
op,
level,
snoop,
lock,
tlb,
level2,
remote,
block,
hops,
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Lbr {
pub hw_index: Option<u64>,
pub entries: Vec<Entry>,
}
super::debug!(Lbr {
{hw_index?},
{entries},
});
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Entry {
pub from: u64,
pub to: u64,
pub mis: bool,
pub pred: bool,
pub in_tx: bool,
pub abort: bool,
pub cycles: u16,
pub branch_type: BranchType,
pub branch_spec: BranchSpec,
pub branch_priv: BranchPriv,
pub counter: Option<u64>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BranchType {
Unknown,
Cond,
Uncond,
Ind,
Call,
IndCall,
Ret,
Syscall,
Sysret,
CondCall,
CondRet,
Eret,
Irq,
SysErr,
NoTx,
DataFault,
AlignFault,
InstrFault,
Arch1,
Arch2,
Arch3,
Arch4,
Arch5,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BranchSpec {
Na,
Wrong,
Correct,
NoSpecCorrect,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BranchPriv {
Unknown,
User,
Kernel,
Hv,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Weight {
Full(u64),
Vars { var1: u32, var2: u16, var3: u16 },
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Txn {
pub elision: bool,
pub tx: bool,
pub is_sync: bool,
pub is_async: bool,
pub retry: bool,
pub conflict: bool,
pub capacity_read: bool,
pub capacity_write: bool,
pub code: u32,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DataSource {
pub op: MemOp,
pub level: MemLevel,
pub snoop: MemSnoop,
pub lock: MemLock,
pub tlb: MemTlb,
pub level2: MemLevel2,
pub remote: bool,
pub block: MemBlock,
pub hops: MemHop,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemOp {
pub na: bool,
pub load: bool,
pub store: bool,
pub prefetch: bool,
pub exec: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemLevel {
pub na: bool,
pub hit: bool,
pub miss: bool,
pub l1: bool,
pub lfb: bool,
pub l2: bool,
pub l3: bool,
pub loc_ram: bool,
pub rem_ram1: bool,
pub rem_ram2: bool,
pub rem_cce1: bool,
pub rem_cce2: bool,
pub io: bool,
pub unc: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemSnoop {
pub na: bool,
pub none: bool,
pub hit: bool,
pub miss: bool,
pub hit_m: bool,
pub fwd: bool,
pub peer: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemLock {
pub na: bool,
pub locked: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemTlb {
pub na: bool,
pub hit: bool,
pub miss: bool,
pub l1: bool,
pub l2: bool,
pub walker: bool,
pub fault: bool,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MemLevel2 {
L1,
L2,
L3,
L4,
L2Mhb,
Msc,
Unc,
Cxl,
Io,
AnyCache,
Lfb,
Ram,
Pmem,
Na,
Unknown,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MemBlock {
pub na: bool,
pub data: bool,
pub addr: bool,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MemHop {
Core,
Node,
Socket,
Board,
Unknown,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Abi {
_32,
_64,
}