use libdrm_amdgpu_sys::AMDGPU::{
CHIP_CLASS,
DeviceHandle,
GRBM_OFFSET,
GRBM2_OFFSET,
};
use crate::stat;
#[derive(Clone, Debug)]
pub struct PCIndex {
pub name: String,
index: usize,
pub usage: u8, }
#[derive(Clone, Debug)]
pub struct PerfCounter {
pub pc_type: PCType,
bits: PCAcc,
pub pc_index: Vec<PCIndex>,
}
impl PerfCounter {
pub fn new_with_chip_class(pc_type: PCType, chip_class: CHIP_CLASS) -> Self {
let index = match pc_type {
PCType::GRBM => {
if CHIP_CLASS::GFX10 <= chip_class {
stat::GFX10_GRBM_INDEX
} else {
stat::GRBM_INDEX
}
},
PCType::GRBM2 => {
if CHIP_CLASS::GFX12 <= chip_class {
stat::GFX12_GRBM2_INDEX
} else if CHIP_CLASS::GFX10_3 <= chip_class {
stat::GFX10_3_GRBM2_INDEX
} else if CHIP_CLASS::GFX10 <= chip_class {
stat::GFX10_GRBM2_INDEX
} else if CHIP_CLASS::GFX9 <= chip_class {
stat::GFX9_GRBM2_INDEX
} else {
stat::GRBM2_INDEX
}
},
};
let pc_index = index
.iter()
.map(|(name, idx)| {
let index = *idx;
assert!(index < 32);
PCIndex {
name: name.to_string(),
index,
usage: 0,
}
})
.collect();
Self {
pc_type,
bits: PCAcc::default(),
pc_index,
}
}
pub fn read_reg(&mut self, amdgpu_dev: &DeviceHandle) {
if let Ok(out) = amdgpu_dev.read_mm_registers(self.pc_type.offset()) {
self.bits.acc(out);
}
}
pub fn clear_pc(&mut self) {
self.bits.clear();
}
pub fn update_pc_usage(&mut self) {
for PCIndex { name: _name, index, usage } in self.pc_index.iter_mut() {
*usage = self.bits.get(*index);
}
}
}
#[derive(Clone, Copy, Debug)]
#[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)]
pub enum PCType {
GRBM,
GRBM2,
}
use std::fmt;
impl fmt::Display for PCType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl PCType {
pub const fn offset(&self) -> u32 {
match self {
Self::GRBM => GRBM_OFFSET,
Self::GRBM2 => GRBM2_OFFSET,
}
}
pub fn check_reg_offset(&self, amdgpu_dev: &DeviceHandle) -> bool {
let offset = self.offset();
let reg_name = match self {
Self::GRBM => "GRBM_STATUS",
Self::GRBM2 => "GRBM2_STATUS2",
};
amdgpu_dev.read_mm_registers(offset).map_or_else(|err| {
println!("{reg_name} ({offset:#X}) register is not allowed. ({err})");
false
}, |_| true)
}
}
#[derive(Clone, Default, Debug)]
struct PCAcc([u8; 32]);
impl PCAcc {
pub fn clear(&mut self) {
*self = Self([0u8; 32])
}
pub fn acc(&mut self, reg: u32) {
*self += Self::from(reg)
}
fn get(&self, index: usize) -> u8 {
self.0[index]
}
}
impl From<u32> for PCAcc {
fn from(val: u32) -> Self {
let mut out = [0u8; 32];
for (i, o) in out.iter_mut().enumerate() {
*o = ((val >> i) & 0b1) as u8;
}
Self(out)
}
}
impl std::ops::AddAssign for PCAcc {
fn add_assign(&mut self, other: Self) {
for (dst, src) in self.0.iter_mut().zip(other.0.iter()) {
*dst += src;
}
}
}