/* * 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 #include #include #include #include #include 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) { std::cout << "Maximum memory usage: " << limit.rlim_cur << " bytes" << std::endl; 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; Version 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 Version 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; } Version 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(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? } }