diff --git a/include/cpu.hpp b/include/cpu.hpp index 90d710e..581c378 100644 --- a/include/cpu.hpp +++ b/include/cpu.hpp @@ -5,17 +5,21 @@ #include #include #include - #include #define N_CPU 16 -struct cpu_hwmon_t { - std::string path = ""; - bool zenpower = false; -}; +// struct cpu_hwmon_t { +// std::string path = ""; +// bool zenpower = false; +// }; + +namespace cpu { + +struct sensors { + std::string hwmon = ""; + bool zenpower = false; -struct cpu_t { int tdie = 0; int tctl = 0; int tccd1 = 0; @@ -27,7 +31,12 @@ struct cpu_t { uint32_t avg_freq = 0; }; -cpu_t getCpu(cpu_hwmon_t hw); -cpu_hwmon_t detectCpuHwmon(std::string pci); +// sensors getCpu(cpu_hwmon_t hw); +// cpu_hwmon_t detectCpuHwmon(std::string pci); + +void detectHwmon(sensors* target, std::string pci); +void update(sensors* g); + +} // namespace cpu #endif \ No newline at end of file diff --git a/include/gpu.hpp b/include/gpu.hpp index eb8162c..daf268d 100644 --- a/include/gpu.hpp +++ b/include/gpu.hpp @@ -1,24 +1,31 @@ #ifndef GPU_HPP #define GPU_HPP -/* see which we actually need now */ #include #include +#include #include #include #include -#include - #define REL_METRICS_PATH "/../../gpu_metrics" #define MAX_METRICS_LENGTH 512 +#define METRICS_IS(m) auto metrics = reinterpret_cast(raw_metrics) + /* should refactor this struct so its a little cleaner and closer to gpu_metrics */ -struct gpu_t { +/* clean abstraction for gpu_metrics or metrics in filesystem in sane units */ + +namespace gpu { + +struct sensors { + std::string hwmon = ""; + bool hasGpuMetrics = false; + uint16_t fan_speed = 0; uint16_t core_clock = 0; uint16_t mem_clock = 0; - double vcore = 0; + float vcore = 0.0f; uint16_t power_avg = 0; uint16_t power_cap = 0; uint16_t power_max = 0; @@ -36,8 +43,46 @@ struct gpu_t { uint8_t umc_usage = 0; }; -std::string detectGpuHwmon(std::string pci); -bool checkForMetrics(std::string hwmon); -gpu_t getGpu(std::string hw, bool hasMetrics); +void detectHwmon(sensors* target, std::string pci); +void update(sensors* g); -#endif +} // namespace gpu + +// class ThrottleStatus(IntFlag): +// # linux/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h +// PPT0 = 1 << 0 +// PPT1 = 1 << 1 +// PPT2 = 1 << 2 +// PPT3 = 1 << 3 +// SPL = 1 << 4 +// FPPT = 1 << 5 +// SPPT = 1 << 6 +// SPPT_APU = 1 << 7 +// TDC_GFX = 1 << 16 +// TDC_SOC = 1 << 17 +// TDC_MEM = 1 << 18 +// TDC_VDD = 1 << 19 +// TDC_CVIP = 1 << 20 +// EDC_CPU = 1 << 21 +// EDC_GFX = 1 << 22 +// APCC = 1 << 23 +// TEMP_GPU = 1 << 32 +// TEMP_CORE = 1 << 33 +// TEMP_MEM = 1 << 34 +// TEMP_EDGE = 1 << 35 +// TEMP_HOTSPOT = 1 << 36 +// TEMP_SOC = 1 << 37 +// TEMP_VR_GFX = 1 << 38 +// TEMP_VR_SOC = 1 << 39 +// TEMP_VR_MEM0 = 1 << 40 +// TEMP_VR_MEM1 = 1 << 41 +// TEMP_LIQUID0 = 1 << 42 +// TEMP_LIQUID1 = 1 << 43 +// VRHOT0 = 1 << 44 +// VRHOT1 = 1 << 45 +// PROCHOT_CPU = 1 << 46 +// PROCHOT_GFX = 1 << 47 +// PPM = 1 << 56 +// FIT = 1 << 57 + +#endif \ No newline at end of file diff --git a/include/gpu_metrics.hpp b/include/gpu_metrics.hpp index a6e7829..1f3e686 100644 --- a/include/gpu_metrics.hpp +++ b/include/gpu_metrics.hpp @@ -13,7 +13,7 @@ https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/include/kgd_pp #define MAX_XCC 8 #define NUM_XCP 8 -namespace gpu { +namespace metrics { struct metrics_table_header { uint16_t structure_size; diff --git a/src/cpu.cpp b/src/cpu.cpp index db7b5c5..0177b71 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -1,45 +1,89 @@ #include -cpu_hwmon_t detectCpuHwmon(std::string pci) { - cpu_hwmon_t hw; +namespace cpu { + +void detectHwmon(sensors* target, std::string pci) { std::string path = "/sys/bus/pci/devices/" + pci + "/hwmon"; + try { for (const auto& entry : std::filesystem::directory_iterator(path)) - hw.path = getFirstDir(path); + target->hwmon = getFirstDir(path); } catch (...) { - std::println("[CpuHwmon] NO CPU HWMON KERNEL MODULE DETECTED"); - return hw; + std::println("[cpu::detectHwmon] NO CPU HWMON KERNEL MODULE DETECTED"); + return; } - hw.zenpower = readFile((hw.path + "/name"), 128) == "zenpower"; - std::println("[CpuHwmon] Detected module \"{}\" in path \"{}\"", hw.zenpower ? "zenpower" : "k10temp", hw.path); - return hw; + target->zenpower = readFile((target->hwmon + "/name"), 128) == "zenpower"; + std::println("[cpu::detectHwmon] Detected module \"{}\" in path \"{}\"", target->zenpower ? "zenpower" : "k10temp", target->hwmon); } -cpu_t getCpu(cpu_hwmon_t hw) { - cpu_t cpu; +void update(sensors* c) { // commented out unused values so its faster - if (hw.path == "") return cpu; // break if no module - if (hw.zenpower) { + if (c->hwmon == "") return; // break if no module + if (c->zenpower) { // cpu.tdie = std::stoi(readFile(hw.path + "/temp1_input", 2)); - cpu.tctl = std::stoi(readFile(hw.path + "/temp2_input", 2)); - cpu.tccd1 = std::stoi(readFile(hw.path + "/temp3_input", 2)); - cpu.pcore = (double)(std::stoi(readFile(hw.path + "/power1_input", 3)) / 100.0); - cpu.psoc = (double)(std::stoi(readFile(hw.path + "/power2_input", 3)) / 100.0); - cpu.ptotal = cpu.pcore + cpu.psoc; - cpu.vcore = (double)(std::stoul(readFile(hw.path + "/in1_input", 4)) / 1000.0); + c->tctl = std::stoi(readFile(c->hwmon + "/temp2_input", 2)); + c->tccd1 = std::stoi(readFile(c->hwmon + "/temp3_input", 2)); + c->pcore = (double)(std::stoi(readFile(c->hwmon + "/power1_input", 3)) / 100.0); + c->psoc = (double)(std::stoi(readFile(c->hwmon + "/power2_input", 3)) / 100.0); + c->ptotal = c->pcore + c->psoc; + c->vcore = (double)(std::stoul(readFile(c->hwmon + "/in1_input", 4)) / 1000.0); // cpu.vsoc = (double)(std::stoul(readFile(hw.path + "/in2_input")) / 1000.0); } else { - cpu.tctl = std::stoi(readFile(hw.path + "/temp1_input", 2)); - cpu.tccd1 = std::stoi(readFile(hw.path + "/temp3_input", 2)); + c->tctl = std::stoi(readFile(c->hwmon+ "/temp1_input", 2)); + c->tccd1 = std::stoi(readFile(c->hwmon + "/temp3_input", 2)); } // lots of reads but still faster than reading /proc/cpuinfo char buf[5]; for (uint8_t i = 0; i < N_CPU; i++) { readFile2("/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq", buf, sizeof(buf)); - cpu.avg_freq += strtol(buf, NULL, 10); + c->avg_freq += strtol(buf, NULL, 10); } - cpu.avg_freq /= N_CPU; + c->avg_freq /= N_CPU; +} - return cpu; -} \ No newline at end of file +// cpu_hwmon_t detectCpuHwmon(std::string pci) { +// cpu_hwmon_t hw; +// std::string path = "/sys/bus/pci/devices/" + pci + "/hwmon"; +// try { +// for (const auto& entry : std::filesystem::directory_iterator(path)) +// hw.path = getFirstDir(path); +// } catch (...) { +// std::println("[CpuHwmon] NO CPU HWMON KERNEL MODULE DETECTED"); +// return hw; +// } +// hw.zenpower = readFile((hw.path + "/name"), 128) == "zenpower"; +// std::println("[CpuHwmon] Detected module \"{}\" in path \"{}\"", hw.zenpower ? "zenpower" : "k10temp", hw.path); +// return hw; +// } + +// cpu_t getCpu(cpu_hwmon_t hw) { +// cpu_t cpu; +// // commented out unused values so its faster +// if (hw.path == "") return cpu; // break if no module +// if (hw.zenpower) { +// // cpu.tdie = std::stoi(readFile(hw.path + "/temp1_input", 2)); +// cpu.tctl = std::stoi(readFile(hw.path + "/temp2_input", 2)); +// cpu.tccd1 = std::stoi(readFile(hw.path + "/temp3_input", 2)); +// cpu.pcore = (double)(std::stoi(readFile(hw.path + "/power1_input", 3)) / 100.0); +// cpu.psoc = (double)(std::stoi(readFile(hw.path + "/power2_input", 3)) / 100.0); +// cpu.ptotal = cpu.pcore + cpu.psoc; +// cpu.vcore = (double)(std::stoul(readFile(hw.path + "/in1_input", 4)) / 1000.0); +// // cpu.vsoc = (double)(std::stoul(readFile(hw.path + "/in2_input")) / 1000.0); +// } else { +// cpu.tctl = std::stoi(readFile(hw.path + "/temp1_input", 2)); +// cpu.tccd1 = std::stoi(readFile(hw.path + "/temp3_input", 2)); +// } + +// // lots of reads but still faster than reading /proc/cpuinfo +// char buf[5]; +// for (uint8_t i = 0; i < N_CPU; i++) { +// readFile2("/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq", buf, sizeof(buf)); +// cpu.avg_freq += strtol(buf, NULL, 10); +// } +// cpu.avg_freq /= N_CPU; + +// return cpu; +// } + +} // namespace cpu \ No newline at end of file diff --git a/src/gpu.cpp b/src/gpu.cpp index 6729255..1ca1c79 100644 --- a/src/gpu.cpp +++ b/src/gpu.cpp @@ -1,97 +1,86 @@ #include -/* -have a bool checkForMetrics(std::string hwmon) function, just checks if file exists -have a gpu_t getGpu(std::string path, bool hasMetrics) function -maybe have a read pp_table function +/* maybe have a read pp_table function */ +/* would be neat to wrap it in a class but eh */ -MAYBE PASS A POINTER TO SENSORS/SENSORS->GPU TO FUNCS -*/ +namespace gpu { -std::string detectGpuHwmon(std::string pci) { - std::string path = getFirstDir("/sys/bus/pci/devices/" + pci + "/hwmon"); - std::println("[GpuHwmon] Detected path \"{}\"", path); - return path; -} +/* takes pointer to a target gpu::sensors struct and updates its hwmon path and detects gpu_metrics */ +void detectHwmon(sensors* target, std::string pci) { + target->hwmon = getFirstDir("/sys/bus/pci/devices/" + pci + "/hwmon"); + std::println("[gpu::detectHwmon] Detected path \"{}\"", target->hwmon); -bool checkForMetrics(std::string hwmon) { - if (FILE* file = fopen((hwmon + REL_METRICS_PATH).c_str(), "r")) { + if (FILE* file = fopen((target->hwmon + REL_METRICS_PATH).c_str(), "r")) { fclose(file); - std::println("[GpuMetrics] found metrics file"); - return true; + std::println("[gpu::detectHwmon] found metrics file"); + target->hasGpuMetrics = true; } - return false; } -gpu_t getGpuFromMetrics(std::string hwmon) { - gpu_t gpu; - char raw_metrics[MAX_METRICS_LENGTH]; - if(!readFile2(hwmon + REL_METRICS_PATH, raw_metrics, sizeof(raw_metrics))) return gpu; // return empty struct if cant read metrics - auto header = reinterpret_cast(raw_metrics); +void updateFromFs(sensors* g) { + // these are always read from fs + g->fan_speed = std::stol(readFile(g->hwmon + "/fan1_input", 4)); + g->vcore = std::stol(readFile(g->hwmon + "/in0_input", 4)) / 1000.0f; + g->power_cap = std::stol(readFile(g->hwmon + "/power1_cap", 16)) / 1000000; + g->power_max = std::stol(readFile(g->hwmon + "/power1_cap_max", 16)) / 1000000; + g->fan_pwm = std::stoi(readFile(g->hwmon + "/pwm1", 4)) * 100 / 256; + g->vram_used = std::stoul(readFile(g->hwmon + "/../../mem_info_vram_used", 16)); + g->vram_total = std::stoul(readFile(g->hwmon + "/../../mem_info_vram_total", 16)); + + g->core_clock = std::stoll(readFile(g->hwmon + "/freq1_input", 16)) / 1000000; + g->mem_clock = std::stoll(readFile(g->hwmon + "/freq2_input", 16)) / 1000000; + g->power_avg = std::stol(readFile(g->hwmon + "/power1_input", 16)) / 1000000; + g->edge_temp = std::stol(readFile(g->hwmon + "/temp1_input", 2)); + g->core_usage = std::stoi(readFile(g->hwmon + "/../../gpu_busy_percent")); +} + +void updateFromMetrics(sensors* g) { + char raw_metrics[MAX_METRICS_LENGTH]; + if (!readFile2(g->hwmon + REL_METRICS_PATH, raw_metrics, sizeof(raw_metrics))) return; + + auto header = reinterpret_cast(raw_metrics); switch (header->format_revision * 10 + header->content_revision) { - /* rx7800xt */ + /* rx5700xt?, rx7800xt */ case 13: { - auto metrics = reinterpret_cast(raw_metrics); - 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; + METRICS_IS(metrics::gpu_metrics_v1_3); + g->core_clock = metrics->average_vclk1_frequency; // why not gfxclock? + g->mem_clock = metrics->average_gfxclk_frequency; // why gfxclock? min mem clock seems to be 96mhz, this is probably including time sleeping + g->core_usage = metrics->average_gfx_activity; + g->media_usage = metrics->average_mm_activity; + g->umc_usage = metrics->average_umc_activity; + g->edge_temp = metrics->temperature_edge; + g->hotspot_temp = metrics->temperature_hotspot; + g->mem_temp = metrics->temperature_mem; + g->gfx_vrm_temp = metrics->temperature_vrgfx; + g->soc_vrm_temp = metrics->temperature_vrsoc; + g->mem_vrm_temp = metrics->temperature_vrmem; + g->power_avg = metrics->average_socket_power; + // some are missing, we used to read them form fs for some reason break; } /* ryzen 5 5600g */ case 22: { - auto metrics = reinterpret_cast(raw_metrics); - gpu.edge_temp = metrics->temperature_gfx / 100; - gpu.power_avg = metrics->average_gfx_power; - gpu.core_usage = metrics->average_gfx_activity; + METRICS_IS(metrics::gpu_metrics_v2_2); + g->edge_temp = metrics->temperature_gfx / 100; break; } /* werid hardware i probably dont like */ default: { - std::println("[GpuMetrics] Unsupported gpu_metrics_v{}_{}", header->format_revision, header->content_revision); + std::println("[gpu::updateFromMetrics] Unsupported gpu_metrics_v{}_{}", header->format_revision, header->content_revision); break; } } - - return gpu; } -gpu_t getGpuFromFs(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(hwmon + "/pwm1", 4)) * 100 / 256; - gpu.vram_used = std::stoul(readFile(hwmon + "/../../mem_info_vram_used", 16)); - // gpu.vram_total = std::stoul(readFile(hwmon + "/../../mem_info_vram_total", 16)); - - 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")); - - return gpu; +/* reads values from system and updates the target gpu::sensors struct */ +void update(sensors* g) { + if (g->hasGpuMetrics) + gpu::updateFromMetrics(g); + else + gpu::updateFromFs(g); } -gpu_t getGpu(std::string hwmon, bool hasMetrics) { - if (hasMetrics) { - return getGpuFromMetrics(hwmon); - } else { - return getGpuFromFs(hwmon); - } -} +} // namespace gpu \ No newline at end of file