burrow-pi-img/deps/tools/rpiConfigServer_src/SystemStatus.cpp
2018-12-11 20:04:00 -08:00

210 lines
5.9 KiB
C++

/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "SystemStatus.h"
#include "wpi/SmallString.h"
#include "wpi/SmallVector.h"
#include "wpi/StringRef.h"
#include "wpi/json.h"
#include "wpi/raw_istream.h"
#include "wpi/raw_ostream.h"
std::shared_ptr<SystemStatus> SystemStatus::GetInstance() {
static auto sysStatus = std::make_shared<SystemStatus>(private_init{});
return sysStatus;
}
void SystemStatus::UpdateAll() {
UpdateMemory();
UpdateCpu();
UpdateNetwork();
status(GetStatusJson());
writable(GetWritable());
}
wpi::json SystemStatus::GetStatusJson() {
wpi::json j = {{"type", "systemStatus"}};
size_t qty;
// memory
{
uint64_t first;
if (m_memoryFree.GetFirstLast(&first, nullptr, &qty)) {
j["systemMemoryFree1s"] = first / 1000;
if (qty >= 5)
j["systemMemoryFree5s"] = m_memoryFree.GetTotal() / qty / 1000;
}
if (m_memoryAvail.GetFirstLast(&first, nullptr, &qty)) {
j["systemMemoryAvail1s"] = first / 1000;
if (qty >= 5)
j["systemMemoryAvail5s"] = m_memoryAvail.GetTotal() / qty / 1000;
}
}
// cpu
{
CpuData first, last;
if (m_cpu.GetFirstLast(&first, &last, nullptr, 2)) {
uint64_t deltaTotal = last.total - first.total;
if (deltaTotal != 0) {
j["systemCpuUser1s"] =
(last.user + last.nice - first.user - first.nice) * 100 /
deltaTotal;
j["systemCpuSystem1s"] =
(last.system - first.system) * 100 / deltaTotal;
j["systemCpuIdle1s"] = (last.idle - first.idle) * 100 / deltaTotal;
}
}
if (m_cpu.GetFirstLast(&first, &last, nullptr, 6)) {
uint64_t deltaTotal = last.total - first.total;
if (deltaTotal != 0) {
j["systemCpuUser5s"] =
(last.user + last.nice - first.user - first.nice) * 100 /
deltaTotal;
j["systemCpuSystem5s"] =
(last.system - first.system) * 100 / deltaTotal;
j["systemCpuIdle5s"] = (last.idle - first.idle) * 100 / deltaTotal;
}
}
}
// network
{
NetworkData first, last;
if (m_network.GetFirstLast(&first, &last, nullptr, 2)) {
j["systemNetwork1s"] = (last.recvBytes + last.xmitBytes -
first.recvBytes - first.xmitBytes) *
8 / 1000;
}
if (m_network.GetFirstLast(&first, &last, nullptr, 6)) {
j["systemNetwork5s"] = (last.recvBytes + last.xmitBytes -
first.recvBytes - first.xmitBytes) *
8 / 5000;
}
}
return j;
}
bool SystemStatus::GetWritable() {
std::error_code ec;
wpi::raw_fd_istream is("/proc/mounts", ec);
if (ec) return false;
wpi::SmallString<256> lineBuf;
while (!is.has_error()) {
wpi::StringRef line = is.getline(lineBuf, 256).trim();
if (line.empty()) break;
wpi::SmallVector<wpi::StringRef, 8> strs;
line.split(strs, ' ', -1, false);
if (strs.size() < 4) continue;
if (strs[1] == "/") return strs[2].contains("rw");
}
return false;
}
void SystemStatus::UpdateMemory() {
std::error_code ec;
wpi::raw_fd_istream is("/proc/meminfo", ec);
if (ec) return;
wpi::SmallString<256> lineBuf;
while (!is.has_error()) {
wpi::StringRef line = is.getline(lineBuf, 256).trim();
if (line.empty()) break;
wpi::StringRef name, amtStr;
std::tie(name, amtStr) = line.split(':');
uint64_t amt;
amtStr = amtStr.trim();
if (amtStr.consumeInteger(10, amt)) continue;
if (name == "MemFree") {
m_memoryFree.Add(amt);
} else if (name == "MemAvailable") {
m_memoryAvail.Add(amt);
}
}
}
void SystemStatus::UpdateCpu() {
std::error_code ec;
wpi::raw_fd_istream is("/proc/stat", ec);
if (ec) return;
wpi::SmallString<256> lineBuf;
while (!is.has_error()) {
wpi::StringRef line = is.getline(lineBuf, 256).trim();
if (line.empty()) break;
wpi::StringRef name, amtStr;
std::tie(name, amtStr) = line.split(' ');
if (name == "cpu") {
CpuData data;
// individual values we care about
amtStr = amtStr.ltrim();
if (amtStr.consumeInteger(10, data.user)) break;
amtStr = amtStr.ltrim();
if (amtStr.consumeInteger(10, data.nice)) break;
amtStr = amtStr.ltrim();
if (amtStr.consumeInteger(10, data.system)) break;
amtStr = amtStr.ltrim();
if (amtStr.consumeInteger(10, data.idle)) break;
// compute total
data.total = data.user + data.nice + data.system + data.idle;
for (;;) {
uint64_t amt;
amtStr = amtStr.ltrim();
if (amtStr.consumeInteger(10, amt)) break;
data.total += amt;
}
m_cpu.Add(data);
break;
}
}
}
void SystemStatus::UpdateNetwork() {
std::error_code ec;
wpi::raw_fd_istream is("/proc/net/dev", ec);
if (ec) return;
NetworkData data;
wpi::SmallString<256> lineBuf;
while (!is.has_error()) {
wpi::StringRef line = is.getline(lineBuf, 256).trim();
if (line.empty()) break;
wpi::StringRef name, amtStr;
std::tie(name, amtStr) = line.split(':');
name = name.trim();
if (name.empty() || name == "lo") continue;
wpi::SmallVector<wpi::StringRef, 20> amtStrs;
amtStr.split(amtStrs, ' ', -1, false);
if (amtStrs.size() < 16) continue;
uint64_t amt;
// receive bytes
if (amtStrs[0].getAsInteger(10, amt)) continue;
data.recvBytes += amt;
// transmit bytes
if (amtStrs[8].getAsInteger(10, amt)) continue;
data.xmitBytes += amt;
}
m_network.Add(data);
}