suyu/src/core/core_timing.h

129 lines
3.8 KiB
C++

// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <thread>
#include <vector>
#include "common/common_types.h"
#include "common/thread.h"
#include "common/wall_clock.h"
namespace Core::Timing {
/// A callback that may be scheduled for a particular core timing event.
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
s64 time, std::chrono::nanoseconds ns_late)>;
/// Contains the characteristics of a particular event.
struct EventType {
explicit EventType(TimedCallback&& callback_, std::string&& name_)
: callback{std::move(callback_)}, name{std::move(name_)}, sequence_number{0} {}
/// The event's callback function.
TimedCallback callback;
/// A pointer to the name of the event.
const std::string name;
/// A monotonic sequence number, incremented when this event is
/// changed externally.
size_t sequence_number;
};
enum class UnscheduleEventType {
Wait,
NoWait,
};
class CoreTiming {
public:
CoreTiming();
~CoreTiming();
CoreTiming(const CoreTiming&) = delete;
CoreTiming(CoreTiming&&) = delete;
CoreTiming& operator=(const CoreTiming&) = delete;
CoreTiming& operator=(CoreTiming&&) = delete;
void Initialize(std::function<void()>&& on_thread_init_);
void ClearPendingEvents();
void SetMulticore(bool is_multicore_) {
is_multicore = is_multicore_;
}
void Pause(bool is_paused);
void SyncPause(bool is_paused);
bool IsRunning() const;
bool HasStarted() const {
return has_started;
}
bool HasPendingEvents() const;
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type, bool absolute_time = false);
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
std::chrono::nanoseconds resched_time,
const std::shared_ptr<EventType>& event_type,
bool absolute_time = false);
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
UnscheduleEventType type = UnscheduleEventType::Wait);
void AddTicks(u64 ticks_to_add);
void ResetTicks();
void Idle();
s64 GetDowncount() const {
return downcount.load(std::memory_order_relaxed);
}
u64 GetClockTicks() const;
u64 GetGPUTicks() const;
std::chrono::microseconds GetGlobalTimeUs() const;
std::chrono::nanoseconds GetGlobalTimeNs() const;
std::optional<s64> Advance();
private:
struct Event {
s64 time;
u64 fifo_order;
std::shared_ptr<EventType> type;
bool operator>(const Event& other) const {
return std::tie(time, fifo_order) > std::tie(other.time, other.fifo_order);
}
};
static void ThreadEntry(CoreTiming& instance);
void ThreadLoop();
void Reset();
std::unique_ptr<Common::WallClock> clock;
std::atomic<s64> global_timer{0};
std::vector<Event> event_queue;
std::atomic<u64> event_fifo_id{0};
Common::Event event{};
Common::Event pause_event{};
mutable std::mutex basic_lock;
std::mutex advance_lock;
std::unique_ptr<std::jthread> timer_thread;
std::atomic<bool> paused{};
std::atomic<bool> paused_set{};
std::atomic<bool> wait_set{};
std::atomic<bool> shutting_down{};
std::atomic<bool> has_started{};
std::function<void()> on_thread_init{};
bool is_multicore{};
std::atomic<s64> pause_end_time{};
std::atomic<u64> cpu_ticks{};
std::atomic<s64> downcount{};
};
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback);
} // namespace Core::Timing