fwt_software/include/fgc/HostMetrics.h

96 lines
3.8 KiB
C++

#pragma once
#include <string>
#include <vector>
namespace fgc::hostmetrics {
// Host (LattePanda / Linux) health reads, for the `test host` subsystem and the
// running program's CPU watch (ThermalGuard). Pure parsers are split from the
// live readers so they unit-test without a real /sys or /proc. All readers
// degrade gracefully (ok=false) rather than throw.
//
// `root` is put in front of every /sys and /proc path ("/" = the real ones), so
// a test or a throttling simulation can hand in a fake tree:
// <root>/sys/class/thermal/thermal_zone*/{temp,type}
// <root>/sys/devices/system/cpu/cpu*/cpufreq/{scaling_cur_freq,cpuinfo_max_freq,scaling_max_freq}
// <root>/sys/devices/system/cpu/cpu*/thermal_throttle/{package,core}_throttle_count
// <root>/proc/stat (when the tree has none, the real /proc/stat)
struct ThermalInfo {
bool ok = false;
double max_temp_c = 0.0; // hottest thermal zone
std::string hottest_zone; // e.g. "x86_pkg_temp"
bool throttled = false; // best-effort (false if unknown)
// The CPU's own zone, for the CPU guard: x86_pkg_temp where there is one,
// else the hottest. Not simply the hottest: the towers also list the Wi-Fi
// card (iwlwifi_1) and the ACPI zone, and the guard watches the CPU.
double cpu_temp_c = 0.0;
std::string cpu_zone;
};
// CPU clock, from cpufreq. MHz.
struct CpuFreqInfo {
bool ok = false;
double mean_mhz = 0.0; // mean of scaling_cur_freq over the cores
double hw_max_mhz = 0.0; // cpuinfo_max_freq: what the chip can do
double cap_mhz = 0.0; // lowest scaling_max_freq: what it may do now
std::vector<double> core_mhz; // per core, cpu0 first
};
// The kernel's count of times the CPU slowed itself because it ran too hot
// (x86 thermal_throttle). It only rises; a rise between two reads is throttling.
// Slow-downs to stay inside the power limit are NOT counted here - ThrottleWatch
// (ThermalGuard.h) also watches the clock for those.
struct ThrottleCount {
bool ok = false;
long long events = 0; // package count (cpu0) + every core's count
};
// Cumulative CPU time from the first line of /proc/stat, in clock ticks. Busy %
// is the change in `busy` over the change in `total` between two reads.
struct CpuTimes {
bool ok = false;
long long busy = 0;
long long total = 0;
};
struct DiskInfo {
bool ok = false;
std::string path;
double total_gb = 0.0;
double free_gb = 0.0;
double used_pct = 0.0;
};
struct MemInfo {
bool ok = false;
double total_mb = 0.0;
double avail_mb = 0.0;
double swap_used_mb = 0.0;
};
struct LoadInfo {
bool ok = false;
double load1 = 0.0, load5 = 0.0, load15 = 0.0;
int cpus = 0;
};
// ---- live readers ----
ThermalInfo readThermal(const std::string& root = "/"); // scans sys/class/thermal
CpuFreqInfo readCpuFreq(const std::string& root = "/");
ThrottleCount readThrottleCount(const std::string& root = "/");
CpuTimes readCpuTimes(const std::string& root = "/");
DiskInfo readDisk(const std::string& path); // statvfs() on the filesystem holding `path`
MemInfo readMeminfo(); // /proc/meminfo
LoadInfo readLoad(); // getloadavg() + nproc
// ---- pure parsers (reused by the readers; exposed for tests) ----
MemInfo parseMeminfo(const std::string& proc_meminfo);
double parseMilliCelsius(const std::string& zone_temp_contents); // "52000\n" -> 52.0
CpuTimes parseProcStatCpu(const std::string& proc_stat); // its "cpu " line
// Busy percentage between two reads; -1 when either is bad or no time passed.
double busyPercent(const CpuTimes& before, const CpuTimes& after);
} // namespace fgc::hostmetrics