diff --git a/src/amdgpu.cpp b/src/amdgpu.cpp index 388fb5e418..75eb477d1b 100644 --- a/src/amdgpu.cpp +++ b/src/amdgpu.cpp @@ -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(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(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(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; @@ -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 diff --git a/src/amdgpu.h b/src/amdgpu.h index 9d3088523d..6e6385daf4 100644 --- a/src/amdgpu.h +++ b/src/amdgpu.h @@ -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;