diff --git a/.gitignore b/.gitignore index a2153c9..038b9b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.o +*.d linuxSmartie \ No newline at end of file diff --git a/Makefile b/Makefile index 741dd35..646ece1 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,40 @@ -MAKEFLAGS := --jobs=$(shell nproc) +MAKEFLAGS := --jobs=16 # MAKEFLAGS += --output-sync=target # compiling with C++26 -BUILD_OPTS = -std=c++2c -Ofast -fdiagnostics-color=always +CXXFLAGS := -std=c++2c -Ofast -fdiagnostics-color=always -Iinclude +# CXXFLAGS += -MMD -MP -build: - g++ -c $(BUILD_OPTS) -o main.o main.cpp - g++ -c $(BUILD_OPTS) -o LCDDisplay.o -Iinclude include/LCDDisplay.cpp - g++ $(BUILD_OPTS) -o linuxSmartie LCDDisplay.o main.o +SOURCES := main.cpp $(wildcard src/*.cpp) +OBJECTS := $(SOURCES:.cpp=.o) +# DEPS := $(OBJECTS:.o=.d) +TEST_SRC := test.cpp $(wildcard src/*.cpp) +TEST_OBJS := $(TEST_SRC:.cpp=.o) + +# glowny target, linkuje linuxSmartie, potrzebuje ${OBJECTS} +linuxSmartie: $(OBJECTS) + g++ $(CXXFLAGS) -o $@ $^ + +# kompiluje test.cpp zamiast main.cpp +test: $(TEST_OBJS) + g++ $(CXXFLAGS) -o $@ $^ + +# kompiluje obiekty, potrzebuje zrodel cpp +%.o: %.cpp + g++ $(CXXFLAGS) -c $< -o $@ + +# -include $(DEPS) + +.PHONY: clean clean: - rm linuxSmartie *.o \ No newline at end of file + rm -f linuxSmartie $(OBJECTS) $(DEPS) $(TEST_OBJS) + + +# build: +# g++ -c $(BUILD_OPTS) -o LCDDisplay.o -Iinclude include/LCDDisplay.cpp +# g++ -c $(BUILD_OPTS) -o gpu.o -Iinclude include/gpu.cpp +# g++ -c $(BUILD_OPTS) -o utils.o -Iinclude include/utils.cpp +# g++ -c $(BUILD_OPTS) -o main.o main.cpp + +# g++ $(BUILD_OPTS) -o linuxSmartie *.o # linking diff --git a/README.md b/README.md index 7812600..eb83962 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,40 @@ Same as plugins. Just write more features scrub, learn some C++, damn - Screens could be automatic tbh, like if it detects media playing it switches to media screen, if GPU power > 80W it switches to main (hwmon) screen - Gonna need custom chars for sure at some point - Measure execution time of main loop, if it's close enough to 1000ms, add network monitoring -- Add more getters in general, CPU temp/clock/power/Vcore would be the big one \ No newline at end of file +- Add more getters in general, CPU temp/clock/power/Vcore would be the big one +- GPU is about as done as it's gonna be +- Needs bar graphs still +- Parse gpu_metrics for GPU metrics + +## LCD layout +It looks something like this +``` +**************************************** +0.4 0 ||09:30:36| 124fps +53/40/35C 4.53GB 544MB 32/40C +26W 424R 65.9W 0R 7/244W 11W +1,200V 1186MHz 3150 2/9MHz 0,112V +**************************************** +``` + +### Ok but what does it all mean +In general left side is CPU/system stuff, right side is GPU stuff +``` +{act core cnt} {whea} {time} {bar/1cpu%}{bar/AllCPU%}{TIME}{gpu%} {xbat} {fps} + +{dieAvg}/{cache}/{iod}C {ram}GB {vram}GB {edge}/{junction}C + +{cpuPpt}W {cpufan}R {wallPow}W {gpufan}R {gpuPpt}/{cap}W {gpuBoard}W + +{cpuV}V {avgCpuFreq}MHz {gpuCoreClkCap} {gpuCoreClk}/{gpuMemClk}MHz {gpuV}V +``` + +Not all of this will be possible ofc but it's a start + +Raw LCD Smartie lines below: +``` +Text01="$dll(hwinfo,1,Average Active Core Count,1)$Fill(9)$dll(hwinfo,1,Total Errors,0)$Fill(14)$dll(tinybar2,8,$dll(hwinfo,1,Max CPU/Thread Usage,),1)$Fill(5)$dll(tinybar2,7,$dll(hwinfo,1,Total CPU Usage,),1)$Time(hh:mm:ss)$dll(tinybar2,6,$dll(hwinfo,1,GPU Utilization,),1)$dll(xbat,1,i,1)$Fill(33)$Right($dll(hwinfo,1,Framerate (Presented),0),$4%)fps" +Text02="$dll(hwinfo,1,1|CPU Die (average),0|a)/$dll(hwinfo,1,1|L3 Cache (CCD1),0)/$dll(hwinfo,1,1|CPU IOD Hotspot,0)$Chr(176)$Fill(10)$dll(format,2,$dll(hwinfo,1,1|8|4,0),0##B)B$Fill(24)$Right($dll(format,2,$dll(hwinfo,1,GPU D3D Memory Dedicated,0),0##B),$6%)B$Fill(34)$Right($dll(hwinfo,1,GPU|1|1,)/$dll(hwinfo,1,GPU|1|4,)$Chr(176),$7%)" +Text03="$dll(hwinfo,1,5|1,0)W$Fill(5)$dll(hwinfo,1,3|2,)R$Fill(14)$Right($dll(tasmopwr,1,tasmota-plug-pc.lan,)W,$6%)$Fill(21)$Right($dll(hwinfo,1,GPU|3|1,)R,$5%)$Fill(27)$Right($dll(hwinfo,1,GPU|5|9,0)/$dll(hwinfo,1,GPU|5|10,0)W,$8%)$Fill(36)$Right($dll(hwinfo,1,GPU|5|7,0)W,$4%)" +Text04="$dll(hwinfo,1,Vcore,3)V $Right($dll(hwinfo,1,Average Effective Clock,a)MHz,$7%)$Fill(16)$dll(hwinfo,1,GPU Shader Clock Frequency Limit,)$Fill(21)$Right($dll(hwinfo,1,GPU|6|2,)/$dll(hwinfo,1,GPU|6|4,)MHz,$12%)$Fill(34)$dll(hwinfo,1,GPU|2|1,3)V$CustomChar(1,16,6,9,8,8,9,6,0)" +``` diff --git a/include/LCDDisplay.hpp b/include/LCDDisplay.hpp index 2d61e20..a85c886 100644 --- a/include/LCDDisplay.hpp +++ b/include/LCDDisplay.hpp @@ -18,4 +18,5 @@ class LCDDisplay { void setCursor(uint8_t row, uint8_t col); void writeLines(std::array lines); void writeSStream(std::stringstream& ss); + void setCustomChar(uint8_t index, std::array cchar); }; diff --git a/include/gpu.hpp b/include/gpu.hpp new file mode 100644 index 0000000..049c157 --- /dev/null +++ b/include/gpu.hpp @@ -0,0 +1,25 @@ +#include + +struct gpu_t { + uint16_t fan_speed; + uint16_t core_clock; + uint16_t mem_clock; + double vcore; + uint16_t power_avg; + uint16_t power_cap; + uint16_t power_max; + uint8_t fan_pwm; + uint8_t edge_temp; + uint8_t hotspot_temp; + uint8_t mem_temp; + uint8_t gfx_vrm_temp; + uint8_t soc_vrm_temp; + uint8_t mem_vrm_temp; + uint64_t vram_used; + uint64_t vram_total; + uint8_t core_usage; + uint8_t media_usage; + uint8_t umc_usage; +}; + +gpu_t getGpu(std::string hw); \ No newline at end of file diff --git a/include/utils.hpp b/include/utils.hpp new file mode 100644 index 0000000..7b7df72 --- /dev/null +++ b/include/utils.hpp @@ -0,0 +1,6 @@ +#include +#include + +std::string readFile(std::string path, uint8_t trim = 0); +int get_val(const std::string &target, const std::string &content); +std::string findHwmonPath(std::string module); \ No newline at end of file diff --git a/main.cpp b/main.cpp index 7fa850b..329c3c3 100644 --- a/main.cpp +++ b/main.cpp @@ -13,32 +13,21 @@ #include #include "include/LCDDisplay.hpp" -#include "include/linux-system-usage.hpp" +#include "include/gpu.hpp" +#include "include/utils.hpp" #define LCD_PORT "/dev/ttyACM0" #define LCD_INTERVAL_MS 1000 -#define LCD_CONTRAST 225 - -struct gpuHwmon_t { - std::string fan_speed; - std::string core_clock; - std::string mem_clock; - std::string core_mv; - std::string power_avg; - std::string power_cap; - std::string power_max; - std::string fan_pwm; - std::string edge_temp; - std::string junction_temp; - std::string mem_temp; -}; +#define LCD_CONTRAST 215 +#define FILL_CHAR ' ' struct mem_usage_t { - std::string free; - std::string used; - std::string total; + uint64_t free; + uint64_t used; + uint64_t total; }; +/* DISPLAY FUNCS */ std::string pBytes(double i, bool isKbytes = false) { std::stringstream ss; std::array suffix = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'}; @@ -46,24 +35,43 @@ std::string pBytes(double i, bool isKbytes = false) { if (s == 'K' && isKbytes) continue; i /= 1024.0; if (i < 1024) { - ss << std::fixed << std::setprecision(i > 100 ? 1 : 2) << i << s; + uint8_t p = 2; + if (i > 10) p = 1; + if (i > 100) p = 0; + ss << std::fixed << std::setprecision(p) << i << s; return ss.str(); } } return "++++"; } +// converts number to string with given decimal places +std::string pNum(auto num, uint8_t decs = 0) { + std::stringstream ss; + ss << std::fixed << std::setprecision(decs) << num; + return ss.str(); +} + +// pads given string to size std::string pad(std::string s, uint8_t w, bool ljust = false) { - if (w > s.size()) s.insert(ljust ? s.end() : s.begin(), w - s.size(), ' '); + if (w > s.size()) s.insert(ljust ? s.end() : s.begin(), w - s.size(), FILL_CHAR); return s; } +// fills n spaces +std::string fill(uint8_t n) { + return std::string(n, FILL_CHAR); +} + +/* getters */ std::string getAvgs() { std::stringstream ss; double avgs[3]; getloadavg(avgs, 3); - ss << std::fixed << std::setprecision(2); - ss << avgs[0] << " " << avgs[1] << " " << avgs[2]; + for (uint8_t i = 0; i < 3; i++) { + ss << std::fixed << std::setprecision(avgs[i] > 10 ? 1 : 2); + ss << " " << avgs[i]; + } return ss.str(); } @@ -83,10 +91,15 @@ std::array getTimeDate() { mem_usage_t getRam() { mem_usage_t mem; - auto memory_data = get_system_usage_linux::read_memory_data(); - mem.free = pBytes(memory_data.available_memory, true); - mem.used = pBytes(memory_data.total_memory - memory_data.available_memory, true); - mem.total = pBytes(memory_data.total_memory, true); + std::ifstream proc_meminfo("/proc/meminfo"); + + if (proc_meminfo.good()) { + std::string content((std::istreambuf_iterator(proc_meminfo)), std::istreambuf_iterator()); + mem.free = get_val("MemAvailable:", content); + mem.total = get_val("MemTotal:", content); + mem.used = mem.total - mem.free; + } + proc_meminfo.close(); return mem; } @@ -94,87 +107,82 @@ mem_usage_t getDisk(std::string mount) { mem_usage_t disk; struct statvfs diskData; statvfs(mount.c_str(), &diskData); - disk.free = pBytes(diskData.f_bfree * diskData.f_frsize); - disk.used = pBytes((diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize); - disk.total = pBytes(diskData.f_blocks * diskData.f_frsize); + disk.free = diskData.f_bfree * diskData.f_frsize; + disk.used = (diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize; + disk.total = diskData.f_blocks * diskData.f_frsize; return disk; } -std::string readFile(std::string path, uint8_t trim = 0) { - std::string ret; - std::stringstream ss; - std::ifstream fs(path); - if (!fs.good()) { - std::cerr << "Error reading " << path << std::endl; - exit(1); - } - ss << fs.rdbuf(); - fs.close(); - ret = ss.str(); - return ret.substr(0, ret.size() - trim - 1); -} +auto getCpuTemp(std::string hw) { + struct { + double tctl; + double tccd1; + } cpu; -gpuHwmon_t getGpu(std::string hw) { - gpuHwmon_t gpu; - - gpu.fan_speed = readFile(hw + "/fan1_input"); - gpu.core_clock = readFile(hw + "/freq1_input", 6); - gpu.mem_clock = readFile(hw + "/freq2_input", 6); - gpu.core_mv = readFile(hw + "/in0_input"); - gpu.power_avg = readFile(hw + "/power1_average", 6); - gpu.power_cap = readFile(hw + "/power1_cap", 6); - gpu.power_max = readFile(hw + "/power1_cap_max", 6); - gpu.fan_pwm = readFile(hw + "/pwm1"); - gpu.edge_temp = readFile(hw + "/temp1_input", 3); - gpu.junction_temp = readFile(hw + "/temp2_input", 3); - gpu.mem_temp = readFile(hw + "/temp3_input", 3); - - return gpu; -} - -std::string getCpuTemp() { - return readFile("/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon3/temp1_input"); + cpu.tctl = (double)(std::stoul(readFile(hw + "/temp1_input")) / 1000.0); + cpu.tccd1 = (double)(std::stoul(readFile(hw + "/temp3_input")) / 1000.0); + return cpu; } void collectAndDraw(LCDDisplay *lcd) { - auto td = getTimeDate(); - auto ram = getRam(); - auto anime = getDisk("/mnt/anime"); - auto home = getDisk("/var/home/drath"); - auto gpu = getGpu("/sys/devices/pci0000:00/0000:00:03.1/0000:08:00.0/0000:09:00.0/0000:0a:00.0/hwmon/hwmon2"); - - std::array lines; - - lines[0] = td[1] + " " + td[0] + pad(getAvgs(), 20); - - lines[1] = pad(ram.used + "/" + ram.total, 13, true) + " "; - lines[1] += pad(gpu.fan_speed + "R", 5) + " "; - lines[1] += pad(gpu.power_avg + "/" + gpu.power_cap + "W", 8) + " "; - lines[1] += pad(gpu.edge_temp + "/" + gpu.junction_temp + "C", 8); - - lines[2] = "/home/drath:" + pad(home.free + " free of " + home.total, 28); - - lines[3] = "/mnt/anime: " + pad(anime.free + " free of " + anime.total, 28); - - lcd->writeLines(lines); } int main(int argc, char *argv[]) { + bool daemon_mode = (argc > 1 && std::string(argv[1]) == "-d"); + + /* init lcd, set contrast and backlight */ LCDDisplay lcd(LCD_PORT, 0010002); - if (argc > 1 && std::string(argv[1]) == "-d") { - std::cout << "[Chrono] Running in daemon mode, " << LCD_INTERVAL_MS << "ms interval" << std::endl; + if (daemon_mode) { lcd.setContrast(LCD_CONTRAST); lcd.setBacklight(true); - std::chrono::milliseconds interval(LCD_INTERVAL_MS); - auto start = std::chrono::steady_clock::now(); - while (true) { - collectAndDraw(&lcd); + } + + /* initial vars */ + std::array lines; + auto cpu_hwmon = findHwmonPath("k10temp"); + auto gpu_hwmon = "/sys/class/drm/card1/device"; + + /* loop setup */ + std::cout << "[Chrono] Running in daemon mode, " << LCD_INTERVAL_MS << "ms interval" << std::endl; + std::chrono::milliseconds interval(LCD_INTERVAL_MS); + auto start = std::chrono::steady_clock::now(); + + /* main loop */ + while (true) { + auto td = getTimeDate(); + auto ram = getRam(); + auto anime = getDisk("/mnt/anime"); + auto home = getDisk("/var/home/drath"); + auto gpu = getGpu(gpu_hwmon); + auto cpu = getCpuTemp(cpu_hwmon); + + lines[0] = td[1] + " " + td[0] + pad(getAvgs(), 20); + + lines[1] = pad(pNum(cpu.tctl) + "/" + pNum(cpu.tccd1) + "C", 8, true); + lines[1] += pad(pBytes(ram.used, true) + "B", 7, true); + lines[1] += fill(7); + lines[1] += pad(pBytes(gpu.vram_used) + "B", 7); + lines[1] += pad(std::to_string(gpu.edge_temp) + "/" + std::to_string(gpu.hotspot_temp) + "/" + std::to_string(gpu.mem_temp) + "C", 11); + + lines[2] = pad("home: " + pBytes(home.free), 11, true); + lines[2] += fill(15); + lines[2] += pad(pNum(gpu.fan_speed) + "R", 5); + lines[2] += pad(std::to_string(gpu.power_avg) + "/" + std::to_string(gpu.power_cap) + "W", 9); + + lines[3] = pad("anime: " + pBytes(anime.free), 13, true); + lines[3] += fill(8); + lines[3] += pad(pNum(gpu.core_clock) + "/" + pNum(gpu.mem_clock) + "MHz ", 13); + lines[3] += pad(pNum(gpu.vcore, 3) + "V", 5); + + lcd.writeLines(lines); + + if (daemon_mode) { std::this_thread::sleep_until(start + interval); start += interval; + } else { + break; } - } else { - collectAndDraw(&lcd); } return 0; diff --git a/include/LCDDisplay.cpp b/src/LCDDisplay.cpp similarity index 90% rename from include/LCDDisplay.cpp rename to src/LCDDisplay.cpp index 0bf1c7f..991f5e1 100644 --- a/include/LCDDisplay.cpp +++ b/src/LCDDisplay.cpp @@ -84,3 +84,11 @@ void LCDDisplay::writeSStream(std::stringstream& ss) { setCursor(2, 0); writeStr(s.substr(80, 159)); } + +void LCDDisplay::setCustomChar(uint8_t index, std::array cchar) { + uint8_t cmdbuf[11]; + cmdbuf[0] = 254; cmdbuf[1] = 78; cmdbuf[2] = index; + for(uint8_t i = 0; i < 8; i++) + cmdbuf[i+3] = cchar[i]; + write(_lcd, cmdbuf, 11); +} \ No newline at end of file diff --git a/src/gpu.cpp b/src/gpu.cpp new file mode 100644 index 0000000..e22c37d --- /dev/null +++ b/src/gpu.cpp @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include + +struct GpuMetricsHeader_t { + uint16_t structure_size; + uint8_t format_revision; + uint8_t content_revision; +}; + +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; +}; + +GpuMetricsHeader_t getGpuMetricsRev(std::string path) { + GpuMetricsHeader_t header; + std::ifstream f(path, std::ios::binary); + if (f.good()) { + f.read(reinterpret_cast(&header), sizeof(header)); + std::cout << "[GpuMetrics] Read GpuMetrics format v" << std::to_string(header.format_revision) << "_" << std::to_string(header.content_revision); + std::cout << ", size " << std::to_string(header.structure_size) << std::endl; + f.close(); + } else { + std::cerr << "[GpuMetrics] Error reading gpu metrics header" << std::endl; + } + + return header; +} + +auto getGpuMetrics(GpuMetricsHeader_t h, std::string path) { + GpuMetrics_v1_3_t metrics; + if (h.format_revision == 1 && h.content_revision == 3) { + 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(); + } + } else { + std::cout << "[GpuMetrics] read failed, unsupported format" << std::endl; + } + + return metrics; +} + +// clean abstraction of gpu_metrics + extra metrics from fs +gpu_t getGpu(std::string hw) { + gpu_t gpu; + auto h = getGpuMetricsRev(hw + "/gpu_metrics"); + auto metrics = getGpuMetrics(h, hw + "/gpu_metrics"); + + // we want as much data as posible from gpu_metrics so we dont read filesystem as much + gpu.fan_speed = std::stol(readFile(hw + "/hwmon/hwmon2/fan1_input")); + 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.vcore = std::stod(readFile(hw + "/hwmon/hwmon2/in0_input")) / 1000.0; + gpu.power_avg = metrics.average_socket_power; + gpu.power_cap = std::stol(readFile(hw + "/hwmon/hwmon2/power1_cap", 6)); + gpu.power_max = std::stol(readFile(hw + "/hwmon/hwmon2/power1_cap_max", 6)); + // gpu.fan_pwm = std::stoi(readFile(hw + "/hwmon/hwmon2/pwm1")); // not super useful + 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.vram_used = std::stoul(readFile(hw + "/mem_info_vram_used")); + gpu.vram_total = std::stoul(readFile(hw + "/mem_info_vram_total")); + gpu.core_usage = metrics.average_gfx_activity; + gpu.media_usage = metrics.average_mm_activity; + gpu.umc_usage = metrics.average_umc_activity; + return gpu; +} \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..e7acc46 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include + +/* SENSOR GETTERS + UTILS*/ +std::string readFile(std::string path, uint8_t trim) { + std::string ret; + std::stringstream ss; + std::ifstream fs(path); + if (!fs.good()) { + std::cerr << "Error reading " << path << std::endl; + exit(1); + } + ss << fs.rdbuf(); + fs.close(); + ret = ss.str(); + if (ret.size() < trim) return ret; + return ret.substr(0, ret.size() - trim - 1); +} + +int get_val(const std::string &target, const std::string &content) { + int result = -1; + std::size_t start = content.find(target); + if (start != std::string::npos) { + int begin = start + target.length(); + std::size_t end = content.find("kB", start); + std::string substr = content.substr(begin, end - begin); + result = std::stoi(substr); + } + return result; +} + +std::string findHwmonPath(std::string module) { + uint8_t id = 0; + for (; id < 10; id++) + if (readFile("/sys/class/hwmon/hwmon" + std::to_string(id) + "/name") == module) { + std::cout << ("[Hwmon] Detected " + module + " path is " + "/sys/class/hwmon/hwmon" + std::to_string(id)) << std::endl; + return "/sys/class/hwmon/hwmon" + std::to_string(id); + } + return ""; +} \ No newline at end of file diff --git a/tests/gpu_metrics.cpp b/tests/gpu_metrics.cpp new file mode 100644 index 0000000..e899b49 --- /dev/null +++ b/tests/gpu_metrics.cpp @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +struct GpuMetricsHeader_t { + uint16_t structure_size; + uint8_t format_revision; + uint8_t content_revision; +}; + +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; +}; + +GpuMetricsHeader_t getGpuMetricsRev(std::string path) { + GpuMetricsHeader_t header; + std::ifstream f(path, std::ios::binary); + if (f.good()) { + f.read(reinterpret_cast(&header), sizeof(header)); + std::cout << "[GpuMetrics] Read GpuMetrics format v" << std::to_string(header.format_revision) << "_" << std::to_string(header.content_revision); + std::cout << ", size " << std::to_string(header.structure_size) << std::endl; + } else { + std::cerr << "[GpuMetrics] Error reading gpu metrics header" << std::endl; + } + return header; +} + +auto getGpuMetrics(GpuMetricsHeader_t h, std::string path) { + GpuMetrics_v1_3_t gpu; + if (h.format_revision == 1 && h.content_revision == 3) { + std::ifstream f(path, std::ios::binary); + if (f.good()) { + f.ignore(sizeof(h)); // skip header + f.read(reinterpret_cast(&gpu), sizeof(gpu)); + } + } else { + std::cout << "[GpuMetrics] read failed, unsupported format" << std::endl; + } + return gpu; +} + +int main(int argc, char *argv[]) { + std::string m = "/sys/devices/pci0000:00/0000:00:03.1/0000:08:00.0/0000:09:00.0/0000:0a:00.0/gpu_metrics"; + GpuMetricsHeader_t h = getGpuMetricsRev(m); + auto gpu = getGpuMetrics(h, m); + + std::cout << "temperature_edge: " << std::to_string(gpu.temperature_edge) << std::endl; + std::cout << "temperature_hotspot: " << std::to_string(gpu.temperature_hotspot) << std::endl; + std::cout << "temperature_mem: " << std::to_string(gpu.temperature_mem) << std::endl; + std::cout << "temperature_vrgfx: " << std::to_string(gpu.temperature_vrgfx) << std::endl; + std::cout << "temperature_vrsoc: " << std::to_string(gpu.temperature_vrsoc) << std::endl; + std::cout << "temperature_vrmem: " << std::to_string(gpu.temperature_vrmem) << std::endl; + std::cout << "average_gfx_activity: " << std::to_string(gpu.average_gfx_activity) << std::endl; + std::cout << "average_umc_activity: " << std::to_string(gpu.average_umc_activity) << std::endl; + std::cout << "average_mm_activity: " << std::to_string(gpu.average_mm_activity) << std::endl; + std::cout << "average_socket_power: " << std::to_string(gpu.average_socket_power) << std::endl; + std::cout << "energy_accumulator: " << std::to_string(gpu.energy_accumulator) << std::endl; + std::cout << "system_clock_counter: " << std::to_string(gpu.system_clock_counter) << std::endl; + std::cout << "average_gfxclk_frequency: " << std::to_string(gpu.average_gfxclk_frequency) << std::endl; + std::cout << "average_socclk_frequency: " << std::to_string(gpu.average_socclk_frequency) << std::endl; + std::cout << "average_uclk_frequency: " << std::to_string(gpu.average_uclk_frequency) << std::endl; + std::cout << "average_vclk0_frequency: " << std::to_string(gpu.average_vclk0_frequency) << std::endl; + std::cout << "average_dclk0_frequency: " << std::to_string(gpu.average_dclk0_frequency) << std::endl; + std::cout << "average_vclk1_frequency: " << std::to_string(gpu.average_vclk1_frequency) << std::endl; + std::cout << "average_dclk1_frequency: " << std::to_string(gpu.average_dclk1_frequency) << std::endl; + std::cout << "current_gfxclk: " << std::to_string(gpu.current_gfxclk) << std::endl; + std::cout << "current_socclk: " << std::to_string(gpu.current_socclk) << std::endl; + std::cout << "current_uclk: " << std::to_string(gpu.current_uclk) << std::endl; + std::cout << "current_vclk0: " << std::to_string(gpu.current_vclk0) << std::endl; + std::cout << "current_dclk0: " << std::to_string(gpu.current_dclk0) << std::endl; + std::cout << "current_vclk1: " << std::to_string(gpu.current_vclk1) << std::endl; + std::cout << "current_dclk1: " << std::to_string(gpu.current_dclk1) << std::endl; + std::cout << "throttle_status: " << std::to_string(gpu.throttle_status) << std::endl; + std::cout << "current_fan_speed: " << std::to_string(gpu.current_fan_speed) << std::endl; + std::cout << "pcie_link_width: " << std::to_string(gpu.pcie_link_width) << std::endl; + std::cout << "pcie_link_speed: " << std::to_string(gpu.pcie_link_speed) << std::endl; + std::cout << "gfx_activity_acc: " << std::to_string(gpu.gfx_activity_acc) << std::endl; + std::cout << "mem_activity_acc: " << std::to_string(gpu.mem_activity_acc) << std::endl; + std::cout << "temperature_hbm: " << std::to_string(gpu.temperature_hbm) << std::endl; + std::cout << "firmware_timestamp: " << std::to_string(gpu.firmware_timestamp) << std::endl; + std::cout << "voltage_soc: " << std::to_string(gpu.voltage_soc) << std::endl; + std::cout << "voltage_gfx: " << std::to_string(gpu.voltage_gfx) << std::endl; + std::cout << "voltage_mem: " << std::to_string(gpu.voltage_mem) << std::endl; + + return 0; +} \ No newline at end of file