Skip to content

Commit

Permalink
VMManager: Log power profile and GPUs on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
F0bes committed Feb 17, 2024
1 parent 689a512 commit 92cd4b7
Showing 1 changed file with 155 additions and 0 deletions.
155 changes: 155 additions & 0 deletions pcsx2/VMManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
#include "common/RedtapeWindows.h"
#include <objbase.h>
#include <timeapi.h>
#include <powrprof.h>
#include <wil/com.h>
#include <dxgi.h>
#endif

#ifdef __APPLE__
Expand Down Expand Up @@ -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<GUID*, decltype(&::LocalFree), ::LocalFree> 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 | grep \"OpenGL version string\"", "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);
Expand All @@ -2254,6 +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());
#ifdef _WIN32
LogUserPowerPlan();
#endif
Console.WriteLn();

std::string features;
Expand All @@ -2267,6 +2418,10 @@ void VMManager::LogCPUCapabilities()
Console.WriteLn(Color_StrongBlack, "x86 Features Detected:");
Console.WriteLnFmt(" {}", features);
Console.WriteLn();

#if defined(__linux__) || defined(_WIN32)
LogGPUCapabilities();
#endif
}


Expand Down

0 comments on commit 92cd4b7

Please sign in to comment.