mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-04 14:01:17 +12:00
Added process cpu use and per-core global cpu use to linux overlay.
This commit is contained in:
parent
5f484b22d2
commit
2d30edcbc6
5 changed files with 181 additions and 79 deletions
|
@ -12,30 +12,16 @@
|
|||
#include "imgui/imgui_extension.h"
|
||||
|
||||
#include "input/InputManager.h"
|
||||
#include "util/ProcessorTime/ProcessorTime.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <Psapi.h>
|
||||
#include <winternl.h>
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
#endif
|
||||
|
||||
struct OverlayStats
|
||||
{
|
||||
OverlayStats() {};
|
||||
|
||||
int processor_count = 1;
|
||||
|
||||
// cemu cpu stats
|
||||
uint64_t last_cpu{}, kernel{}, user{};
|
||||
|
||||
// global cpu stats
|
||||
struct ProcessorTime
|
||||
{
|
||||
uint64_t idle{}, kernel{}, user{};
|
||||
};
|
||||
|
||||
ProcessorTime processor_time_cemu;
|
||||
std::vector<ProcessorTime> processor_times;
|
||||
|
||||
double fps{};
|
||||
|
@ -565,21 +551,50 @@ void LatteOverlay_render(bool pad_view)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void LatteOverlay_init()
|
||||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
SYSTEM_INFO sys_info;
|
||||
GetSystemInfo(&sys_info);
|
||||
g_state.processor_count = sys_info.dwNumberOfProcessors;
|
||||
#else
|
||||
g_state.processor_count = std::thread::hardware_concurrency();
|
||||
#endif
|
||||
g_state.processor_count = GetProcessorCount();
|
||||
|
||||
g_state.processor_times.resize(g_state.processor_count);
|
||||
g_state.cpu_per_core.resize(g_state.processor_count);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
ProcessorTime now[g_state.processor_count];
|
||||
QueryCoreTimes(g_state.processor_count, now);
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateStats_RamUsage()
|
||||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
PROCESS_MEMORY_COUNTERS pmc{};
|
||||
pmc.cb = sizeof(pmc);
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
|
||||
g_state.ram_usage = (pmc.WorkingSetSize / 1000) / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LatteOverlay_updateStats(double fps, sint32 drawcalls)
|
||||
{
|
||||
if (GetConfig().overlay.position == ScreenPosition::kDisabled)
|
||||
|
@ -587,61 +602,9 @@ void LatteOverlay_updateStats(double fps, sint32 drawcalls)
|
|||
|
||||
g_state.fps = fps;
|
||||
g_state.draw_calls_per_frame = drawcalls;
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
// 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
|
||||
PROCESS_MEMORY_COUNTERS pmc{};
|
||||
pmc.cb = sizeof(pmc);
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
|
||||
g_state.ram_usage = (pmc.WorkingSetSize / 1000) / 1000;
|
||||
#endif
|
||||
UpdateStats_CemuCpu();
|
||||
UpdateStats_CpuPerCore();
|
||||
UpdateStats_RamUsage();
|
||||
|
||||
// update vram
|
||||
g_renderer->GetVRAMInfo(g_state.vramUsage, g_state.vramTotal);
|
||||
|
|
29
src/util/ProcessorTime/ProcessorTime.cpp
Normal file
29
src/util/ProcessorTime/ProcessorTime.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include "util/ProcessorTime/ProcessorTime.h"
|
||||
|
||||
uint64_t ProcessorTime::work()
|
||||
{
|
||||
return user + kernel;
|
||||
}
|
||||
|
||||
uint64_t 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_t now, user, kernel;
|
||||
QueryProcTime(now, user, kernel);
|
||||
|
||||
out.idle = now - (user + kernel);
|
||||
out.kernel = kernel;
|
||||
out.user = user;
|
||||
}
|
16
src/util/ProcessorTime/ProcessorTime.h
Normal file
16
src/util/ProcessorTime/ProcessorTime.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
struct ProcessorTime
|
||||
{
|
||||
uint64_t idle{}, kernel{}, user{};
|
||||
|
||||
uint64_t work();
|
||||
uint64_t total();
|
||||
|
||||
static double Compare(ProcessorTime &last, ProcessorTime &now);
|
||||
};
|
||||
|
||||
uint32_t GetProcessorCount();
|
||||
void QueryProcTime(uint64_t &out_now, uint64_t &out_user, uint64_t &out_kernel);
|
||||
void QueryProcTime(ProcessorTime &out);
|
||||
void QueryCoreTimes(uint32_t count, ProcessorTime out[]);
|
44
src/util/ProcessorTime/ProcessorTimeUnix.cpp
Normal file
44
src/util/ProcessorTime/ProcessorTimeUnix.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#if BOOST_OS_LINUX
|
||||
|
||||
#include "util/ProcessorTime/ProcessorTime.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/resource.h>
|
||||
#include <string>
|
||||
|
||||
uint32_t GetProcessorCount()
|
||||
{
|
||||
return std::thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
void QueryProcTime(uint64_t &out_now, uint64_t &out_user, uint64_t &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_utime;
|
||||
out_now = static_cast<uint64_t>(clock_now);
|
||||
out_user = static_cast<uint64_t>(clock_user);
|
||||
out_kernel = static_cast<uint64_t>(clock_kernel);
|
||||
}
|
||||
|
||||
void QueryCoreTimes(uint32_t 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_t 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
|
50
src/util/ProcessorTime/ProcessorTimeWin.cpp
Normal file
50
src/util/ProcessorTime/ProcessorTimeWin.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#if BOOST_OS_WINDOWS
|
||||
|
||||
#include "util/ProcessorTime/ProcessorTime.h"
|
||||
|
||||
#include <Psapi.h>
|
||||
#include <winternl.h>
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
|
||||
uint32_t GetProcessorCount()
|
||||
{
|
||||
SYSTEM_INFO sys_info;
|
||||
GetSystemInfo(&sys_info);
|
||||
return sys_info.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
void QueryProcTime(uint64_t &out_now, uint64_t &out_user, uint64_t &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 = static_cast<uint64_t>(now.QuadPart);
|
||||
out_user = static_cast<uint64_t>(user.QuadPart);
|
||||
out_kernel = static_cast<uint64_t>(kernel.QuadPart);
|
||||
}
|
||||
|
||||
void QueryCoreTimes(uint32_t 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
|
Loading…
Add table
Add a link
Reference in a new issue