2022-03-11 21:08:44 +01:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "perf_monitor.hpp"
|
2023-09-18 10:29:34 +03:00
|
|
|
|
|
|
|
|
#include "Emu/System.h"
|
2025-02-11 03:00:37 +01:00
|
|
|
#include "Emu/Cell/timers.hpp"
|
2022-03-11 21:08:44 +01:00
|
|
|
#include "util/cpu_stats.hpp"
|
2026-01-24 22:39:51 +02:00
|
|
|
#include "util/sysinfo.hpp"
|
2022-03-11 21:08:44 +01:00
|
|
|
#include "Utilities/Thread.h"
|
|
|
|
|
|
2023-09-18 10:29:34 +03:00
|
|
|
LOG_CHANNEL(perf_log, "PERF");
|
2022-03-11 21:08:44 +01:00
|
|
|
|
|
|
|
|
void perf_monitor::operator()()
|
|
|
|
|
{
|
2026-01-24 22:39:51 +02:00
|
|
|
constexpr u64 update_interval_us = 500000; // Update every half second
|
|
|
|
|
constexpr u64 log_interval_us_max = 10000000; // Log at minimum every 10 seconds
|
|
|
|
|
constexpr u64 log_interval_us_min = 500000; // Log at maximum every half a second (catching possible memory leak)
|
|
|
|
|
constexpr u64 log_mem_increase = 50 * (1024 * 1024); // Log when memory usage increased by this amount
|
|
|
|
|
|
2022-03-11 21:08:44 +01:00
|
|
|
u64 elapsed_us = 0;
|
|
|
|
|
|
|
|
|
|
utils::cpu_stats stats;
|
|
|
|
|
stats.init_cpu_query();
|
|
|
|
|
|
2023-09-18 10:29:34 +03:00
|
|
|
u32 logged_pause = 0;
|
|
|
|
|
u64 last_pause_time = umax;
|
2026-01-24 22:39:51 +02:00
|
|
|
u64 max_memory_usage = 0;
|
2023-09-18 10:29:34 +03:00
|
|
|
|
|
|
|
|
std::vector<double> per_core_usage;
|
2024-08-16 20:06:20 +03:00
|
|
|
std::string msg;
|
2023-09-18 10:29:34 +03:00
|
|
|
|
2026-01-24 22:39:51 +02:00
|
|
|
for (u64 sleep_until = get_system_time();;)
|
2022-03-11 21:08:44 +01:00
|
|
|
{
|
2024-08-16 20:06:20 +03:00
|
|
|
thread_ctrl::wait_until(&sleep_until, update_interval_us);
|
2022-03-11 21:08:44 +01:00
|
|
|
elapsed_us += update_interval_us;
|
|
|
|
|
|
|
|
|
|
double total_usage = 0.0;
|
|
|
|
|
|
|
|
|
|
stats.get_per_core_usage(per_core_usage, total_usage);
|
|
|
|
|
|
2026-08-17 20:50:43 -04:00
|
|
|
// OUR resident set, not the machine's. This used to report
|
|
|
|
|
// utils::get_memory_usage().second -- MemTotal minus MemAvailable from /proc/meminfo,
|
|
|
|
|
// which counts every process on the device plus page cache -- under the label "RAM
|
|
|
|
|
// Usage", directly beside this emulator's own CPU figures. On a 7.4 GB phone it read
|
|
|
|
|
// ~5.6 GB while the emulator itself held ~3.3 GB, so three separate investigations into
|
|
|
|
|
// "the emulator is using 5.6 GB" were chasing the device's number. The process RSS is
|
|
|
|
|
// also the figure Android's low-memory killer actually decides on.
|
|
|
|
|
const u64 current_mem_use = utils::get_process_memory_usage();
|
2026-01-24 22:39:51 +02:00
|
|
|
const u64 mem_use_increase = current_mem_use >= max_memory_usage ? current_mem_use - max_memory_usage : 0;
|
|
|
|
|
|
2026-08-17 20:50:43 -04:00
|
|
|
const auto [system_total, system_used] = utils::get_memory_usage();
|
|
|
|
|
|
2026-01-24 22:39:51 +02:00
|
|
|
const u64 log_interval = (mem_use_increase >= log_mem_increase ? log_interval_us_min : log_interval_us_max);
|
|
|
|
|
|
|
|
|
|
if (elapsed_us >= log_interval || thread_ctrl::state() == thread_state::aborting)
|
2022-03-11 21:08:44 +01:00
|
|
|
{
|
2026-01-24 22:39:51 +02:00
|
|
|
max_memory_usage = std::max<u64>(current_mem_use, max_memory_usage);
|
2022-03-11 21:08:44 +01:00
|
|
|
elapsed_us = 0;
|
|
|
|
|
|
2023-09-18 10:29:34 +03:00
|
|
|
const bool is_paused = Emu.IsPaused();
|
|
|
|
|
const u64 pause_time = Emu.GetPauseTime();
|
|
|
|
|
|
|
|
|
|
if (!is_paused || last_pause_time != pause_time)
|
|
|
|
|
{
|
|
|
|
|
// Resumed or not paused since last check
|
|
|
|
|
logged_pause = 0;
|
|
|
|
|
last_pause_time = pause_time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_paused)
|
|
|
|
|
{
|
|
|
|
|
if (logged_pause >= 2)
|
|
|
|
|
{
|
|
|
|
|
// Let's not spam the log when emulation is paused
|
|
|
|
|
// But still emit the message two times so even paused state can be debugged and inspected
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logged_pause++;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 20:06:20 +03:00
|
|
|
msg.clear();
|
|
|
|
|
fmt::append(msg, "CPU Usage: Total: %.1f%%", total_usage);
|
2022-03-11 21:08:44 +01:00
|
|
|
|
|
|
|
|
if (!per_core_usage.empty())
|
|
|
|
|
{
|
|
|
|
|
fmt::append(msg, ", Cores:");
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 20:06:20 +03:00
|
|
|
for (usz i = 0; i < per_core_usage.size(); i++)
|
2022-03-11 21:08:44 +01:00
|
|
|
{
|
|
|
|
|
fmt::append(msg, "%s %.1f%%", i > 0 ? "," : "", per_core_usage[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 22:39:51 +02:00
|
|
|
if (max_memory_usage)
|
|
|
|
|
{
|
2026-08-17 20:50:43 -04:00
|
|
|
// Both numbers, each named for what it is. The headroom is what a report about
|
|
|
|
|
// being killed needs: our own total says nothing about how close the device is.
|
|
|
|
|
fmt::append(msg, ", Process RSS: %dMB (Peak: %dMB)",
|
|
|
|
|
current_mem_use / (1024 * 1024), max_memory_usage / (1024 * 1024));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (system_total)
|
|
|
|
|
{
|
|
|
|
|
fmt::append(msg, ", System: %dMB/%dMB used (%dMB free)",
|
|
|
|
|
system_used / (1024 * 1024), system_total / (1024 * 1024),
|
|
|
|
|
(system_total - system_used) / (1024 * 1024));
|
2026-01-24 22:39:51 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-18 10:29:34 +03:00
|
|
|
perf_log.notice("%s", msg);
|
2026-01-24 22:39:51 +02:00
|
|
|
|
|
|
|
|
if (thread_ctrl::state() == thread_state::aborting)
|
|
|
|
|
{
|
|
|
|
|
// Log once before terminating
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-11 21:08:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
perf_monitor::~perf_monitor()
|
|
|
|
|
{
|
|
|
|
|
}
|