118 lines
3.4 KiB
C++
118 lines
3.4 KiB
C++
#include "fgc/HostMetrics.h"
|
|
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include <sys/statvfs.h>
|
|
#include <unistd.h>
|
|
|
|
namespace fgc::hostmetrics {
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
namespace {
|
|
|
|
std::string readFile(const fs::path& p) {
|
|
std::ifstream f(p);
|
|
if (!f) return {};
|
|
std::ostringstream ss;
|
|
ss << f.rdbuf();
|
|
return ss.str();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
double parseMilliCelsius(const std::string& s) {
|
|
try {
|
|
return std::stod(s) / 1000.0; // sysfs reports milli-degrees C
|
|
} catch (...) {
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
MemInfo parseMeminfo(const std::string& text) {
|
|
MemInfo m;
|
|
std::istringstream in(text);
|
|
std::string line;
|
|
double mem_total_kb = 0, mem_avail_kb = 0, swap_total_kb = 0, swap_free_kb = 0;
|
|
bool have_total = false, have_avail = false;
|
|
while (std::getline(in, line)) {
|
|
std::istringstream ls(line);
|
|
std::string key, val, unit;
|
|
if (!(ls >> key >> val)) continue;
|
|
double kb = 0;
|
|
try { kb = std::stod(val); } catch (...) { continue; }
|
|
if (key == "MemTotal:") { mem_total_kb = kb; have_total = true; }
|
|
else if (key == "MemAvailable:") { mem_avail_kb = kb; have_avail = true; }
|
|
else if (key == "SwapTotal:") swap_total_kb = kb;
|
|
else if (key == "SwapFree:") swap_free_kb = kb;
|
|
}
|
|
m.ok = have_total && have_avail;
|
|
m.total_mb = mem_total_kb / 1024.0;
|
|
m.avail_mb = mem_avail_kb / 1024.0;
|
|
m.swap_used_mb = (swap_total_kb - swap_free_kb) / 1024.0;
|
|
return m;
|
|
}
|
|
|
|
ThermalInfo readThermal() {
|
|
ThermalInfo t;
|
|
const fs::path root = "/sys/class/thermal";
|
|
std::error_code ec;
|
|
if (!fs::exists(root, ec)) return t;
|
|
for (auto& e : fs::directory_iterator(root, ec)) {
|
|
const auto name = e.path().filename().string();
|
|
if (name.rfind("thermal_zone", 0) != 0) continue;
|
|
std::string temp_s = readFile(e.path() / "temp");
|
|
if (temp_s.empty()) continue;
|
|
double c = parseMilliCelsius(temp_s);
|
|
if (!t.ok || c > t.max_temp_c) {
|
|
t.ok = true;
|
|
t.max_temp_c = c;
|
|
std::string type = readFile(e.path() / "type");
|
|
// strip trailing newline
|
|
while (!type.empty() && (type.back() == '\n' || type.back() == '\r')) type.pop_back();
|
|
t.hottest_zone = type.empty() ? name : type;
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
|
|
DiskInfo readDisk(const std::string& path) {
|
|
DiskInfo d;
|
|
d.path = path;
|
|
struct statvfs vfs {};
|
|
if (statvfs(path.c_str(), &vfs) != 0) return d;
|
|
const double frsize = static_cast<double>(vfs.f_frsize);
|
|
const double total = static_cast<double>(vfs.f_blocks) * frsize;
|
|
const double avail = static_cast<double>(vfs.f_bavail) * frsize;
|
|
const double gb = 1024.0 * 1024.0 * 1024.0;
|
|
d.ok = true;
|
|
d.total_gb = total / gb;
|
|
d.free_gb = avail / gb;
|
|
d.used_pct = total > 0 ? 100.0 * (total - avail) / total : 0.0;
|
|
return d;
|
|
}
|
|
|
|
MemInfo readMeminfo() {
|
|
return parseMeminfo(readFile("/proc/meminfo"));
|
|
}
|
|
|
|
LoadInfo readLoad() {
|
|
LoadInfo l;
|
|
double avg[3] = {0, 0, 0};
|
|
if (getloadavg(avg, 3) == 3) {
|
|
l.ok = true;
|
|
l.load1 = avg[0];
|
|
l.load5 = avg[1];
|
|
l.load15 = avg[2];
|
|
}
|
|
long n = sysconf(_SC_NPROCESSORS_ONLN);
|
|
l.cpus = (n > 0) ? static_cast<int>(n) : 0;
|
|
return l;
|
|
}
|
|
|
|
} // namespace fgc::hostmetrics
|