From 46e039dab26724e3782e451c65a0745ab2bbd005 Mon Sep 17 00:00:00 2001 From: Ty Lamontagne Date: Sat, 17 Feb 2024 15:23:45 -0500 Subject: [PATCH] VMManager: Log power profile and GPUs on startup --- common/Linux/LnxMisc.cpp | 35 +++++++++ pcsx2/VMManager.cpp | 156 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 1 deletion(-) diff --git a/common/Linux/LnxMisc.cpp b/common/Linux/LnxMisc.cpp index 2919e0edfd..27029a230e 100644 --- a/common/Linux/LnxMisc.cpp +++ b/common/Linux/LnxMisc.cpp @@ -49,6 +49,41 @@ u64 GetCPUTicks() std::string GetOSVersionString() { #if defined(__linux__) + FILE* file = fopen("/etc/os-release", "r"); + if (file) + { + char line[256]; + std::string distro; + std::string version = ""; + while (fgets(line, sizeof(line), file)) + { + std::string_view line_view(line); + if (line_view.starts_with("NAME=")) + { + distro = line_view.substr(5, line_view.size() - 6); + } + else if (line_view.starts_with("BUILD_ID=")) + { + version = line_view.substr(9, line_view.size() - 10); + } + else if (line_view.starts_with("VERSION_ID=")) + { + version = line_view.substr(11, line_view.size() - 12); + } + } + fclose(file); + + // Some distros put quotes around the name and or version. + if (distro.starts_with("\"") && distro.ends_with("\"")) + distro = distro.substr(1, distro.size() - 2); + + if (version.starts_with("\"") && version.ends_with("\"")) + version = version.substr(1, version.size() - 2); + + if (!distro.empty() && !version.empty()) + return fmt::format("{} {}", distro, version); + } + return "Linux"; #else // freebsd return "Other Unix"; diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 3f4648b251..3f4e806014 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -65,6 +65,9 @@ #include "common/RedtapeWindows.h" #include #include +#include +#include +#include #endif #ifdef __APPLE__ @@ -2237,6 +2240,151 @@ bool VMManager::IsLoadableFileName(const std::string_view& path) return IsDiscFileName(path) || IsElfFileName(path) || IsGSDumpFileName(path) || IsBlockDumpFileName(path); } +#ifdef _WIN32 +inline void LogUserPowerPlan() +{ + wil::unique_any pPwrGUID; + DWORD ret = PowerGetActiveScheme(NULL, pPwrGUID.put()); + if (ret != ERROR_SUCCESS) + return; + + UCHAR aBuffer[2048]; + DWORD aBufferSize = sizeof(aBuffer); + ret = PowerReadFriendlyName(NULL, pPwrGUID.get(), &NO_SUBGROUP_GUID, NULL, aBuffer, &aBufferSize); + std::string friendlyName(StringUtil::WideStringToUTF8String((wchar_t*)aBuffer)); + if (ret != ERROR_SUCCESS) + return; + + DWORD acMax = 0, acMin = 0, dcMax = 0, dcMin = 0; + + if (PowerReadACValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MAXIMUM, &acMax) || + PowerReadACValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MINIMUM, &acMin) || + PowerReadDCValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MAXIMUM, &dcMax) || + PowerReadDCValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MINIMUM, &dcMin)) + return; + + Console.WriteLnFmt( + " Power Profile = '{}'\n" + " Power States (min/max)\n" + " AC = {}% / {}%\n" + " Battery = {}% / {}%\n", friendlyName.c_str(), acMin, acMax, dcMin, dcMax); +} +#endif + +#if defined(__linux__) || defined(_WIN32) +void LogGPUCapabilities() +{ + Console.WriteLn(Color_StrongBlack, "Graphics Adapters Detected:"); +#if defined(_WIN32) + IDXGIFactory1* pFactory = nullptr; + if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) + return; + + UINT i = 0; + IDXGIAdapter* pAdapter = nullptr; + while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND) + { + DXGI_ADAPTER_DESC desc; + LARGE_INTEGER umdver; + if (SUCCEEDED(pAdapter->GetDesc(&desc)) && SUCCEEDED(pAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &umdver))) + { + Console.WriteLnFmt( + " GPU = {}\n" + " Driver Version = {}.{}.{}.{}\n", + StringUtil::WideStringToUTF8String(desc.Description), + umdver.QuadPart >> 48, + (umdver.QuadPart >> 32) & 0xFFFF, + (umdver.QuadPart >> 16) & 0xFFFF, + umdver.QuadPart & 0xFFFF); + + i++; + pAdapter->Release(); + pAdapter = nullptr; + } + else + { + pAdapter->Release(); + pAdapter = nullptr; + + break; + } + } + + if (pAdapter) + pAdapter->Release(); + pFactory->Release(); +#else + // Credits to neofetch for the following (modified) script + std::string gpu_script = R"gpu_script( + lspci -mm | + awk -F '\"|\" \"|\\(' \ + '/"Display|"3D|"VGA/ { + a[$0] = $1 "" $3 " " ($(NF-1) ~ /^$|^Device [[:xdigit:]]+$/ ? $4 : $(NF-1)) + } + END { for (i in a) { + if (!seen[a[i]]++) { + sub("^[^ ]+ ", "", a[i]); + print a[i] + } + }}' + )gpu_script"; + + FILE* f = popen(gpu_script.c_str(), "r"); + if (f) + { + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), f)) + { + std::string card(buffer); + std::string version = "Unknown\n"; + if (card.find("NVIDIA") != std::string::npos) + { + // Assumes that all NVIDIA cards use the same driver + FILE* fnsmi = popen("nvidia-smi --query-gpu=driver_version --format=csv,noheader", "r"); + if (fnsmi) + { + if (fgets(buffer, sizeof(buffer), fnsmi)) + { + version = std::string(buffer); + } + pclose(fnsmi); + } + } + else + { + // Assuming non-NVIDIA cards are using the mesa driver + FILE* fglxinfo = popen("glxinfo | sed -n 's/OpenGL version string:/OGL/p'", "r"); + if (fglxinfo) + { + if (fgets(buffer, sizeof(buffer), fglxinfo)) + { + version = std::string(buffer); + + // This path is taken if the card was Intel or AMD + // If glxinfo is reporting NVIDIA, then it's likely that this is a multi-gpu system + // and that this version doesn't apply to this AMD / Intel device + // Alternatively we could use vulkaninfo, which allows us to select the device + // But I was unable to get that to work on my system + // So for now, we cannot get the iGPU version on NVIDIA dGPU systems + if (version.find("NVIDIA") != std::string::npos) + { + version = "Unknown (OpenGL default is NVIDIA)\n"; + } + } + pclose(fglxinfo); + } + } + Console.WriteLnFmt( + " GPU = {}" + " Driver Version = {}", + card, version); + } + pclose(f); + } +#endif +} +#endif + void VMManager::LogCPUCapabilities() { Console.WriteLn(Color_StrongGreen, "PCSX2 " GIT_REV); @@ -2254,7 +2402,9 @@ void VMManager::LogCPUCapabilities() Console.WriteLnFmt(" Processor = {}", cpuinfo_get_package(0)->name); Console.WriteLnFmt(" Core Count = {} cores", cpuinfo_get_cores_count()); Console.WriteLnFmt(" Thread Count = {} threads", cpuinfo_get_processors_count()); - Console.WriteLn(); +#ifdef _WIN32 + LogUserPowerPlan(); +#endif std::string features; if (cpuinfo_has_x86_avx()) @@ -2267,6 +2417,10 @@ void VMManager::LogCPUCapabilities() Console.WriteLn(Color_StrongBlack, "x86 Features Detected:"); Console.WriteLnFmt(" {}", features); Console.WriteLn(); + +#if defined(__linux__) || defined(_WIN32) + LogGPUCapabilities(); +#endif }