diff --git a/Utilities/lockless.h b/Utilities/lockless.h index f49544ea3d..08c8cb2df5 100644 --- a/Utilities/lockless.h +++ b/Utilities/lockless.h @@ -379,8 +379,8 @@ public: return m_head != 0; } - template - void push(Args&&... args) + template + bool push(Args&&... args) { auto oldv = m_head.load(); auto item = new lf_queue_item(load(oldv), std::forward(args)...); @@ -390,9 +390,19 @@ public: item->m_link = load(oldv); } - if (!oldv) + if (!oldv && Notify) { // Notify only if queue was empty + notify(true); + } + + return !oldv; + } + + void notify(bool force = false) + { + if (force || operator bool()) + { utils::bless>(&m_head)[1].notify_one(); } } diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index 7b9cba2347..8bc19d7f7e 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -4570,11 +4570,15 @@ struct spu_llvm } u32 worker_index = 0; + u32 notify_compile_count = 0; + std::vector notify_compile(worker_count); m_workers = make_single>("SPUW.", worker_count); auto workers_ptr = m_workers.load(); auto& workers = *workers_ptr; + usz add_count = 65535; + while (thread_ctrl::state() != thread_state::aborting) { for (const auto& pair : registered.pop_all()) @@ -4590,9 +4594,24 @@ struct spu_llvm if (enqueued.empty()) { + // Send pending notifications + if (notify_compile_count) + { + for (usz i = 0; i < worker_count; i++) + { + if (notify_compile[i]) + { + (workers.begin() + (i % worker_count))->registered.notify(); + } + } + } + // Interrupt profiler thread and put it to sleep static_cast(prof_mutex.reset()); thread_ctrl::wait_on(utils::bless>(®istered)[1], 0); + add_count = 65535; // Reset count + std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags + notify_compile_count = 0; continue; } @@ -4620,8 +4639,34 @@ struct spu_llvm // Remove item from the queue enqueued.erase(found_it); + // Prefer using an inactive thread + for (usz i = 0; i < worker_count && !!(workers.begin() + (worker_index % worker_count))->registered; i++) + { + worker_index++; + } + // Push the workload - (workers.begin() + (worker_index++ % worker_count))->registered.push(reinterpret_cast(_old), &func); + const bool notify = (workers.begin() + (worker_index % worker_count))->registered.template push(reinterpret_cast(_old), &func); + + if (notify && !notify_compile[worker_index % worker_count]) + { + notify_compile[worker_index % worker_count] = 1; + notify_compile_count++; + + if (notify_compile_count == notify_compile.size()) + { + // Notify all + for (usz i = 0; i < worker_count; i++) + { + (workers.begin() + (i % worker_count))->registered.notify(); + } + + std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags + notify_compile_count = 0; + } + } + + worker_index++; } static_cast(prof_mutex.init_always([&]{ samples.clear(); }));