Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Savestates/sys_fs: Fix incredibly large savestates and improve saving performance #12560

Merged
merged 3 commits into from Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion Utilities/Thread.h
Expand Up @@ -635,13 +635,21 @@ class named_thread final : public Context, result_storage<Context>, thread_base
// Join thread by thread_state::finished
named_thread& operator=(thread_state s)
{
bool notify_sync = false;

if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second)
{
notify_sync = true;
}

if constexpr (std::is_assignable_v<Context&, thread_state>)
{
static_cast<Context&>(*this) = s;
}

if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second)
if (notify_sync)
{
// Notify after context abortion has been made so all conditions for wake-up be satisfied by the time of notification
thread::m_sync.notify_one(1);
}

Expand Down
15 changes: 13 additions & 2 deletions rpcs3/Emu/CPU/CPUThread.cpp
Expand Up @@ -881,8 +881,19 @@ void cpu_thread::notify()

cpu_thread& cpu_thread::operator=(thread_state)
{
state += cpu_flag::exit;
state.notify_one(cpu_flag::exit);
if (state & cpu_flag::exit)
{
// Must be notified elsewhere or self-raised
return *this;
}

const auto old = state.fetch_add(cpu_flag::exit);

if (old & cpu_flag::wait && old.none_of(cpu_flag::again + cpu_flag::exit))
{
state.notify_one(cpu_flag::exit);
}

return *this;
}

Expand Down
23 changes: 21 additions & 2 deletions rpcs3/Emu/Cell/SPURecompiler.cpp
Expand Up @@ -12,6 +12,7 @@
#include "Utilities/StrUtil.h"
#include "Utilities/JIT.h"
#include "util/init_mutex.hpp"
#include "util/shared_ptr.hpp"

#include "SPUThread.h"
#include "SPUAnalyser.h"
Expand Down Expand Up @@ -10647,6 +10648,7 @@ struct spu_llvm
{
// Workload
lf_queue<std::pair<const u64, spu_item*>> registered;
atomic_ptr<named_thread_group<spu_llvm_worker>> m_workers;

spu_llvm()
{
Expand Down Expand Up @@ -10716,7 +10718,9 @@ struct spu_llvm

u32 worker_index = 0;

named_thread_group<spu_llvm_worker> workers("SPUW.", worker_count);
m_workers = make_single<named_thread_group<spu_llvm_worker>>("SPUW.", worker_count);
auto workers_ptr = m_workers.load();
auto& workers = *workers_ptr;

while (thread_ctrl::state() != thread_state::aborting)
{
Expand Down Expand Up @@ -10769,12 +10773,27 @@ struct spu_llvm

static_cast<void>(prof_mutex.init_always([&]{ samples.clear(); }));

m_workers.reset();

for (u32 i = 0; i < worker_count; i++)
{
(workers.begin() + i)->registered.push(0, nullptr);
(workers.begin() + i)->operator=(thread_state::aborting);
}
}

spu_llvm& operator=(thread_state)
{
if (const auto workers = m_workers.load())
{
for (u32 i = 0; i < workers->size(); i++)
{
(workers->begin() + i)->operator=(thread_state::aborting);
}
}

return *this;
}

static constexpr auto thread_name = "SPU LLVM"sv;
};

Expand Down
26 changes: 23 additions & 3 deletions rpcs3/Emu/Cell/lv2/sys_fs.cpp
Expand Up @@ -313,7 +313,7 @@ void lv2_file::save(utils::serial& ar)
}

// UNIX allows deletion of files while descriptors are still opened
// descriptpors shall keep the data in memory in this case
// descriptors shall keep the data in memory in this case
const bool in_mem = [&]()
{
if (mp->flags & lv2_mp_flag::read_only)
Expand All @@ -323,11 +323,31 @@ void lv2_file::save(utils::serial& ar)

fs::file test{real_path};

if (!test) return true;
if (!test)
{
if (fs::is_file(real_path + ".66600"))
{
// May be a split-files descriptor, don't even bother
return false;
}

return true;
}

return test.stat() != file.stat();
fs::stat_t test_s = test.stat();
fs::stat_t file_s = file.stat();

// They don't matter for comparison and only create problems with encrypted files
test_s.is_writable = file_s.is_writable;
test_s.size = file_s.size;
return test_s != file_s;
}();

if (in_mem)
{
sys_fs.error("Saving \'%s\' LV2 file descriptor in memory! (exists=%s, type=%s, flags=0x%x)", name.data(), fs::is_file(real_path), type, flags);
}

ar(in_mem);

if (in_mem)
Expand Down