RPCS3: Notify RAM shortage, Log current and peak RAM usage

This commit is contained in:
Elad
2026-01-24 22:39:51 +02:00
parent 2702417192
commit a4523651c7
7 changed files with 70 additions and 45 deletions
+10
View File
@@ -2879,6 +2879,16 @@ void thread_base::exec()
} }
} }
if (auto [total, current] = utils::get_memory_usage(); total - current <= 256 * 1024 * 1024)
{
if (reason_buf.empty())
{
reason_buf = std::string{reason};
}
fmt::append(reason_buf, " (Possible RAM deficiency: free RAM: %dMB)", (total - current) / (1024 * 1024));
}
if (!reason_buf.empty()) if (!reason_buf.empty())
{ {
reason = reason_buf; reason = reason_buf;
+1 -1
View File
@@ -8615,7 +8615,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
// Blocks starting from 0x0 or invalid instruction won't be compiled, may need special interpreter fallback // Blocks starting from 0x0 or invalid instruction won't be compiled, may need special interpreter fallback
} }
if (!m_patterns.empty()) if (!m_patterns.empty() && g_cfg.core.spu_debug)
{ {
std::string out_dump; std::string out_dump;
dump(result, out_dump); dump(result, out_dump);
+12 -34
View File
@@ -900,10 +900,8 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3
switch (auto error = fs::g_tls_error) switch (auto error = fs::g_tls_error)
{ {
case fs::error::noent: return {CELL_ENOENT}; case fs::error::noent: return {CELL_ENOENT};
default: sys_fs.error("lv2_file::open(): unknown error %s", error); break; default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO};
} }
if (flags & CELL_FS_O_MSELF && !verify_mself(file)) if (flags & CELL_FS_O_MSELF && !verify_mself(file))
@@ -1374,8 +1372,7 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
} }
default: default:
{ {
sys_fs.error("sys_fs_opendir(): unknown error %s", error); fmt::throw_exception("unknown error %s", error);
return {CELL_EIO, path};
} }
} }
} }
@@ -1597,8 +1594,7 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
} }
default: default:
{ {
sys_fs.error("sys_fs_stat(): unknown error %s", error); fmt::throw_exception("unknown error %s", error);
return {CELL_EIO, path};
} }
} }
} }
@@ -1732,10 +1728,8 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
{ {
return {sys_fs.warning, CELL_EEXIST, path}; return {sys_fs.warning, CELL_EEXIST, path};
} }
default: sys_fs.error("sys_fs_mkdir(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO, path}; // ???
} }
sys_fs.notice("sys_fs_mkdir(): directory %s created", path); sys_fs.notice("sys_fs_mkdir(): directory %s created", path);
@@ -1797,10 +1791,8 @@ error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to
{ {
case fs::error::noent: return {CELL_ENOENT, from}; case fs::error::noent: return {CELL_ENOENT, from};
case fs::error::exist: return {CELL_EEXIST, to}; case fs::error::exist: return {CELL_EEXIST, to};
default: sys_fs.error("sys_fs_rename(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO, from}; // ???
} }
sys_fs.notice("sys_fs_rename(): %s renamed to %s", from, to); sys_fs.notice("sys_fs_rename(): %s renamed to %s", from, to);
@@ -1852,10 +1844,8 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
{ {
case fs::error::noent: return {CELL_ENOENT, path}; case fs::error::noent: return {CELL_ENOENT, path};
case fs::error::notempty: return {CELL_ENOTEMPTY, path}; case fs::error::notempty: return {CELL_ENOTEMPTY, path};
default: sys_fs.error("sys_fs_rmdir(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO, path}; // ???
} }
sys_fs.notice("sys_fs_rmdir(): directory %s removed", path); sys_fs.notice("sys_fs_rmdir(): directory %s removed", path);
@@ -1910,10 +1900,8 @@ error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr<char> path)
{ {
return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path};
} }
default: sys_fs.error("sys_fs_unlink(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO, path}; // ???
} }
sys_fs.notice("sys_fs_unlink(): file %s deleted", path); sys_fs.notice("sys_fs_unlink(): file %s deleted", path);
@@ -2632,10 +2620,8 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
switch (auto error = fs::g_tls_error) switch (auto error = fs::g_tls_error)
{ {
case fs::error::inval: return {CELL_EINVAL, "fd=%u, offset=0x%x, whence=%d", fd, offset, whence}; case fs::error::inval: return {CELL_EINVAL, "fd=%u, offset=0x%x, whence=%d", fd, offset, whence};
default: sys_fs.error("sys_fs_lseek(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return CELL_EIO; // ???
} }
lock.unlock(); lock.unlock();
@@ -2751,10 +2737,8 @@ error_code sys_fs_get_block_size(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u
{ {
case fs::error::exist: return {CELL_EISDIR, path}; case fs::error::exist: return {CELL_EISDIR, path};
case fs::error::noent: return {CELL_ENOENT, path}; case fs::error::noent: return {CELL_ENOENT, path};
default: sys_fs.error("sys_fs_get_block_size(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO, path}; // ???
} }
static_cast<void>(ppu.test_stopped()); static_cast<void>(ppu.test_stopped());
@@ -2809,10 +2793,8 @@ error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size)
{ {
return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path};
} }
default: sys_fs.error("sys_fs_truncate(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO, path}; // ???
} }
return CELL_OK; return CELL_OK;
@@ -2858,10 +2840,8 @@ error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size)
switch (auto error = fs::g_tls_error) switch (auto error = fs::g_tls_error)
{ {
case fs::error::ok: case fs::error::ok:
default: sys_fs.error("sys_fs_ftruncate(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return CELL_EIO; // ???
} }
return CELL_OK; return CELL_OK;
@@ -3057,10 +3037,8 @@ error_code sys_fs_utime(ppu_thread& ppu, vm::cptr<char> path, vm::cptr<CellFsUti
{ {
return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path};
} }
default: sys_fs.error("sys_fs_utime(): unknown error %s", error); default: fmt::throw_exception("unknown error %s", error);
} }
return {CELL_EIO, path}; // ???
} }
return CELL_OK; return CELL_OK;
+26 -9
View File
@@ -4,14 +4,18 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/timers.hpp" #include "Emu/Cell/timers.hpp"
#include "util/cpu_stats.hpp" #include "util/cpu_stats.hpp"
#include "util/sysinfo.hpp"
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
LOG_CHANNEL(perf_log, "PERF"); LOG_CHANNEL(perf_log, "PERF");
void perf_monitor::operator()() void perf_monitor::operator()()
{ {
constexpr u64 update_interval_us = 1000000; // Update every second constexpr u64 update_interval_us = 500000; // Update every half second
constexpr u64 log_interval_us = 10000000; // Log every 10 seconds 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
u64 elapsed_us = 0; u64 elapsed_us = 0;
utils::cpu_stats stats; utils::cpu_stats stats;
@@ -19,26 +23,28 @@ void perf_monitor::operator()()
u32 logged_pause = 0; u32 logged_pause = 0;
u64 last_pause_time = umax; u64 last_pause_time = umax;
u64 max_memory_usage = 0;
std::vector<double> per_core_usage; std::vector<double> per_core_usage;
std::string msg; std::string msg;
for (u64 sleep_until = get_system_time(); thread_ctrl::state() != thread_state::aborting;) for (u64 sleep_until = get_system_time();;)
{ {
thread_ctrl::wait_until(&sleep_until, update_interval_us); thread_ctrl::wait_until(&sleep_until, update_interval_us);
elapsed_us += update_interval_us; elapsed_us += update_interval_us;
if (thread_ctrl::state() == thread_state::aborting)
{
break;
}
double total_usage = 0.0; double total_usage = 0.0;
stats.get_per_core_usage(per_core_usage, total_usage); stats.get_per_core_usage(per_core_usage, total_usage);
if (elapsed_us >= log_interval_us) const u64 current_mem_use = utils::get_memory_usage().second;
const u64 mem_use_increase = current_mem_use >= max_memory_usage ? current_mem_use - max_memory_usage : 0;
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)
{ {
max_memory_usage = std::max<u64>(current_mem_use, max_memory_usage);
elapsed_us = 0; elapsed_us = 0;
const bool is_paused = Emu.IsPaused(); const bool is_paused = Emu.IsPaused();
@@ -76,7 +82,18 @@ void perf_monitor::operator()()
fmt::append(msg, "%s %.1f%%", i > 0 ? "," : "", per_core_usage[i]); fmt::append(msg, "%s %.1f%%", i > 0 ? "," : "", per_core_usage[i]);
} }
if (max_memory_usage)
{
fmt::append(msg, ", RAM Usage: %dMB (Peak: %dMB)", current_mem_use / (1024 * 1024), max_memory_usage / (1024 * 1024));
}
perf_log.notice("%s", msg); perf_log.notice("%s", msg);
if (thread_ctrl::state() == thread_state::aborting)
{
// Log once before terminating
break;
}
} }
} }
} }
+4
View File
@@ -197,6 +197,10 @@ std::set<std::string> get_one_drive_paths()
fmt::append(buf, "\nBuild: \"%s\"", rpcs3::get_verbose_version()); fmt::append(buf, "\nBuild: \"%s\"", rpcs3::get_verbose_version());
fmt::append(buf, "\nDate: \"%s\"", std::chrono::system_clock::now()); fmt::append(buf, "\nDate: \"%s\"", std::chrono::system_clock::now());
const auto [total, current] = utils::get_memory_usage();
fmt::append(buf, "\nRAM Usage: %dMB/%dMB (%dMB free)", current / (1024 * 1024), total / (1024 * 1024), (total - current) / (1024 * 1024));
} }
std::string_view text = s_is_error_launch ? _text : buf; std::string_view text = s_is_error_launch ? _text : buf;
+15 -1
View File
@@ -736,6 +736,20 @@ std::string utils::get_firmware_version()
return {}; return {};
} }
std::pair<u64, u64> utils::get_memory_usage()
{
#ifdef _WIN32
::MEMORYSTATUSEX status{};
status.dwLength = sizeof(status);
::GlobalMemoryStatusEx(&status);
return { status.ullTotalPhys, status.ullTotalPhys - status.ullAvailPhys };
#else
// TODO
return { get_total_memory(), 0 };
#endif
}
utils::OS_version utils::get_OS_version() utils::OS_version utils::get_OS_version()
{ {
OS_version res {}; OS_version res {};
@@ -1087,7 +1101,7 @@ static const bool s_tsc_freq_evaluated = []() -> bool
u64 utils::get_total_memory() u64 utils::get_total_memory()
{ {
#ifdef _WIN32 #ifdef _WIN32
::MEMORYSTATUSEX memInfo; ::MEMORYSTATUSEX memInfo{};
memInfo.dwLength = sizeof(memInfo); memInfo.dwLength = sizeof(memInfo);
::GlobalMemoryStatusEx(&memInfo); ::GlobalMemoryStatusEx(&memInfo);
return memInfo.ullTotalPhys; return memInfo.ullTotalPhys;
+2
View File
@@ -71,6 +71,8 @@ namespace utils
std::string get_firmware_version(); std::string get_firmware_version();
std::pair<u64, u64> get_memory_usage();
struct OS_version struct OS_version
{ {
std::string type; std::string type;