359 lines
7.5 KiB
C++
359 lines
7.5 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include "Host/SystemInfo.hpp"
|
|
#include "Base/Logger.hpp"
|
|
#include "Base/Utils.hpp"
|
|
#include "Math/ByteSize.hpp"
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <climits>
|
|
#include <sys/resource.h>
|
|
#include <sys/utsname.h>
|
|
|
|
namespace openVulkanoCpp
|
|
{
|
|
namespace
|
|
{
|
|
size_t ReadMemInfo(std::string_view value)
|
|
{
|
|
std::ifstream meminfoFile("/proc/meminfo");
|
|
if (!meminfoFile)
|
|
{
|
|
Logger::PERF->error("Failed to open /proc/meminfo");
|
|
return 0;
|
|
}
|
|
std::string line;
|
|
while (std::getline(meminfoFile, line))
|
|
{
|
|
if (Utils::StartsWith(line, value))
|
|
{
|
|
std::string n, t;
|
|
size_t v;
|
|
std::istringstream ss(line);
|
|
ss >> n >> v >> t;
|
|
return ByteSize(v, ByteSizeUnit::FromName(t));
|
|
}
|
|
}
|
|
meminfoFile.close();
|
|
return 0;
|
|
}
|
|
|
|
size_t ReadProcStatus(std::string_view value)
|
|
{
|
|
std::ifstream statusFile("/proc/self/status");
|
|
if (statusFile)
|
|
{
|
|
size_t mem = 0;
|
|
std::string line;
|
|
while (std::getline(statusFile, line))
|
|
{
|
|
if (Utils::StartsWith(line, value))
|
|
{
|
|
std::string n, t;
|
|
size_t v;
|
|
std::istringstream ss(line);
|
|
ss >> n >> v >> t;
|
|
return ByteSize(v, ByteSizeUnit::FromName(t));
|
|
}
|
|
}
|
|
statusFile.close();
|
|
return mem;
|
|
}
|
|
Logger::PERF->error("Failed to open /proc/self/status");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
size_t SystemInfo::GetSystemRam()
|
|
{
|
|
return ReadMemInfo("MemTotal");
|
|
}
|
|
|
|
size_t SystemInfo::GetSystemRamAvailable()
|
|
{
|
|
return ReadMemInfo("MemAvailable");
|
|
}
|
|
|
|
size_t SystemInfo::GetAppRamUsed()
|
|
{
|
|
return ReadProcStatus("VmSize");
|
|
}
|
|
|
|
size_t SystemInfo::GetAppRamAvailable()
|
|
{
|
|
return std::min(GetSystemRamAvailable(), GetAppVirtualMemoryMax() - GetAppRamUsed());
|
|
}
|
|
|
|
size_t SystemInfo::GetAppRamMax()
|
|
{
|
|
return std::min(GetSystemRam(), GetAppVirtualMemoryMax());
|
|
}
|
|
|
|
size_t SystemInfo::GetAppVirtualMemoryMax()
|
|
{
|
|
rlimit limit;
|
|
if (getrlimit(RLIMIT_AS, &limit) == 0)
|
|
{
|
|
return limit.rlim_cur;
|
|
}
|
|
Logger::PERF->error("Failed to query max application memory");
|
|
return 0;
|
|
}
|
|
|
|
std::string SystemInfo::GetUserName()
|
|
{
|
|
char* name = getlogin();
|
|
if (!name) return "unknown";
|
|
return name;
|
|
}
|
|
|
|
std::string SystemInfo::GetHostName()
|
|
{
|
|
char hostname[HOST_NAME_MAX + 1];
|
|
gethostname(hostname, HOST_NAME_MAX + 1);
|
|
return hostname;
|
|
}
|
|
|
|
std::string SystemInfo::GetDeviceName()
|
|
{
|
|
return GetHostName();
|
|
}
|
|
|
|
std::string SystemInfo::GetDeviceVendorName()
|
|
{
|
|
std::ifstream dmiStream("/sys/class/dmi/id/board_vendor");
|
|
if (!dmiStream)
|
|
{
|
|
Logger::PERF->error("Failed to read /sys/class/dmi/id/board_vendor");
|
|
return "Unknown";
|
|
}
|
|
|
|
std::string motherboardName;
|
|
std::getline(dmiStream, motherboardName);
|
|
return motherboardName;
|
|
}
|
|
|
|
std::string SystemInfo::GetDeviceModelName()
|
|
{
|
|
std::ifstream dmiStream("/sys/class/dmi/id/board_name");
|
|
if (!dmiStream)
|
|
{
|
|
Logger::PERF->error("Failed to read /sys/class/dmi/id/board_name");
|
|
return "Unknown";
|
|
}
|
|
|
|
std::string motherboardName;
|
|
std::getline(dmiStream, motherboardName);
|
|
return motherboardName;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
struct OsInfo
|
|
{
|
|
std::string osName, osNameFormatted;
|
|
OsVersion version;
|
|
|
|
static std::string TryRead(const std::string line, std::string_view prefix)
|
|
{
|
|
if (Utils::StartsWith(line, prefix))
|
|
{
|
|
size_t prefixLen = prefix.length();
|
|
return line.substr(prefixLen, line.length() - prefixLen - 1);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
static OsVersion ParseVersionString(char* str)
|
|
{
|
|
int ver[3];
|
|
int i = 0;
|
|
|
|
while (*str && i < 3)
|
|
{
|
|
if (isdigit(*str))
|
|
{
|
|
ver[i] = strtol(str, &str, 10);
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
str++;
|
|
}
|
|
}
|
|
return {ver[0], ver[1], ver[2], 0};
|
|
}
|
|
|
|
OsInfo() : version({0, 0, 0, 0})
|
|
{
|
|
std::ifstream osRel("/etc/os-release");
|
|
std::string versionString;
|
|
if (osRel)
|
|
{
|
|
std::string line, name, tmp;
|
|
while (std::getline(osRel, line))
|
|
{
|
|
if (!(tmp = TryRead(line, "PRETTY_NAME=\"")).empty())
|
|
{
|
|
osName = std::move(tmp);
|
|
}
|
|
else if (!(tmp = TryRead(line, "NAME=\"")).empty())
|
|
{
|
|
name = std::move(tmp);
|
|
}
|
|
else if (name.empty() && Utils::StartsWith(line, "ID=\""))
|
|
{
|
|
name = line.substr(4, line.length() - 5);
|
|
}
|
|
else if (!(tmp = TryRead(line, "BUILD_ID=\"")).empty())
|
|
{
|
|
versionString = std::move(tmp);
|
|
}
|
|
else if (!(tmp = TryRead(line, "VERSION_ID=\"")).empty())
|
|
{
|
|
versionString = std::move(tmp);
|
|
}
|
|
}
|
|
if (osName.empty()) osName = name;
|
|
osNameFormatted = osName + " " + versionString;
|
|
if (!versionString.empty()) version = ParseVersionString(versionString.data());
|
|
}
|
|
if (osName.empty() || versionString.empty())
|
|
{ // fallback to uname
|
|
struct utsname buffer;
|
|
|
|
errno = 0;
|
|
if (uname(&buffer) == 0)
|
|
{
|
|
osName = buffer.sysname;
|
|
osNameFormatted = osName + " " + buffer.release;
|
|
|
|
version = ParseVersionString(buffer.release);
|
|
return;
|
|
}
|
|
perror("uname");
|
|
}
|
|
if (osName.empty()) osName = "Linux";
|
|
if (osNameFormatted.empty()) osNameFormatted = "Linux";
|
|
}
|
|
};
|
|
|
|
OsInfo osInfo;
|
|
}
|
|
|
|
std::string SystemInfo::GetOsName()
|
|
{
|
|
return osInfo.osName;
|
|
}
|
|
|
|
OsVersion SystemInfo::GetOsVersion()
|
|
{
|
|
return osInfo.version;
|
|
}
|
|
|
|
std::string SystemInfo::GetOsNameHumanReadable()
|
|
{
|
|
return osInfo.osNameFormatted;
|
|
}
|
|
|
|
DeviceType SystemInfo::GetDeviceType()
|
|
{
|
|
return DeviceType::PC; // TODO?
|
|
}
|
|
|
|
size_t SystemInfo::GetCpuCoreCount()
|
|
{
|
|
return 0; //TODO
|
|
}
|
|
|
|
size_t SystemInfo::GetCpuThreadCount()
|
|
{
|
|
return std::thread::hardware_concurrency();
|
|
}
|
|
|
|
int32_t SystemInfo::GetCpuTemperature()
|
|
{
|
|
std::ifstream tempFile("/sys/class/thermal/thermal_zone0/temp");
|
|
if (!tempFile)
|
|
{
|
|
Logger::PERF->error("Failed to open the temperature file");
|
|
return 20;
|
|
}
|
|
|
|
std::string tempStr;
|
|
std::getline(tempFile, tempStr);
|
|
|
|
return static_cast<int>(std::stof(tempStr) / 1000.0f);
|
|
}
|
|
|
|
CpuThermalState SystemInfo::GetCpuThermalState()
|
|
{
|
|
auto temp = GetCpuTemperature();
|
|
if (temp < 70) return CpuThermalState::Normal;
|
|
if (temp < 80) return CpuThermalState::Fair;
|
|
if (temp < 95) return CpuThermalState::Serious;
|
|
return CpuThermalState::Critical;
|
|
}
|
|
|
|
bool SystemInfo::IsDeviceInLowPowerMode()
|
|
{
|
|
return false; //TODO?
|
|
}
|
|
|
|
BatteryState SystemInfo::GetDeviceBatteryState()
|
|
{
|
|
std::ifstream powerSupplyFile("/sys/class/power_supply/BAT0/status");
|
|
if (powerSupplyFile)
|
|
{
|
|
std::string status;
|
|
std::getline(powerSupplyFile, status);
|
|
if (status == "Charging") return BatteryState::Charging;
|
|
if (status == "Not charging") return BatteryState::NotCharging;
|
|
if (status == "Full") return BatteryState::ChargingFull;
|
|
if (status == "Discharging") return BatteryState::Unplugged;
|
|
}
|
|
return BatteryState::Unavailable;
|
|
}
|
|
|
|
float SystemInfo::GetDeviceBatteryLevel()
|
|
{
|
|
std::ifstream powerSupplyFile("/sys/class/power_supply/BAT0/capacity");
|
|
if (powerSupplyFile)
|
|
{
|
|
float value;
|
|
powerSupplyFile >> value;
|
|
return value;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void SystemInfo::EnableEnergyEvents()
|
|
{
|
|
//TODO
|
|
}
|
|
|
|
bool SystemInfo::IsMultitaskingSupported()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
DeviceOrientation SystemInfo::GetDeviceOrientation()
|
|
{
|
|
return DeviceOrientation::LandscapeRight; // TODO?
|
|
}
|
|
|
|
void SystemInfo::EnableDeviceOrientationEvents()
|
|
{
|
|
//TODO?
|
|
}
|
|
|
|
InterfaceOrientation SystemInfo::GetInterfaceOrientation()
|
|
{
|
|
return InterfaceOrientation::Landscape; // TODO?
|
|
}
|
|
} |