diff --git a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp index 979b77c3..7bd4c2db 100644 --- a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp +++ b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp @@ -12,30 +12,16 @@ #include "imgui/imgui_extension.h" #include "input/InputManager.h" +#include "util/ProcessorTime/ProcessorTime.h" #include -#if BOOST_OS_WINDOWS -#include -#include -#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 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 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); diff --git a/src/util/ProcessorTime/ProcessorTime.cpp b/src/util/ProcessorTime/ProcessorTime.cpp new file mode 100644 index 00000000..b185fc81 --- /dev/null +++ b/src/util/ProcessorTime/ProcessorTime.cpp @@ -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; +} \ No newline at end of file diff --git a/src/util/ProcessorTime/ProcessorTime.h b/src/util/ProcessorTime/ProcessorTime.h new file mode 100644 index 00000000..35f75b7b --- /dev/null +++ b/src/util/ProcessorTime/ProcessorTime.h @@ -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[]); \ No newline at end of file diff --git a/src/util/ProcessorTime/ProcessorTimeUnix.cpp b/src/util/ProcessorTime/ProcessorTimeUnix.cpp new file mode 100644 index 00000000..f733532d --- /dev/null +++ b/src/util/ProcessorTime/ProcessorTimeUnix.cpp @@ -0,0 +1,44 @@ +#if BOOST_OS_LINUX + +#include "util/ProcessorTime/ProcessorTime.h" + +#include +#include +#include +#include + +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(clock_now); + out_user = static_cast(clock_user); + out_kernel = static_cast(clock_kernel); +} + +void QueryCoreTimes(uint32_t count, ProcessorTime out[]) +{ + std::ifstream file("/proc/stat"); + file.ignore(std::numeric_limits::max(), '\n'); + + for (auto i = 0; i < count; ++i) + { + uint64_t user, nice, kernel, idle; + file.ignore(std::numeric_limits::max(), ' '); + file >> user >> nice >> kernel >> idle; + file.ignore(std::numeric_limits::max(), '\n'); + + out[i].idle = idle; + out[i].kernel = kernel; + out[i].user = user + nice; + } +} + +#endif \ No newline at end of file diff --git a/src/util/ProcessorTime/ProcessorTimeWin.cpp b/src/util/ProcessorTime/ProcessorTimeWin.cpp new file mode 100644 index 00000000..383d00d0 --- /dev/null +++ b/src/util/ProcessorTime/ProcessorTimeWin.cpp @@ -0,0 +1,50 @@ +#if BOOST_OS_WINDOWS + +#include "util/ProcessorTime/ProcessorTime.h" + +#include +#include +#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(now.QuadPart); + out_user = static_cast(user.QuadPart); + out_kernel = static_cast(kernel.QuadPart); +} + +void QueryCoreTimes(uint32_t count, ProcessorTime out[]) +{ + std::vector 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 \ No newline at end of file