Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 52 additions & 27 deletions src/amdgpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,38 +50,57 @@ void AMDGPU::get_instant_metrics(struct amdgpu_common_metrics *metrics) {
}

bool is_power=false, is_current=false, is_temp=false, is_other=false;
if (header.format_revision == 1) {
// Desktop GPUs
if (buf.size() < sizeof(gpu_metrics_v1_3)) {
SPDLOG_DEBUG(
"amdgpu metrics file '{}' too small for gpu_metrics_v1_3 "
"(have {}, need {})",
gpu_metrics_path, buf.size(), sizeof(gpu_metrics_v1_3));
return;
}

const auto *amdgpu_metrics = reinterpret_cast<const gpu_metrics_v1_3 *>(buf.data());
metrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity;
if (header.format_revision == 1) { // Desktop GPUs
if (header.content_revision == 0) { // gpu_metrics_v1_0
if (buf.size() != sizeof(gpu_metrics_v1_0)) {
SPDLOG_DEBUG(
"amdgpu metrics file '{}' does not fit gpu_metrics_v1_0 but reported as v1_0"
"(have {}, need {})",
gpu_metrics_path, buf.size(), sizeof(gpu_metrics_v1_0));
return;
}
const auto *amdgpu_metrics = reinterpret_cast<const gpu_metrics_v1_0 *>(buf.data());
metrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity;

metrics->average_gfx_power_w = amdgpu_metrics->average_socket_power;
metrics->average_gfx_power_w = amdgpu_metrics->average_socket_power / 1000.0f;

metrics->current_gfxclk_mhz = amdgpu_metrics->current_gfxclk;
metrics->current_uclk_mhz = amdgpu_metrics->current_uclk;
metrics->current_gfxclk_mhz = amdgpu_metrics->current_gfxclk;
metrics->current_uclk_mhz = amdgpu_metrics->current_uclk;

metrics->gpu_temp_c = amdgpu_metrics->temperature_edge;
metrics->fan_speed = amdgpu_metrics->current_fan_speed;
metrics->gpu_temp_c = amdgpu_metrics->temperature_edge;
metrics->fan_speed = amdgpu_metrics->current_fan_speed;
} else { // Assume it's gpu_metrics_v1_3
if (buf.size() < sizeof(gpu_metrics_v1_3)) {
SPDLOG_DEBUG(
"amdgpu metrics file '{}' too small for gpu_metrics_v1_3 "
"(have {}, need {})",
gpu_metrics_path, buf.size(), sizeof(gpu_metrics_v1_3));
return;
}
const auto *amdgpu_metrics = reinterpret_cast<const gpu_metrics_v1_3 *>(buf.data());
metrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity;

uint64_t indep = amdgpu_metrics->indep_throttle_status;
// RDNA 3 almost always shows the TEMP_HOTSPOT throtting flag,
// so clear that bit
indep &= ~(1ull << TEMP_HOTSPOT_BIT); // your existing quirk
metrics->average_gfx_power_w = amdgpu_metrics->average_socket_power;

is_power = ((indep >> 0) & 0xFF) != 0;
is_current = ((indep >> 16) & 0xFF) != 0;
is_temp = ((indep >> 32) & 0xFFFF) != 0;
is_other = ((indep >> 56) & 0xFF) != 0;
if (throttling)
throttling->indep_throttle_status = indep;
metrics->current_gfxclk_mhz = amdgpu_metrics->current_gfxclk;
metrics->current_uclk_mhz = amdgpu_metrics->current_uclk;

metrics->gpu_temp_c = amdgpu_metrics->temperature_edge;
metrics->fan_speed = amdgpu_metrics->current_fan_speed;

uint64_t indep = amdgpu_metrics->indep_throttle_status;
// RDNA 3 almost always shows the TEMP_HOTSPOT throtting flag,
// so clear that bit
indep &= ~(1ull << TEMP_HOTSPOT_BIT); // your existing quirk

is_power = ((indep >> 0) & 0xFF) != 0;
is_current = ((indep >> 16) & 0xFF) != 0;
is_temp = ((indep >> 32) & 0xFFFF) != 0;
is_other = ((indep >> 56) & 0xFF) != 0;
if (throttling)
throttling->indep_throttle_status = indep;
}
} else if (header.format_revision == 2) {
// APUS
size_t needed = 0;
Expand Down Expand Up @@ -322,7 +341,13 @@ void AMDGPU::get_samples_and_copy(struct amdgpu_common_metrics metrics_buffer[ME
metrics.fan_rpm = true;

metrics.load = amdgpu_common_metrics.gpu_load_percent;
metrics.powerUsage = amdgpu_common_metrics.average_gfx_power_w;

if (amdgpu_common_metrics.average_gfx_power_w > 0) {
// Some old GPUs like Radeon VII/Instinct MI50 report power 0 in gpu metrics
// Do not override it then, keep the value read from sysfs hwmon
metrics.powerUsage = amdgpu_common_metrics.average_gfx_power_w;
}

metrics.MemClock = amdgpu_common_metrics.current_uclk_mhz;

// Use hwmon instead, see gpu.cpp
Expand Down
59 changes: 59 additions & 0 deletions src/amdgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,65 @@ struct metrics_table_header {
uint8_t content_revision;
};

/*
* gpu_metrics_v1_0 is not naturally aligned, so not recommended,
* but some GPUs like vega20 are still using it.
*/
struct gpu_metrics_v1_0 {
struct metrics_table_header common_header;
uint32_t padding1;

/* Driver attached timestamp (in ns) */
uint64_t system_clock_counter;

/* Temperature */
uint16_t temperature_edge;
uint16_t temperature_hotspot;
uint16_t temperature_mem;
uint16_t temperature_vrgfx;
uint16_t temperature_vrsoc;
uint16_t temperature_vrmem;

/* Utilization */
uint16_t average_gfx_activity;
uint16_t average_umc_activity; // memory controller
uint16_t average_mm_activity; // UVD or VCN

/* Power/Energy */
uint16_t average_socket_power; // mW
uint32_t energy_accumulator;

/* Average clocks */
uint16_t average_gfxclk_frequency;
uint16_t average_socclk_frequency;
uint16_t average_uclk_frequency;
uint16_t average_vclk0_frequency;
uint16_t average_dclk0_frequency;
uint16_t average_vclk1_frequency;
uint16_t average_dclk1_frequency;

/* Current clocks */
uint16_t current_gfxclk;
uint16_t current_socclk;
uint16_t current_uclk;
uint16_t current_vclk0;
uint16_t current_dclk0;
uint16_t current_vclk1;
uint16_t current_dclk1;

/* Throttle status */
uint32_t throttle_status;

/* Fans */
uint16_t current_fan_speed; // RPM

/* Link width/speed */
uint8_t pcie_link_width;
uint8_t pcie_link_speed; // in 0.1 GT/s

uint32_t padding2;
};

struct gpu_metrics_v1_3 {
struct metrics_table_header common_header;

Expand Down