diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 8288f5abff..00ded52e3f 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -3968,7 +3968,13 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector possible_exec_file_paths; - ::semaphore<2> ovl_sema; + // Allow to allocate 2000 times the size of each file for the use of LLVM + // This works very nicely with Metal Gear Solid 4 for example: + // 2 7MB overlay files -> 14GB + // The growth in memory requirements of LLVM is not linear with file size of course + // But these estimates should hopefully protect RPCS3 in the coming years + // Especially when thread count is on the rise with each CPU generation + atomic_t file_size_limit = static_cast(std::clamp(utils::aligned_div(utils::get_total_memory(), 2000), 65536, u32{umax})); const u32 software_thread_limit = std::min(g_cfg.core.llvm_threads ? g_cfg.core.llvm_threads : u32{umax}, ::size32(file_queue)); const u32 cpu_thread_limit = utils::get_thread_count() > 8u ? std::max(utils::get_thread_count(), 2) - 1 : utils::get_thread_count(); // One LLVM thread less @@ -3981,6 +3987,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector& dir_queue, std::vector& dir_queue, std::vector bool + { + // Try not to process too many files at once because it seems to reduce performance and cause RAM shortages + // Concurrently compiling more OVL or huge PRX files does not have much theoretical benefit + while (!file_size_limit.fetch_op([&](u32& value) + { + if (value) + { + // Allow at least one file, make 0 the "memory unavailable" sign value for atomic waiting efficiency + const u32 new_val = static_cast(utils::sub_saturate(value, file_size)); + restore_mem = value - new_val; + value = new_val; + return true; + } + + // Resort to waiting + restore_mem = 0; + return false; + }).second) + { + // Wait until not 0 + file_size_limit.wait(0); + } + + if (Emu.IsStopped()) + { + return false; + } + + return true; + }; + elf_error prx_err{}, ovl_err{}; if (ppu_prx_object obj = src; (prx_err = obj, obj == elf_error::ok)) { + if (!wait_for_memory()) + { + // Emulation stopped + continue; + } + if (auto prx = ppu_load_prx(obj, true, path, offset)) { obj.clear(), src.close(); // Clear decrypted file and elf object memory @@ -4040,10 +4095,6 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector& dir_queue, std::vectorget().sem); !ovlm->analyse(0, ovlm->entry, ovlm->seg0_code_end, ovlm->applied_patches, []() { @@ -4086,10 +4143,18 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector