Added SystemInfo. Improved overlay on Linux.

This commit is contained in:
Tom Lally 2022-09-01 22:48:58 +01:00
parent d3a7b3b5a6
commit b8f9374b90
5 changed files with 192 additions and 77 deletions

View file

@ -12,30 +12,16 @@
#include "imgui/imgui_extension.h" #include "imgui/imgui_extension.h"
#include "input/InputManager.h" #include "input/InputManager.h"
#include "util/SystemInfo/SystemInfo.h"
#include <cinttypes> #include <cinttypes>
#if BOOST_OS_WINDOWS
#include <Psapi.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")
#endif
struct OverlayStats struct OverlayStats
{ {
OverlayStats() {}; OverlayStats() {};
int processor_count = 1; int processor_count = 1;
ProcessorTime processor_time_cemu;
// cemu cpu stats
uint64_t last_cpu{}, kernel{}, user{};
// global cpu stats
struct ProcessorTime
{
uint64_t idle{}, kernel{}, user{};
};
std::vector<ProcessorTime> processor_times; std::vector<ProcessorTime> processor_times;
double fps{}; double fps{};
@ -565,19 +551,38 @@ void LatteOverlay_render(bool pad_view)
} }
} }
void LatteOverlay_init() void LatteOverlay_init()
{ {
#if BOOST_OS_WINDOWS g_state.processor_count = GetProcessorCount();
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
g_state.processor_count = sys_info.dwNumberOfProcessors;
g_state.processor_times.resize(g_state.processor_count); g_state.processor_times.resize(g_state.processor_count);
g_state.cpu_per_core.resize(g_state.processor_count); g_state.cpu_per_core.resize(g_state.processor_count);
#else }
g_state.processor_count = 1;
#endif static void UpdateStats_CemuCpu()
{
ProcessorTime now;
QueryProcTime(now);
double cpu = ProcessorTime::Compare(g_state.processor_time_cemu, now);
cpu /= g_state.processor_count;
g_state.cpu_usage = cpu * 100;
g_state.processor_time_cemu = now;
}
static void UpdateStats_CpuPerCore()
{
std::vector<ProcessorTime> now(g_state.processor_count);
QueryCoreTimes(g_state.processor_count, now.data());
for (int32_t i = 0; i < g_state.processor_count; ++i)
{
double cpu = ProcessorTime::Compare(g_state.processor_times[i], now[i]);
g_state.cpu_per_core[i] = cpu * 100;
g_state.processor_times[i] = now[i];
}
} }
void LatteOverlay_updateStats(double fps, sint32 drawcalls) void LatteOverlay_updateStats(double fps, sint32 drawcalls)
@ -587,61 +592,11 @@ void LatteOverlay_updateStats(double fps, sint32 drawcalls)
g_state.fps = fps; g_state.fps = fps;
g_state.draw_calls_per_frame = drawcalls; g_state.draw_calls_per_frame = drawcalls;
UpdateStats_CemuCpu();
#if BOOST_OS_WINDOWS UpdateStats_CpuPerCore();
// update cemu cpu
FILETIME ftime, fkernel, fuser;
LARGE_INTEGER now, kernel, user;
GetSystemTimeAsFileTime(&ftime);
now.LowPart = ftime.dwLowDateTime;
now.HighPart = ftime.dwHighDateTime;
GetProcessTimes(GetCurrentProcess(), &ftime, &ftime, &fkernel, &fuser);
kernel.LowPart = fkernel.dwLowDateTime;
kernel.HighPart = fkernel.dwHighDateTime;
user.LowPart = fuser.dwLowDateTime;
user.HighPart = fuser.dwHighDateTime;
double percent = (kernel.QuadPart - g_state.kernel) + (user.QuadPart - g_state.user);
percent /= (now.QuadPart - g_state.last_cpu);
percent /= g_state.processor_count;
g_state.cpu_usage = percent * 100;
g_state.last_cpu = now.QuadPart;
g_state.user = user.QuadPart;
g_state.kernel = kernel.QuadPart;
// update cpu per core
std::vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> sppi(g_state.processor_count);
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi.data(), sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * g_state.processor_count, nullptr)))
{
for (sint32 i = 0; i < g_state.processor_count; ++i)
{
const uint64 kernel_diff = sppi[i].KernelTime.QuadPart - g_state.processor_times[i].kernel;
const uint64 user_diff = sppi[i].UserTime.QuadPart - g_state.processor_times[i].user;
const uint64 idle_diff = sppi[i].IdleTime.QuadPart - g_state.processor_times[i].idle;
const auto total = kernel_diff + user_diff; // kernel time already includes idletime
const double cpu = total == 0 ? 0 : (1.0 - ((double)idle_diff / total)) * 100.0;
g_state.cpu_per_core[i] = cpu;
//total_cpu += cpu;
g_state.processor_times[i].idle = sppi[i].IdleTime.QuadPart;
g_state.processor_times[i].kernel = sppi[i].KernelTime.QuadPart;
g_state.processor_times[i].user = sppi[i].UserTime.QuadPart;
}
//total_cpu /= g_state.processor_count;
//g_state.cpu_usage = total_cpu;
}
// update ram // update ram
PROCESS_MEMORY_COUNTERS pmc{}; g_state.ram_usage = (QueryRamUsage() / 1000) / 1000;
pmc.cb = sizeof(pmc);
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
g_state.ram_usage = (pmc.WorkingSetSize / 1000) / 1000;
#endif
// update vram // update vram
g_renderer->GetVRAMInfo(g_state.vramUsage, g_state.vramTotal); g_renderer->GetVRAMInfo(g_state.vramUsage, g_state.vramTotal);

View file

@ -0,0 +1,29 @@
#include "util/SystemInfo/SystemInfo.h"
uint64 ProcessorTime::work()
{
return user + kernel;
}
uint64 ProcessorTime::total()
{
return idle + user + kernel;
}
double ProcessorTime::Compare(ProcessorTime &last, ProcessorTime &now)
{
auto dwork = now.work() - last.work();
auto dtotal = now.total() - last.total();
return (double)dwork / dtotal;
}
void QueryProcTime(ProcessorTime &out)
{
uint64 now, user, kernel;
QueryProcTime(now, user, kernel);
out.idle = now - (user + kernel);
out.kernel = kernel;
out.user = user;
}

View file

@ -0,0 +1,17 @@
#pragma once
struct ProcessorTime
{
uint64 idle{}, kernel{}, user{};
uint64 work();
uint64 total();
static double Compare(ProcessorTime &last, ProcessorTime &now);
};
uint32 GetProcessorCount();
uint64 QueryRamUsage();
void QueryProcTime(uint64 &out_now, uint64 &out_user, uint64 &out_kernel);
void QueryProcTime(ProcessorTime &out);
void QueryCoreTimes(uint32 count, ProcessorTime out[]);

View file

@ -0,0 +1,56 @@
#if BOOST_OS_LINUX
#include "util/SystemInfo/SystemInfo.h"
#include <unistd.h>
#include <sys/times.h>
#include <string>
uint32 GetProcessorCount()
{
return std::thread::hardware_concurrency();
}
uint64 QueryRamUsage()
{
long page_size = sysconf(_SC_PAGESIZE);
std::ifstream file("/proc/self/statm");
file.ignore(std::numeric_limits<std::streamsize>::max(), ' ');
uint64 no_pages;
file >> no_pages;
return no_pages * page_size;
}
void QueryProcTime(uint64 &out_now, uint64 &out_user, uint64 &out_kernel)
{
struct tms time_info;
clock_t clock_now = times(&time_info);
clock_t clock_user = time_info.tms_utime;
clock_t clock_kernel = time_info.tms_stime;
out_now = static_cast<uint64>(clock_now);
out_user = static_cast<uint64>(clock_user);
out_kernel = static_cast<uint64>(clock_kernel);
}
void QueryCoreTimes(uint32 count, ProcessorTime out[])
{
std::ifstream file("/proc/stat");
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
for (auto i = 0; i < count; ++i)
{
uint64 user, nice, kernel, idle;
file.ignore(std::numeric_limits<std::streamsize>::max(), ' ');
file >> user >> nice >> kernel >> idle;
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
out[i].idle = idle;
out[i].kernel = kernel;
out[i].user = user + nice;
}
}
#endif

View file

@ -0,0 +1,58 @@
#if BOOST_OS_WINDOWS
#include "util/SystemInfo/SystemInfo.h"
#include <Psapi.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")
uint32 GetProcessorCount()
{
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
return sys_info.dwNumberOfProcessors;
}
uint64 QueryRamUsage()
{
PROCESS_MEMORY_COUNTERS pmc{};
pmc.cb = sizeof(pmc);
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
return pmc.WorkingSetSize;
}
void QueryProcTime(uint64 &out_now, uint64 &out_user, uint64 &out_kernel)
{
FILETIME ftime, fkernel, fuser;
LARGE_INTEGER now, kernel, user;
GetSystemTimeAsFileTime(&ftime);
now.LowPart = ftime.dwLowDateTime;
now.HighPart = ftime.dwHighDateTime;
GetProcessTimes(GetCurrentProcess(), &ftime, &ftime, &fkernel, &fuser);
kernel.LowPart = fkernel.dwLowDateTime;
kernel.HighPart = fkernel.dwHighDateTime;
user.LowPart = fuser.dwLowDateTime;
user.HighPart = fuser.dwHighDateTime;
out_now = now.QuadPart;
out_user = user.QuadPart;
out_kernel = kernel.QuadPart;
}
void QueryCoreTimes(uint32 count, ProcessorTime out[])
{
std::vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> sppi(count);
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi.data(), sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * count, nullptr)))
{
for (auto i = 0; i < count; ++i)
{
out[i].idle = sppi[i].IdleTime.QuadPart;
out[i].kernel = sppi[i].KernelTime.QuadPart;
out[i].user = sppi[i].UserTime.QuadPart;
}
}
}
#endif