use libdrm_amdgpu_sys::*;
fn info(pci_bus: &PCI::BUS_INFO) {
let Ok(device_path) = pci_bus.get_drm_render_path() else { return };
let (amdgpu_dev, _major, _minor) = {
use std::fs::File;
use std::os::fd::IntoRawFd;
let fd = File::open(device_path).unwrap();
AMDGPU::DeviceHandle::init(fd.into_raw_fd()).unwrap()
};
if let Ok(drm_ver) = amdgpu_dev.get_drm_version_struct() {
println!("{drm_ver:#?}");
}
if let Ok(ext_info) = amdgpu_dev.device_info() {
use AMDGPU::GPU_INFO;
println!("Marketing Name: [{}]", ext_info.find_device_name_or_default());
let gpu_type = if ext_info.is_apu() { "APU" } else { "dGPU" };
let asic = ext_info.get_asic_name();
println!(
"DeviceID.RevID: {:#0X}.{:#0X}",
ext_info.device_id(),
ext_info.pci_rev_id()
);
println!();
println!("Family:\t\t{}", ext_info.get_family_name());
println!("ASIC Name:\t{asic}");
println!("Chip class:\t{}", ext_info.get_chip_class());
println!("GPU Type:\t{gpu_type}");
if let Some(gfx_ver) = ext_info.get_gfx_target_version() {
println!("gfx_target_version: {gfx_ver}");
}
let max_good_cu_per_sa = ext_info.get_max_good_cu_per_sa();
let min_good_cu_per_sa = ext_info.get_min_good_cu_per_sa();
println!();
println!("Shader Engine (SE):\t\t{:3}", ext_info.max_se());
println!("Shader Array (SA/SH) per SE:\t{:3}", ext_info.max_sa_per_se());
if max_good_cu_per_sa != min_good_cu_per_sa {
println!("CU per SA[0]:\t\t\t{:3}", max_good_cu_per_sa);
println!("CU per SA[1]:\t\t\t{:3}", min_good_cu_per_sa);
} else {
println!("CU per SA:\t\t\t{:3}", max_good_cu_per_sa);
}
println!("Total Compute Unit:\t\t{:3}", ext_info.cu_active_number());
if let Some((min, max)) = amdgpu_dev.get_min_max_gpu_clock() {
println!("Engine Clock:\t\t{min}-{max} MHz");
}
println!("Peak FP32:\t\t{} GFLOPS", ext_info.peak_gflops());
println!();
println!("VRAM Type:\t\t{}", ext_info.get_vram_type());
println!("VRAM Bit Width:\t\t{}-bit", ext_info.vram_bit_width);
if let Some((min, max)) = amdgpu_dev.get_min_max_memory_clock() {
println!("Memory Clock:\t\t{min}-{max} MHz");
}
println!("Peak Memory BW:\t\t{} GB/s", ext_info.peak_memory_bw_gb());
println!();
println!("L1cache (per CU):\t{:4} KiB", ext_info.get_l1_cache_size() >> 10);
if 0 < ext_info.sqc_data_cache_size {
println!("SQC Data Cache:\t\t{:4} KiB", ext_info.sqc_data_cache_size);
}
if 0 < ext_info.sqc_inst_cache_size {
println!("SQC Inst Cache:\t\t{:4} KiB", ext_info.sqc_inst_cache_size);
}
let gl1_cache_size = ext_info.get_gl1_cache_size();
let l3_cache_size = ext_info.calc_l3_cache_size_mb();
if 0 < gl1_cache_size {
println!("GL1cache (per SA/SH):\t{:4} KiB", gl1_cache_size >> 10);
}
if 0 < ext_info.gl1c_cache_size {
println!("Total GL1cache:\t\t{gl1_cache_size:4} KiB");
}
println!(
"L2cache:\t\t{:4} KiB ({} Banks)",
ext_info.calc_l2_cache_size() >> 10,
ext_info.get_actual_num_tcc_blocks(),
);
if 0 < l3_cache_size {
println!("L3cache:\t\t{l3_cache_size:4} MiB");
}
}
if let Ok(info) = amdgpu_dev.memory_info() {
println!();
println!(
"VRAM Usage:\t\t\t{usage}/{total} MiB",
usage = info.vram.heap_usage >> 20,
total = info.vram.total_heap_size >> 20,
);
println!(
"CPU Accessible VRAM Usage:\t{usage}/{total} MiB",
usage = info.cpu_accessible_vram.heap_usage >> 20,
total = info.cpu_accessible_vram.total_heap_size >> 20,
);
println!(
"GTT Usage:\t\t\t{usage}/{total} MiB",
usage = info.gtt.heap_usage >> 20,
total = info.gtt.total_heap_size >> 20,
);
let re_bar = if info.check_resizable_bar() { "Enabled" } else { "Disabled" };
println!("ResizableBAR:\t\t\t{re_bar}");
if let Ok(moved) = amdgpu_dev.num_bytes_moved() {
println!("Number of bytes moved for TTM migration: {moved}");
}
if let Ok(fault_count) = amdgpu_dev.num_vram_cpu_page_faults() {
println!("Number of VRAM page faults on CPU access: {fault_count}");
}
if let Ok(e) = amdgpu_dev.num_evictions() {
println!("Number of TTM buffer evictions: {e}");
}
if let Ok(lost) = amdgpu_dev.vram_lost_counter() {
println!("VRAM lost counter: {lost}");
}
if let Ok(ras) = amdgpu_dev.ras_enabled_features() {
use AMDGPU::RasBlock;
println!("ECC Memory: {}", if ras.is_supported(RasBlock::UMC) {
"supported"
} else {
"not supported"
});
}
}
{
use AMDGPU::HW_IP::*;
let ip_list = [
HW_IP_TYPE::GFX,
HW_IP_TYPE::COMPUTE,
HW_IP_TYPE::DMA,
HW_IP_TYPE::UVD,
HW_IP_TYPE::VCE,
HW_IP_TYPE::UVD_ENC,
HW_IP_TYPE::VCN_DEC,
HW_IP_TYPE::VCN_ENC,
HW_IP_TYPE::VCN_JPEG,
HW_IP_TYPE::VPE,
];
println!("\nHardware IP info:");
for ip_type in &ip_list {
if let (Ok(ip_info), Ok(ip_count)) = (
amdgpu_dev.query_hw_ip_info(*ip_type, 0),
amdgpu_dev.query_hw_ip_count(*ip_type),
) {
let (major, minor) = ip_info.version();
let queues = ip_info.num_queues();
if queues == 0 {
continue;
}
println!(
"{ip_type:8} count: {ip_count}, ver: {major:2}.{minor}, queues: {queues}",
ip_type = ip_type.to_string(),
);
}
}
}
{
use AMDGPU::FW_VERSION::*;
let fw_list = [
FW_TYPE::VCE,
FW_TYPE::UVD,
FW_TYPE::GMC,
FW_TYPE::GFX_ME,
FW_TYPE::GFX_PFP,
FW_TYPE::GFX_CE,
FW_TYPE::GFX_RLC,
FW_TYPE::GFX_MEC,
FW_TYPE::SMC,
FW_TYPE::SDMA,
FW_TYPE::SOS,
FW_TYPE::ASD,
FW_TYPE::VCN,
FW_TYPE::GFX_RLC_RESTORE_LIST_CNTL,
FW_TYPE::GFX_RLC_RESTORE_LIST_GPM_MEM,
FW_TYPE::GFX_RLC_RESTORE_LIST_SRM_MEM,
FW_TYPE::DMCU,
FW_TYPE::TA,
FW_TYPE::DMCUB,
FW_TYPE::TOC,
FW_TYPE::VPE,
];
println!("\nFirmware info:");
for fw_type in &fw_list {
let fw_info = match amdgpu_dev.query_firmware_version(*fw_type, 0, 0) {
Ok(v) => v,
Err(_) => continue,
};
let (ver, ftr) = (fw_info.version, fw_info.feature);
if ver == 0 {
continue;
}
println!(
"{fw_type:<8} ver: {ver:>#10X}, feature: {ftr:>3}",
fw_type = fw_type.to_string(),
);
}
}
{
use AMDGPU::VIDEO_CAPS::CAP_TYPE;
println!("\nVideo caps:");
if let Ok(codec_info) = amdgpu_dev.get_video_caps_info(CAP_TYPE::DECODE) {
println!("{codec_info:#?}");
}
if let Ok(codec_info) = amdgpu_dev.get_video_caps_info(CAP_TYPE::ENCODE) {
println!("{codec_info:#?}");
}
}
if let Ok(bus_info) = amdgpu_dev.get_pci_bus_info() {
println!("\nPCI (domain:bus:dev.func): {bus_info}");
if let Ok(render) = bus_info.get_drm_render_path() {
println!("Render: {render:?}");
}
if let Ok(card) = bus_info.get_drm_card_path() {
println!("Card: {card:?}");
}
}
if let Some([min, max]) = amdgpu_dev.get_min_max_link_info_from_dpm() {
println!(
"PCIe Link Speed (DPM) : Gen{}x{} - Gen{}x{}",
min.gen,
min.width,
max.gen,
max.width,
);
if let Some(max_gpu_link) = amdgpu_dev.get_max_gpu_link() {
println!(
"PCIe Link Speed (GPU, Max) : Gen{}x{}",
max_gpu_link.gen,
max_gpu_link.width,
);
}
if let Some(max_system_link) = amdgpu_dev.get_max_system_link() {
println!(
"PCIe Link Speed (System, Max): Gen{}x{}",
max_system_link.gen,
max_system_link.width,
);
}
} else {
println!("PCIe Link Speed (DPM) : None");
}
if let Ok(vbios) = amdgpu_dev.get_vbios_info() {
println!("\nVBIOS info:");
println!("name: [{}]", vbios.name);
println!("pn: [{}]", vbios.pn);
println!("ver: [{}]", vbios.ver);
println!("date: [{}]", vbios.date);
}
{
use AMDGPU::SENSOR_INFO::*;
let sensors = [
SENSOR_TYPE::GFX_SCLK,
SENSOR_TYPE::GFX_MCLK,
SENSOR_TYPE::GPU_TEMP,
SENSOR_TYPE::GPU_LOAD,
SENSOR_TYPE::GPU_AVG_POWER,
SENSOR_TYPE::VDDNB,
SENSOR_TYPE::VDDGFX,
SENSOR_TYPE::STABLE_PSTATE_GFX_SCLK,
SENSOR_TYPE::STABLE_PSTATE_GFX_MCLK,
SENSOR_TYPE::PEAK_PSTATE_GFX_SCLK,
SENSOR_TYPE::PEAK_PSTATE_GFX_MCLK,
];
println!("\nSensors:");
for s in &sensors {
if let Ok(val) = amdgpu_dev.sensor_info(*s) {
println!("{s:?}: {val}");
} else {
println!("{s:?}: not supported");
}
}
}
if let Ok(sysfs) = amdgpu_dev.get_sysfs_path() {
println!("sysfs: {sysfs:?}");
use AMDGPU::{DpmForcedLevel, PowerProfile};
let profiles: Vec<String> = PowerProfile::get_all_supported_profiles_from_sysfs(&sysfs)
.iter()
.map(|p| p.to_string())
.collect();
println!("Supported Power Profiles: {profiles:?}");
if let Some(profiles) = PowerProfile::get_current_profile_from_sysfs(&sysfs) {
println!("Current Power Profiles: {profiles}");
}
if let Ok(level) = DpmForcedLevel::get_from_sysfs(&sysfs) {
println!("power_dpm_force_performance_lvel: {level:?}");
}
use AMDGPU::{RasErrorCount, RasBlock};
if let Ok(cnt) = RasErrorCount::get_from_sysfs_with_ras_block(&sysfs, RasBlock::UMC) {
println!(
"Memory Error Count: uncorrected {}, corrected {}",
cnt.uncorrected,
cnt.corrected,
);
}
}
if let Some(hwmon) = amdgpu_dev.get_hwmon_path() {
println!("hwmon: {hwmon:?}");
use AMDGPU::{HwmonTemp, HwmonTempType, PowerCap};
if let Some(power_cap) = PowerCap::from_hwmon_path(&hwmon) {
let PowerCap { type_, current, default, min, max } = power_cap;
println!("PowerCap ({type_}): {current} W (Current), {default} W (Default), {min}-{max} W (Range)");
}
if let Some(edge_temp) = HwmonTemp::from_hwmon_path(&hwmon, HwmonTempType::Edge) {
println!("{edge_temp:?}");
}
if let Some(junction_temp) = HwmonTemp::from_hwmon_path(&hwmon, HwmonTempType::Junction) {
println!("{junction_temp:?}");
}
if let Some(mem_temp) = HwmonTemp::from_hwmon_path(&hwmon, HwmonTempType::Memory) {
println!("{mem_temp:?}");
}
}
println!();
}
fn main() {
let pci_devs = AMDGPU::get_all_amdgpu_pci_bus();
if pci_devs.is_empty() {
panic!("No AMDGPU devices.");
}
for pci_bus in &pci_devs {
info(pci_bus);
}
}