diff options
author | Fernando Sahmkow <fsahmkow27@gmail.com> | 2020-02-25 03:04:12 +0100 |
---|---|---|
committer | Fernando Sahmkow <fsahmkow27@gmail.com> | 2020-06-27 17:35:06 +0200 |
commit | e31425df3877636c098ec7426ebd2067920715cb (patch) | |
tree | 5c0fc518a4ebb8413c491b43a9fdd99450c7bd80 /src/core/core_timing.h | |
parent | Merge pull request #3396 from FernandoS27/prometheus-1 (diff) | |
download | yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.gz yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.bz2 yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.lz yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.xz yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.zst yuzu-e31425df3877636c098ec7426ebd2067920715cb.zip |
Diffstat (limited to '')
-rw-r--r-- | src/core/core_timing.h | 108 |
1 files changed, 57 insertions, 51 deletions
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index d50f4eb8a..707c8ef0c 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -1,19 +1,25 @@ -// Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project -// Licensed under GPLv2+ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #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/spin_lock.h" +#include "common/thread.h" #include "common/threadsafe_queue.h" +#include "common/wall_clock.h" +#include "core/hardware_properties.h" namespace Core::Timing { @@ -56,58 +62,55 @@ public: /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is /// required to end slice - 1 and start slice 0 before the first cycle of code is executed. - void Initialize(); + void Initialize(std::function<void(void)>&& on_thread_init_); /// Tears down all timing related functionality. void Shutdown(); - /// After the first Advance, the slice lengths and the downcount will be reduced whenever an - /// event is scheduled earlier than the current values. - /// - /// Scheduling from a callback will not update the downcount until the Advance() completes. - void ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type, - u64 userdata = 0); + /// Pauses/Unpauses the execution of the timer thread. + void Pause(bool is_paused); - void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); + /// Pauses/Unpauses the execution of the timer thread and waits until paused. + void SyncPause(bool is_paused); - /// We only permit one event of each type in the queue at a time. - void RemoveEvent(const std::shared_ptr<EventType>& event_type); + /// Checks if core timing is running. + bool IsRunning() const; - void ForceExceptionCheck(s64 cycles); + /// Checks if the timer thread has started. + bool HasStarted() const { + return has_started; + } - /// This should only be called from the emu thread, if you are calling it any other thread, - /// you are doing something evil - u64 GetTicks() const; + /// Checks if there are any pending time events. + bool HasPendingEvents() const; - u64 GetIdleTicks() const; + /// Schedules an event in core timing + void ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type, + u64 userdata = 0); - void AddTicks(u64 ticks); + void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); - /// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends - /// the previous timing slice and begins the next one, you must Advance from the previous - /// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an - /// Advance() is required to initialize the slice length before the first cycle of emulated - /// instructions is executed. - void Advance(); + /// We only permit one event of each type in the queue at a time. + void RemoveEvent(const std::shared_ptr<EventType>& event_type); - /// Pretend that the main CPU has executed enough cycles to reach the next event. - void Idle(); + void AddTicks(std::size_t core_index, u64 ticks); - std::chrono::microseconds GetGlobalTimeUs() const; + void ResetTicks(std::size_t core_index); - void ResetRun(); + /// Returns current time in emulated CPU cycles + u64 GetCPUTicks() const; - s64 GetDowncount() const; + /// Returns current time in emulated in Clock cycles + u64 GetClockTicks() const; - void SwitchContext(u64 new_context) { - current_context = new_context; - } + /// Returns current time in microseconds. + std::chrono::microseconds GetGlobalTimeUs() const; - bool CanCurrentContextRun() const { - return time_slice[current_context] > 0; - } + /// Returns current time in nanoseconds. + std::chrono::nanoseconds GetGlobalTimeNs() const; - std::optional<u64> NextAvailableCore(const s64 needed_ticks) const; + /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. + std::optional<u64> Advance(); private: struct Event; @@ -115,21 +118,14 @@ private: /// Clear all pending events. This should ONLY be done on exit. void ClearPendingEvents(); - static constexpr u64 num_cpu_cores = 4; + static void ThreadEntry(CoreTiming& instance); + void ThreadLoop(); + + std::unique_ptr<Common::WallClock> clock; - s64 global_timer = 0; - s64 idled_cycles = 0; - s64 slice_length = 0; - u64 accumulated_ticks = 0; - std::array<s64, num_cpu_cores> downcounts{}; - // Slice of time assigned to each core per run. - std::array<s64, num_cpu_cores> time_slice{}; - u64 current_context = 0; + u64 global_timer = 0; - // Are we in a function that has been called from Advance() - // If events are scheduled from a function that gets called from Advance(), - // don't change slice_length and downcount. - bool is_global_timer_sane = false; + std::chrono::nanoseconds start_point; // The queue is a min-heap using std::make_heap/push_heap/pop_heap. // We don't use std::priority_queue because we need to be able to serialize, unserialize and @@ -139,8 +135,18 @@ private: u64 event_fifo_id = 0; std::shared_ptr<EventType> ev_lost; - - std::mutex inner_mutex; + Common::Event event{}; + Common::SpinLock basic_lock{}; + Common::SpinLock advance_lock{}; + std::unique_ptr<std::thread> 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(void)> on_thread_init{}; + + std::array<std::atomic<u64>, Core::Hardware::NUM_CPU_CORES> ticks_count{}; }; /// Creates a core timing event with the given name and callback. |