#include struct GpuMetrics_v1_1_t { uint16_t temperature_edge; uint16_t temperature_hotspot; uint16_t temperature_mem; uint16_t temperature_vrgfx; uint16_t temperature_vrsoc; uint16_t temperature_vrmem; uint16_t average_gfx_activity; uint16_t average_umc_activity; uint16_t average_mm_activity; uint16_t average_socket_power; uint64_t energy_accumulator; uint64_t system_clock_counter; 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; 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; uint32_t throttle_status; uint16_t current_fan_speed; uint16_t pcie_link_width; uint16_t pcie_link_speed; uint16_t padding; uint32_t gfx_activity_acc; uint32_t mem_activity_acc; uint16_t temperature_hbm; }; struct GpuMetrics_v1_3_t { uint16_t temperature_edge; uint16_t temperature_hotspot; uint16_t temperature_mem; uint16_t temperature_vrgfx; uint16_t temperature_vrsoc; uint16_t temperature_vrmem; uint16_t average_gfx_activity; uint16_t average_umc_activity; uint16_t average_mm_activity; uint16_t average_socket_power; uint64_t energy_accumulator; uint64_t system_clock_counter; 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; 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; uint32_t throttle_status; uint16_t current_fan_speed; uint16_t pcie_link_width; uint16_t pcie_link_speed; uint16_t padding; uint32_t gfx_activity_acc; uint32_t mem_activity_acc; uint16_t temperature_hbm; uint64_t firmware_timestamp; uint16_t voltage_soc; uint16_t voltage_gfx; uint16_t voltage_mem; uint8_t padding1; }; std::string detectGpuHwmon(std::string pci) { std::string path = getFirstDir("/sys/bus/pci/devices/" + pci + "/hwmon"); std::println("[GpuHwmon] Detected path \"{}\"", path); return path; } GpuMetricsHeader_t getGpuMetricsHeader(std::string path) { GpuMetricsHeader_t header; std::ifstream f(path, std::ios::binary); if (f.good()) { f.read(reinterpret_cast(&header), sizeof(header)); std::println("[GpuMetrics] header at path {} read, GpuMetrics_v{}_{}, size {}", path, header.format_revision, header.content_revision, header.structure_size); f.close(); } else { std::println("[GpuMetrics] error reading header at path {} (wrong card # ?)", path); // should be err } return header; } /* will return empty metric if fails */ auto getGpuMetrics(GpuMetricsHeader_t h, std::string path) { GpuMetrics_v1_3_t metrics; uint8_t rev = h.format_revision * 10 + h.content_revision; switch (rev) { case 13: { std::ifstream f(path, std::ios::binary); if (f.good()) { f.ignore(sizeof(h)); // skip header f.read(reinterpret_cast(&metrics), sizeof(metrics)); f.close(); } } break; } return metrics; } // clean abstraction of gpu_metrics + extra metrics from fs, works with rx7800xt gpu_t getGpu(GpuMetricsHeader_t header, std::string hw) { gpu_t gpu; uint8_t hwmon = 3; // these are always read from fs gpu.fan_speed = std::stol(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/fan1_input")); gpu.vcore = std::stol(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/in0_input")) / 1000.0; gpu.power_cap = std::stol(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/power1_cap", 3)); gpu.power_max = std::stol(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/power1_cap_max", 3)); // gpu.fan_pwm = std::stoi(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon)+ "/pwm1")); // not super useful gpu.vram_used = std::stoul(readFile(hw + "/mem_info_vram_used")); gpu.vram_total = std::stoul(readFile(hw + "/mem_info_vram_total")); auto metrics = getGpuMetrics(header, hw + "/gpu_metrics"); // check if metrics valid, if not use fs if (header.structure_size != 0) { gpu.core_clock = metrics.average_vclk1_frequency; // why not gfxclock? gpu.mem_clock = metrics.average_gfxclk_frequency; // why gfxclock? min mem clock seems to be 96mhz, this is probably including time sleeping gpu.core_usage = metrics.average_gfx_activity; gpu.media_usage = metrics.average_mm_activity; gpu.umc_usage = metrics.average_umc_activity; gpu.edge_temp = metrics.temperature_edge; gpu.hotspot_temp = metrics.temperature_hotspot; gpu.mem_temp = metrics.temperature_mem; gpu.gfx_vrm_temp = metrics.temperature_vrgfx; gpu.soc_vrm_temp = metrics.temperature_vrsoc; gpu.mem_vrm_temp = metrics.temperature_vrmem; gpu.power_avg = metrics.average_socket_power; } else { gpu.core_clock = std::stoll(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/freq1_input", 16)) / 1000000; gpu.mem_clock = std::stoll(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/freq2_input", 16)) / 1000000; gpu.vcore = std::stod(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/in0_input", 8)) / 1000.0; gpu.power_avg = std::stol(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/power1_input", 3)); gpu.edge_temp = std::stol(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon) + "/temp1_input", 2)); gpu.core_usage = std::stoi(readFile(hw + "/gpu_busy_percent")); } if (gpu.fan_speed > 9999) gpu.fan_speed = 9999; return gpu; } gpu_t getGpu(std::string hwmon) { gpu_t gpu; // these are always read from fs gpu.fan_speed = std::stol(readFile(hwmon + "/fan1_input", 4)); gpu.vcore = std::stol(readFile(hwmon + "/in0_input", 4)) / 1000.0; gpu.power_cap = std::stol(readFile(hwmon + "/power1_cap", 16)) / 1000000; // gpu.power_max = std::stol(readFile(hwmon + "/power1_cap_max", 16)) / 1000000; // gpu.fan_pwm = std::stoi(readFile(hw + "/hwmon/hwmon" + std::to_string(hwmon)+ "/pwm1")); // not super useful gpu.vram_used = std::stoul(readFile(hwmon + "/../../mem_info_vram_used", 16)); // gpu.vram_total = std::stoul(readFile(hwmon + "/../../mem_info_vram_total", 16)); // these also exist in gpu_metrics? gpu.core_clock = std::stoll(readFile(hwmon + "/freq1_input", 16)) / 1000000; gpu.mem_clock = std::stoll(readFile(hwmon + "/freq2_input", 16)) / 1000000; gpu.power_avg = std::stol(readFile(hwmon + "/power1_input", 16)) / 1000000; gpu.edge_temp = std::stol(readFile(hwmon + "/temp1_input", 2)); gpu.core_usage = std::stoi(readFile(hwmon + "/../../gpu_busy_percent")); if (gpu.fan_speed > 9999) gpu.fan_speed = 9999; return gpu; }