summaryrefslogtreecommitdiff
path: root/src/core/host_timing.h
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-05 19:12:27 -0400
committerGravatar Fernando Sahmkow2020-06-18 16:29:16 -0400
commit62e35ffc0effddfacb73ebc766735148436d7331 (patch)
tree10f765118c2f2bfd63dfc8ae0fc0f3a5aff6b1ba /src/core/host_timing.h
parentCommon: Polish Fiber class, add comments, asserts and more tests. (diff)
downloadyuzu-62e35ffc0effddfacb73ebc766735148436d7331.tar.gz
yuzu-62e35ffc0effddfacb73ebc766735148436d7331.tar.xz
yuzu-62e35ffc0effddfacb73ebc766735148436d7331.zip
Core: Implement a Host Timer.
Diffstat (limited to 'src/core/host_timing.h')
-rw-r--r--src/core/host_timing.h126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/core/host_timing.h b/src/core/host_timing.h
new file mode 100644
index 000000000..a3a32e087
--- /dev/null
+++ b/src/core/host_timing.h
@@ -0,0 +1,126 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <chrono>
8#include <functional>
9#include <memory>
10#include <mutex>
11#include <optional>
12#include <string>
13#include <thread>
14#include <vector>
15
16#include "common/common_types.h"
17#include "common/threadsafe_queue.h"
18
19namespace Core::HostTiming {
20
21/// A callback that may be scheduled for a particular core timing event.
22using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>;
23using sys_time_point = std::chrono::time_point<std::chrono::system_clock>;
24
25/// Contains the characteristics of a particular event.
26struct EventType {
27 EventType(TimedCallback&& callback, std::string&& name)
28 : callback{std::move(callback)}, name{std::move(name)} {}
29
30 /// The event's callback function.
31 TimedCallback callback;
32 /// A pointer to the name of the event.
33 const std::string name;
34};
35
36/**
37 * This is a system to schedule events into the emulated machine's future. Time is measured
38 * in main CPU clock cycles.
39 *
40 * To schedule an event, you first have to register its type. This is where you pass in the
41 * callback. You then schedule events using the type id you get back.
42 *
43 * The int cyclesLate that the callbacks get is how many cycles late it was.
44 * So to schedule a new event on a regular basis:
45 * inside callback:
46 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
47 */
48class CoreTiming {
49public:
50 CoreTiming();
51 ~CoreTiming();
52
53 CoreTiming(const CoreTiming&) = delete;
54 CoreTiming(CoreTiming&&) = delete;
55
56 CoreTiming& operator=(const CoreTiming&) = delete;
57 CoreTiming& operator=(CoreTiming&&) = delete;
58
59 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
60 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
61 void Initialize();
62
63 /// Tears down all timing related functionality.
64 void Shutdown();
65
66 /// Schedules an event in core timing
67 void ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type,
68 u64 userdata = 0);
69
70 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
71
72 /// We only permit one event of each type in the queue at a time.
73 void RemoveEvent(const std::shared_ptr<EventType>& event_type);
74
75 /// Returns current time in emulated CPU cycles
76 u64 GetCPUTicks() const;
77
78 /// Returns current time in emulated in Clock cycles
79 u64 GetClockTicks() const;
80
81 /// Returns current time in microseconds.
82 std::chrono::microseconds GetGlobalTimeUs() const;
83
84 /// Returns current time in nanoseconds.
85 std::chrono::nanoseconds GetGlobalTimeNs() const;
86
87private:
88 struct Event;
89
90 /// Clear all pending events. This should ONLY be done on exit.
91 void ClearPendingEvents();
92
93 static void ThreadEntry(CoreTiming& instance);
94 void Advance();
95
96 sys_time_point start_time;
97
98 u64 global_timer = 0;
99
100 std::chrono::nanoseconds start_point;
101
102 // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
103 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
104 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
105 // accomodated by the standard adaptor class.
106 std::vector<Event> event_queue;
107 u64 event_fifo_id = 0;
108
109 std::shared_ptr<EventType> ev_lost;
110 bool is_set = false;
111 std::condition_variable condvar;
112 std::mutex inner_mutex;
113 std::unique_ptr<std::thread> timer_thread;
114 std::atomic<bool> shutting_down{};
115};
116
117/// Creates a core timing event with the given name and callback.
118///
119/// @param name The name of the core timing event to create.
120/// @param callback The callback to execute for the event.
121///
122/// @returns An EventType instance representing the created event.
123///
124std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback);
125
126} // namespace Core::Timing