mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-02-04 02:51:18 +01:00
this basically allows the threads to exist in these logical CPUs, undisturbed, and without trashing each other's cache this could improve performance, very tricky thing to pull off correctly, but again, this is mostly an experiment will mainly benefit: Linux, Android, FreeBSD, Windows (not ARM) Additionally, this means no context trashing :) Signed-off-by: lizzie <lizzie@eden-emu.dev> Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3121 Reviewed-by: DraVee <dravee@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev> Co-authored-by: lizzie <lizzie@eden-emu.dev> Co-committed-by: lizzie <lizzie@eden-emu.dev>
113 lines
2.9 KiB
C++
113 lines
2.9 KiB
C++
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
|
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <cstddef>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include "common/common_types.h"
|
|
#include "common/polyfill_thread.h"
|
|
|
|
namespace Common {
|
|
|
|
class Event {
|
|
public:
|
|
void Set() {
|
|
std::scoped_lock lk{mutex};
|
|
if (!is_set) {
|
|
is_set = true;
|
|
condvar.notify_one();
|
|
}
|
|
}
|
|
|
|
void Wait() {
|
|
std::unique_lock lk{mutex};
|
|
condvar.wait(lk, [&] { return is_set.load(); });
|
|
is_set = false;
|
|
}
|
|
|
|
bool WaitFor(const std::chrono::nanoseconds& time) {
|
|
std::unique_lock lk{mutex};
|
|
if (!condvar.wait_for(lk, time, [this] { return is_set.load(); }))
|
|
return false;
|
|
is_set = false;
|
|
return true;
|
|
}
|
|
|
|
template <class Clock, class Duration>
|
|
bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
|
|
std::unique_lock lk{mutex};
|
|
if (!condvar.wait_until(lk, time, [this] { return is_set.load(); }))
|
|
return false;
|
|
is_set = false;
|
|
return true;
|
|
}
|
|
|
|
void Reset() {
|
|
std::unique_lock lk{mutex};
|
|
// no other action required, since wait loops on the predicate and any lingering signal will
|
|
// get cleared on the first iteration
|
|
is_set = false;
|
|
}
|
|
|
|
[[nodiscard]] bool IsSet() const {
|
|
return is_set;
|
|
}
|
|
|
|
private:
|
|
std::condition_variable condvar;
|
|
std::mutex mutex;
|
|
std::atomic_bool is_set{false};
|
|
};
|
|
|
|
class Barrier {
|
|
public:
|
|
explicit Barrier(std::size_t count_) : count(count_) {}
|
|
|
|
/// Blocks until all "count" threads have called Sync()
|
|
bool Sync(std::stop_token token = {}) {
|
|
std::unique_lock lk{mutex};
|
|
const std::size_t current_generation = generation;
|
|
|
|
if (++waiting == count) {
|
|
generation++;
|
|
waiting = 0;
|
|
condvar.notify_all();
|
|
return true;
|
|
} else {
|
|
condvar.wait(lk, token,
|
|
[this, current_generation] { return current_generation != generation; });
|
|
return !token.stop_requested();
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::condition_variable_any condvar;
|
|
std::mutex mutex;
|
|
std::size_t count;
|
|
std::size_t waiting = 0;
|
|
std::size_t generation = 0; // Incremented once each time the barrier is used
|
|
};
|
|
|
|
enum class ThreadPriority : u32 {
|
|
Low = 0,
|
|
Normal = 1,
|
|
High = 2,
|
|
VeryHigh = 3,
|
|
Critical = 4,
|
|
};
|
|
|
|
void SetCurrentThreadPriority(ThreadPriority new_priority);
|
|
void SetCurrentThreadName(const char* name);
|
|
void PinCurrentThreadToPerformanceCore(size_t core_id);
|
|
|
|
} // namespace Common
|