summaryrefslogtreecommitdiff
path: root/src/core/core_timing.h
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-24 22:04:12 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:35:06 -0400
commite31425df3877636c098ec7426ebd2067920715cb (patch)
tree5c0fc518a4ebb8413c491b43a9fdd99450c7bd80 /src/core/core_timing.h
parentMerge pull request #3396 from FernandoS27/prometheus-1 (diff)
downloadyuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.gz
yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.xz
yuzu-e31425df3877636c098ec7426ebd2067920715cb.zip
General: Recover Prometheus project from harddrive failure
This commit: Implements CPU Interrupts, Replaces Cycle Timing for Host Timing, Reworks the Kernel's Scheduler, Introduce Idle State and Suspended State, Recreates the bootmanager, Initializes Multicore system.
Diffstat (limited to 'src/core/core_timing.h')
-rw-r--r--src/core/core_timing.h108
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 @@
1// Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project 1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2+ 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
7#include <chrono> 8#include <chrono>
8#include <functional> 9#include <functional>
9#include <memory> 10#include <memory>
10#include <mutex> 11#include <mutex>
11#include <optional> 12#include <optional>
12#include <string> 13#include <string>
14#include <thread>
13#include <vector> 15#include <vector>
14 16
15#include "common/common_types.h" 17#include "common/common_types.h"
18#include "common/spin_lock.h"
19#include "common/thread.h"
16#include "common/threadsafe_queue.h" 20#include "common/threadsafe_queue.h"
21#include "common/wall_clock.h"
22#include "core/hardware_properties.h"
17 23
18namespace Core::Timing { 24namespace Core::Timing {
19 25
@@ -56,58 +62,55 @@ public:
56 62
57 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is 63 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
58 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed. 64 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
59 void Initialize(); 65 void Initialize(std::function<void(void)>&& on_thread_init_);
60 66
61 /// Tears down all timing related functionality. 67 /// Tears down all timing related functionality.
62 void Shutdown(); 68 void Shutdown();
63 69
64 /// After the first Advance, the slice lengths and the downcount will be reduced whenever an 70 /// Pauses/Unpauses the execution of the timer thread.
65 /// event is scheduled earlier than the current values. 71 void Pause(bool is_paused);
66 ///
67 /// Scheduling from a callback will not update the downcount until the Advance() completes.
68 void ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type,
69 u64 userdata = 0);
70 72
71 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); 73 /// Pauses/Unpauses the execution of the timer thread and waits until paused.
74 void SyncPause(bool is_paused);
72 75
73 /// We only permit one event of each type in the queue at a time. 76 /// Checks if core timing is running.
74 void RemoveEvent(const std::shared_ptr<EventType>& event_type); 77 bool IsRunning() const;
75 78
76 void ForceExceptionCheck(s64 cycles); 79 /// Checks if the timer thread has started.
80 bool HasStarted() const {
81 return has_started;
82 }
77 83
78 /// This should only be called from the emu thread, if you are calling it any other thread, 84 /// Checks if there are any pending time events.
79 /// you are doing something evil 85 bool HasPendingEvents() const;
80 u64 GetTicks() const;
81 86
82 u64 GetIdleTicks() const; 87 /// Schedules an event in core timing
88 void ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type,
89 u64 userdata = 0);
83 90
84 void AddTicks(u64 ticks); 91 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
85 92
86 /// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends 93 /// We only permit one event of each type in the queue at a time.
87 /// the previous timing slice and begins the next one, you must Advance from the previous 94 void RemoveEvent(const std::shared_ptr<EventType>& event_type);
88 /// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
89 /// Advance() is required to initialize the slice length before the first cycle of emulated
90 /// instructions is executed.
91 void Advance();
92 95
93 /// Pretend that the main CPU has executed enough cycles to reach the next event. 96 void AddTicks(std::size_t core_index, u64 ticks);
94 void Idle();
95 97
96 std::chrono::microseconds GetGlobalTimeUs() const; 98 void ResetTicks(std::size_t core_index);
97 99
98 void ResetRun(); 100 /// Returns current time in emulated CPU cycles
101 u64 GetCPUTicks() const;
99 102
100 s64 GetDowncount() const; 103 /// Returns current time in emulated in Clock cycles
104 u64 GetClockTicks() const;
101 105
102 void SwitchContext(u64 new_context) { 106 /// Returns current time in microseconds.
103 current_context = new_context; 107 std::chrono::microseconds GetGlobalTimeUs() const;
104 }
105 108
106 bool CanCurrentContextRun() const { 109 /// Returns current time in nanoseconds.
107 return time_slice[current_context] > 0; 110 std::chrono::nanoseconds GetGlobalTimeNs() const;
108 }
109 111
110 std::optional<u64> NextAvailableCore(const s64 needed_ticks) const; 112 /// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
113 std::optional<u64> Advance();
111 114
112private: 115private:
113 struct Event; 116 struct Event;
@@ -115,21 +118,14 @@ private:
115 /// Clear all pending events. This should ONLY be done on exit. 118 /// Clear all pending events. This should ONLY be done on exit.
116 void ClearPendingEvents(); 119 void ClearPendingEvents();
117 120
118 static constexpr u64 num_cpu_cores = 4; 121 static void ThreadEntry(CoreTiming& instance);
122 void ThreadLoop();
123
124 std::unique_ptr<Common::WallClock> clock;
119 125
120 s64 global_timer = 0; 126 u64 global_timer = 0;
121 s64 idled_cycles = 0;
122 s64 slice_length = 0;
123 u64 accumulated_ticks = 0;
124 std::array<s64, num_cpu_cores> downcounts{};
125 // Slice of time assigned to each core per run.
126 std::array<s64, num_cpu_cores> time_slice{};
127 u64 current_context = 0;
128 127
129 // Are we in a function that has been called from Advance() 128 std::chrono::nanoseconds start_point;
130 // If events are scheduled from a function that gets called from Advance(),
131 // don't change slice_length and downcount.
132 bool is_global_timer_sane = false;
133 129
134 // The queue is a min-heap using std::make_heap/push_heap/pop_heap. 130 // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
135 // We don't use std::priority_queue because we need to be able to serialize, unserialize and 131 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
@@ -139,8 +135,18 @@ private:
139 u64 event_fifo_id = 0; 135 u64 event_fifo_id = 0;
140 136
141 std::shared_ptr<EventType> ev_lost; 137 std::shared_ptr<EventType> ev_lost;
142 138 Common::Event event{};
143 std::mutex inner_mutex; 139 Common::SpinLock basic_lock{};
140 Common::SpinLock advance_lock{};
141 std::unique_ptr<std::thread> timer_thread;
142 std::atomic<bool> paused{};
143 std::atomic<bool> paused_set{};
144 std::atomic<bool> wait_set{};
145 std::atomic<bool> shutting_down{};
146 std::atomic<bool> has_started{};
147 std::function<void(void)> on_thread_init{};
148
149 std::array<std::atomic<u64>, Core::Hardware::NUM_CPU_CORES> ticks_count{};
144}; 150};
145 151
146/// Creates a core timing event with the given name and callback. 152/// Creates a core timing event with the given name and callback.