MXVK Vulkan Framework 0.35.0
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() { start_time = std::chrono::steady_clock::now(); }
34
35 /** @brief Record the end of a timed interval. */
36 void stop() { stop_time = std::chrono::steady_clock::now(); }
37
38 /**
39 * @brief Print the recorded interval in milliseconds and nanoseconds.
40 * @param name Descriptive name shown with the timing result.
41 *
42 * Call stop() before calling this function.
43 */
44 void echo(std::string_view name) const {
45 const auto elapsed = stop_time - start_time;
46 std::cout << "Stopwatch [" << name << "]\n"
47 << "Timer was active for : " << std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << " Milliseconds\n"
48 << "Timer was active for : " << std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count() << " Nanoseconds\n";
49 }
50
51 /**
52 * @brief Return the time elapsed since the most recent start().
53 * @return Elapsed time in milliseconds.
54 */
55 unsigned long timePassed() const {
56 auto now = std::chrono::steady_clock::now();
57 return std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
58 }
59
60 private:
61 std::chrono::steady_clock::time_point start_time, stop_time;
62};
63
64/**
65 * @brief Stopwatch policy backed by `std::chrono::high_resolution_clock`.
66 *
67 * This policy provides the clock's finest available resolution. Elapsed
68 * queries are returned in nanoseconds.
69 */
71 public:
72 /** @brief Record the beginning of a timed interval. */
73 void start() { start_time = std::chrono::high_resolution_clock::now(); }
74
75 /** @brief Record the end of a timed interval. */
76 void stop() { stop_time = std::chrono::high_resolution_clock::now(); }
77
78 /**
79 * @brief Print the recorded interval in milliseconds and nanoseconds.
80 * @param name Descriptive name shown with the timing result.
81 *
82 * Call stop() before calling this function.
83 */
84 void echo(std::string_view name) const {
85 const auto elapsed = stop_time - start_time;
86 std::cout << "Stopwatch [" << name << "]\n"
87 << "Timer was active for : " << std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << " Milliseconds\n"
88 << "Timer was active for : " << std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count() << " Nanoseconds\n";
89 }
90
91 /**
92 * @brief Return the time elapsed since the most recent start().
93 * @return Elapsed time in nanoseconds.
94 */
95 unsigned long timePassed() const {
96 auto now = std::chrono::high_resolution_clock::now();
97 return std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time).count();
98 }
99
100 private:
101 std::chrono::high_resolution_clock::time_point start_time, stop_time;
102};
103
104/**
105 * @brief RAII stopwatch using a selectable clock policy.
106 *
107 * Construction starts the timer immediately. Stop() prints the result and is
108 * safe to call more than once. If the stopwatch is still running when it is
109 * destroyed, the destructor stops it and prints the result automatically.
110 *
111 * @tparam T Clock policy satisfying ClockPolicy.
112 *
113 * @note The stopwatch stores its name as a `std::string_view`. The referenced
114 * string must remain valid for the lifetime of the stopwatch.
115 */
116template <ClockPolicy T> class StopWatch {
117 public:
118 /**
119 * @brief Construct and immediately start a stopwatch.
120 * @param name Descriptive name printed with the timing result.
121 */
122 explicit StopWatch(std::string_view name) : time_name(name) { Start(name); }
123
124 /** @brief Stop and print the timer if it is still running. */
126 if (!m_stopped) {
127 Stop();
128 }
129 }
130
131 /** @brief Stopwatches cannot be copied. */
132 StopWatch(const StopWatch &) = delete;
133 /** @brief Stopwatches cannot be copy-assigned. */
134 StopWatch &operator=(const StopWatch &) = delete;
135 /** @brief Stopwatches cannot be moved. */
136 StopWatch(StopWatch &&) = delete;
137 /** @brief Stopwatches cannot be move-assigned. */
139
140 /**
141 * @brief Start a new timed interval.
142 * @param name Descriptive name printed with the timing result.
143 *
144 * Calling this function restarts the stopwatch and replaces its name.
145 */
146 void Start(std::string_view name) {
147 time_name = name;
148 m_stopped = false;
149 clock_interface.start();
150 }
151
152 /**
153 * @brief Stop the current interval and print its duration.
154 *
155 * Repeated calls have no effect until Start() begins another interval.
156 */
157 void Stop() {
158 if (m_stopped)
159 return;
160 clock_interface.stop();
161 Echo(time_name);
162 m_stopped = true;
163 }
164
165 /**
166 * @brief Print the interval recorded by the clock policy.
167 * @param name Descriptive name shown with the timing result.
168 */
169 void Echo(std::string_view name) const { clock_interface.echo(name); }
170
171 /**
172 * @brief Query the time elapsed since the most recent Start().
173 * @return Elapsed time in the unit defined by the selected clock policy.
174 *
175 * SteadyClockPolicy returns milliseconds, while
176 * HighResolutionClockPolicy returns nanoseconds.
177 */
178 unsigned long TimePassed() const { return clock_interface.timePassed(); }
179
180 private:
181 std::string_view time_name;
182 T clock_interface;
183 bool m_stopped = false;
184};
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.