MXVK Vulkan Framework 0.33.1
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
mxvk_stopwatch.hpp
Go to the documentation of this file.
1#pragma once
2#include <chrono>
3#include <concepts>
4#include <iostream>
5#include <string_view>
6
7/**
8 * @brief Defines the interface required by a stopwatch clock policy.
9 *
10 * A compatible policy must support starting and stopping its clock, printing
11 * the measured interval, and querying the currently elapsed time.
12 *
13 * @tparam T Clock policy type to validate.
14 */
15template <typename T>
16concept ClockPolicy = requires(T clock, std::string_view name) {
17 { clock.start() } -> std::same_as<void>;
18 { clock.stop() } -> std::same_as<void>;
19 { clock.echo(name) } -> std::same_as<void>;
20 { clock.timePassed() } -> std::convertible_to<unsigned long>;
21};
22
23/**
24 * @brief Stopwatch policy backed by `std::chrono::steady_clock`.
25 *
26 * The steady clock is monotonic, making this policy suitable for measuring
27 * elapsed wall-clock time even if the system clock is adjusted. Elapsed
28 * queries are returned in milliseconds.
29 */
31 public:
32 /** @brief Record the beginning of a timed interval. */
33 void start() {
34 start_time = std::chrono::steady_clock::now();
35 }
36
37 /** @brief Record the end of a timed interval. */
38 void stop() {
39 stop_time = std::chrono::steady_clock::now();
40 }
41
42 /**
43 * @brief Print the recorded interval in milliseconds and nanoseconds.
44 * @param name Descriptive name shown with the timing result.
45 *
46 * Call stop() before calling this function.
47 */
48 void echo(std::string_view name) const {
49 const auto elapsed = stop_time - start_time;
50 std::cout << "Stopwatch [" << name << "]\n"
51 << "Timer was active for : "
52 << std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count()
53 << " Milliseconds\n"
54 << "Timer was active for : "
55 << std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()
56 << " Nanoseconds\n";
57 }
58
59 /**
60 * @brief Return the time elapsed since the most recent start().
61 * @return Elapsed time in milliseconds.
62 */
63 unsigned long timePassed() const {
64 auto now = std::chrono::steady_clock::now();
65 return std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
66 }
67
68 private:
69 std::chrono::steady_clock::time_point start_time, stop_time;
70};
71
72/**
73 * @brief Stopwatch policy backed by `std::chrono::high_resolution_clock`.
74 *
75 * This policy provides the clock's finest available resolution. Elapsed
76 * queries are returned in nanoseconds.
77 */
79 public:
80 /** @brief Record the beginning of a timed interval. */
81 void start() {
82 start_time = std::chrono::high_resolution_clock::now();
83 }
84
85 /** @brief Record the end of a timed interval. */
86 void stop() {
87 stop_time = std::chrono::high_resolution_clock::now();
88 }
89
90 /**
91 * @brief Print the recorded interval in milliseconds and nanoseconds.
92 * @param name Descriptive name shown with the timing result.
93 *
94 * Call stop() before calling this function.
95 */
96 void echo(std::string_view name) const {
97 const auto elapsed = stop_time - start_time;
98 std::cout << "Stopwatch [" << name << "]\n"
99 << "Timer was active for : "
100 << std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count()
101 << " Milliseconds\n"
102 << "Timer was active for : "
103 << std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()
104 << " Nanoseconds\n";
105 }
106
107 /**
108 * @brief Return the time elapsed since the most recent start().
109 * @return Elapsed time in nanoseconds.
110 */
111 unsigned long timePassed() const {
112 auto now = std::chrono::high_resolution_clock::now();
113 return std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time).count();
114 }
115
116 private:
117 std::chrono::high_resolution_clock::time_point start_time, stop_time;
118};
119
120/**
121 * @brief RAII stopwatch using a selectable clock policy.
122 *
123 * Construction starts the timer immediately. Stop() prints the result and is
124 * safe to call more than once. If the stopwatch is still running when it is
125 * destroyed, the destructor stops it and prints the result automatically.
126 *
127 * @tparam T Clock policy satisfying ClockPolicy.
128 *
129 * @note The stopwatch stores its name as a `std::string_view`. The referenced
130 * string must remain valid for the lifetime of the stopwatch.
131 */
132template <ClockPolicy T>
134 public:
135 /**
136 * @brief Construct and immediately start a stopwatch.
137 * @param name Descriptive name printed with the timing result.
138 */
139 explicit StopWatch(std::string_view name) : time_name(name) {
140 Start(name);
141 }
142
143 /** @brief Stop and print the timer if it is still running. */
145 if (!m_stopped) {
146 Stop();
147 }
148 }
149
150 /** @brief Stopwatches cannot be copied. */
151 StopWatch(const StopWatch &) = delete;
152 /** @brief Stopwatches cannot be copy-assigned. */
153 StopWatch &operator=(const StopWatch &) = delete;
154 /** @brief Stopwatches cannot be moved. */
155 StopWatch(StopWatch &&) = delete;
156 /** @brief Stopwatches cannot be move-assigned. */
158
159 /**
160 * @brief Start a new timed interval.
161 * @param name Descriptive name printed with the timing result.
162 *
163 * Calling this function restarts the stopwatch and replaces its name.
164 */
165 void Start(std::string_view name) {
166 time_name = name;
167 m_stopped = false;
168 clock_interface.start();
169 }
170
171 /**
172 * @brief Stop the current interval and print its duration.
173 *
174 * Repeated calls have no effect until Start() begins another interval.
175 */
176 void Stop() {
177 if (m_stopped)
178 return;
179 clock_interface.stop();
180 Echo(time_name);
181 m_stopped = true;
182 }
183
184 /**
185 * @brief Print the interval recorded by the clock policy.
186 * @param name Descriptive name shown with the timing result.
187 */
188 void Echo(std::string_view name) const {
189 clock_interface.echo(name);
190 }
191
192 /**
193 * @brief Query the time elapsed since the most recent Start().
194 * @return Elapsed time in the unit defined by the selected clock policy.
195 *
196 * SteadyClockPolicy returns milliseconds, while
197 * HighResolutionClockPolicy returns nanoseconds.
198 */
199 unsigned long TimePassed() const {
200 return clock_interface.timePassed();
201 }
202
203 private:
204 std::string_view time_name;
205 T clock_interface;
206 bool m_stopped = false;
207};
Stopwatch policy backed by std::chrono::high_resolution_clock.
void stop()
Record the end of a timed interval.
unsigned long timePassed() const
Return the time elapsed since the most recent start().
void echo(std::string_view name) const
Print the recorded interval in milliseconds and nanoseconds.
void start()
Record the beginning of a timed interval.
Stopwatch policy backed by std::chrono::steady_clock.
void stop()
Record the end of a timed interval.
void echo(std::string_view name) const
Print the recorded interval in milliseconds and nanoseconds.
void start()
Record the beginning of a timed interval.
unsigned long timePassed() const
Return the time elapsed since the most recent start().
StopWatch & operator=(StopWatch &&)=delete
Stopwatches cannot be move-assigned.
StopWatch & operator=(const StopWatch &)=delete
Stopwatches cannot be copy-assigned.
StopWatch(StopWatch &&)=delete
Stopwatches cannot be moved.
void Stop()
Stop the current interval and print its duration.
StopWatch(const StopWatch &)=delete
Stopwatches cannot be copied.
StopWatch(std::string_view name)
Construct and immediately start a stopwatch.
void Echo(std::string_view name) const
Print the interval recorded by the clock policy.
~StopWatch()
Stop and print the timer if it is still running.
unsigned long TimePassed() const
Query the time elapsed since the most recent Start().
void Start(std::string_view name)
Start a new timed interval.
Defines the interface required by a stopwatch clock policy.