RPCS3: Notify RAM shortage, Log current and peak RAM usage
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user