sane makefile, sane structure, lots of updates
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
*.o
|
||||
*.d
|
||||
linuxSmartie
|
||||
41
Makefile
41
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
|
||||
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
|
||||
|
||||
38
README.md
38
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
|
||||
- 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)"
|
||||
```
|
||||
|
||||
@@ -18,4 +18,5 @@ class LCDDisplay {
|
||||
void setCursor(uint8_t row, uint8_t col);
|
||||
void writeLines(std::array<std::string, 4> lines);
|
||||
void writeSStream(std::stringstream& ss);
|
||||
void setCustomChar(uint8_t index, std::array<uint8_t, 8> cchar);
|
||||
};
|
||||
|
||||
25
include/gpu.hpp
Normal file
25
include/gpu.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <string>
|
||||
|
||||
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);
|
||||
6
include/utils.hpp
Normal file
6
include/utils.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
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);
|
||||
190
main.cpp
190
main.cpp
@@ -13,32 +13,21 @@
|
||||
#include <thread>
|
||||
|
||||
#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<std::string, 2> 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<char>(proc_meminfo)), std::istreambuf_iterator<char>());
|
||||
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<std::string, 4> 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<std::string, 4> 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;
|
||||
|
||||
@@ -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<uint8_t, 8> 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);
|
||||
}
|
||||
151
src/gpu.cpp
Normal file
151
src/gpu.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <gpu.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utils.hpp>
|
||||
|
||||
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<char *>(&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<char *>(&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;
|
||||
}
|
||||
44
src/utils.cpp
Normal file
44
src/utils.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utils.hpp>
|
||||
|
||||
/* 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 "";
|
||||
}
|
||||
162
tests/gpu_metrics.cpp
Normal file
162
tests/gpu_metrics.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
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<char *>(&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<char *>(&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;
|
||||
}
|
||||
Reference in New Issue
Block a user