Sleipnir C++ API
Loading...
Searching...
No Matches
time_tracer.hpp
1// Copyright (c) Sleipnir contributors
2
3#pragma once
4
5#include <array>
6#include <chrono>
7#include <concepts>
8#include <cstddef>
9#include <span>
10#include <string_view>
11#include <type_traits>
12#include <utility>
13
14namespace slp {
15
21 public:
23 SetupTimeTracer() = default;
24
28 explicit SetupTimeTracer(bool enabled) : m_enabled{enabled} {}
29
31 void start() {
32#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
33 if (m_enabled) {
34 m_setup_start_time = std::chrono::steady_clock::now();
35 }
36#endif
37 }
38
40 void stop() {
41#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
42 if (m_enabled) {
43 m_setup_duration = std::chrono::steady_clock::now() - m_setup_start_time;
44 }
45#endif
46 }
47
51 const std::chrono::duration<double>& duration() const {
52 return m_setup_duration;
53 }
54
55 private:
56 [[maybe_unused]]
57 bool m_enabled = true;
58 std::chrono::steady_clock::time_point m_setup_start_time;
59 std::chrono::duration<double> m_setup_duration{0.0};
60};
61
65 public:
67 SolveTimeTracer() = default;
68
72 explicit SolveTimeTracer(bool enabled) : m_enabled{enabled} {}
73
75 void start() {
76#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
77 if (m_enabled) {
78 m_current_solve_start_time = std::chrono::steady_clock::now();
79 }
80#endif
81 }
82
85 void stop() {
86#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
87 if (m_enabled) {
88 m_current_solve_duration =
89 std::chrono::steady_clock::now() - m_current_solve_start_time;
90 m_total_solve_duration += m_current_solve_duration;
91
92 ++m_num_solves;
93 m_average_solve_duration =
94 (m_num_solves - 1.0) / m_num_solves * m_average_solve_duration +
95 1.0 / m_num_solves * m_current_solve_duration;
96 }
97#endif
98 }
99
103 int num_solves() const { return m_num_solves; }
104
108 const std::chrono::duration<double>& current_duration() const {
109 return m_current_solve_duration;
110 }
111
115 const std::chrono::duration<double>& average_duration() const {
116 return m_average_solve_duration;
117 }
118
122 const std::chrono::duration<double>& total_duration() const {
123 return m_total_solve_duration;
124 }
125
126 private:
127 [[maybe_unused]]
128 bool m_enabled = true;
129 std::chrono::steady_clock::time_point m_current_solve_start_time;
130 std::chrono::duration<double> m_current_solve_duration{0.0};
131 std::chrono::duration<double> m_total_solve_duration{0.0};
132
133 int m_num_solves = 0;
134 std::chrono::duration<double> m_average_solve_duration{0.0};
135};
136
138template <typename T>
139concept TimeTracer =
140 std::same_as<T, SetupTimeTracer> || std::same_as<T, SolveTimeTracer>;
141
145template <TimeTracer Tracer>
147 public:
151 explicit ScopedTimeTracer(Tracer& tracer) noexcept : m_tracer{&tracer} {
152 m_tracer->start();
153 }
154
157 if (m_active) {
158 m_tracer->stop();
159 }
160 }
161
166 : m_tracer{rhs.m_tracer}, m_active{rhs.m_active} {
167 rhs.m_active = false;
168 }
169
170 ScopedTimeTracer(const ScopedTimeTracer&) = delete;
171 ScopedTimeTracer& operator=(const ScopedTimeTracer&) = delete;
172
176 void stop() {
177 if (m_active) {
178 m_tracer->stop();
179 m_active = false;
180 }
181 }
182
186 const std::chrono::duration<double>& current_duration() const {
187 return m_tracer->current_duration();
188 }
189
190 private:
191 Tracer* m_tracer;
192 bool m_active = true;
193};
194
201template <TimeTracer Tracer>
203 public:
207 explicit PhaseTimeTracer(Tracer& tracer) noexcept : m_tracer{&tracer} {
208 m_tracer->start();
209 }
210
213
214 PhaseTimeTracer(const PhaseTimeTracer&) = delete;
215 PhaseTimeTracer& operator=(const PhaseTimeTracer&) = delete;
216
220 void next(Tracer& tracer) {
221 stop();
222 m_tracer = &tracer;
223 m_tracer->start();
224 }
225
227 void stop() {
228 if (m_tracer != nullptr) {
229 m_tracer->stop();
230 m_tracer = nullptr;
231 }
232 }
233
234 private:
235 Tracer* m_tracer;
236};
237
245template <TimeTracer Tracer, typename F>
246auto traced(Tracer& tracer, const F& f) {
247 return [&tracer, &f]<typename... Args>(Args&&... args) -> decltype(auto) {
248 ScopedTimeTracer scoped_tracer{tracer};
249 return f(std::forward<Args>(args)...);
250 };
251}
252
256template <typename ID>
257 requires std::is_enum_v<ID>
260 ID id;
261
263 std::string_view name;
264
266 int depth;
267};
268
269namespace detail {
270
278template <typename ID, size_t N>
279consteval bool is_valid_time_trace(
280 const std::array<TimeTraceEntry<ID>, N>& entries) {
281 if (N == 0 || entries[0].depth != 0) {
282 return false;
283 }
284
285 for (size_t i = 1; i < N; ++i) {
286 // Each entry after the root must have a larger ID than the previous entry
287 if (std::to_underlying(entries[i].id) <=
288 std::to_underlying(entries[i - 1].id)) {
289 return false;
290 }
291
292 // Each entry after the root must be a descendant of the root
293 if (entries[i].depth < 1) {
294 return false;
295 }
296
297 // Each entry must be at most one level deeper than the previous entry, so
298 // it's either the previous entry's child, its sibling, or a sibling of one
299 // of its ancestors
300 if (entries[i].depth > entries[i - 1].depth + 1) {
301 return false;
302 }
303 }
304
305 return true;
306}
307
312void tracer_id_is_not_in_time_trace();
313
314} // namespace detail
315
319template <const auto& Entries>
320 requires(detail::is_valid_time_trace(Entries))
322 public:
324 using ID = decltype(Entries[0].id);
325
332 // NOLINTNEXTLINE (google-explicit-constructor)
333 consteval TimeTracerIndex(ID id) {
334 for (size_t i = 0; i < Entries.size(); ++i) {
335 if (Entries[i].id == id) {
336 m_index = i;
337 return;
338 }
339 }
340
341 detail::tracer_id_is_not_in_time_trace();
342 }
343
347 constexpr size_t value() const { return m_index; }
348
349 private:
350 size_t m_index = 0;
351};
352
358template <TimeTracer Tracer, const auto& Entries>
359 requires(detail::is_valid_time_trace(Entries))
361 public:
364
368 explicit TimeTracerTree(bool enabled) { m_tracers.fill(Tracer{enabled}); }
369
376 return m_tracers[index.value()];
377 }
378
382 Tracer& root() { return m_tracers[0]; }
383
387 static constexpr std::span<const TimeTraceEntry<ID>, Entries.size()>
389 return Entries;
390 }
391
395 std::span<const Tracer, Entries.size()> tracers() const { return m_tracers; }
396
397 private:
398 std::array<Tracer, Entries.size()> m_tracers;
399};
400
401} // namespace slp
Definition time_tracer.hpp:202
void next(Tracer &tracer)
Definition time_tracer.hpp:220
void stop()
Stops the active phase, if any.
Definition time_tracer.hpp:227
PhaseTimeTracer(Tracer &tracer) noexcept
Definition time_tracer.hpp:207
~PhaseTimeTracer()
Stops the active phase.
Definition time_tracer.hpp:212
Definition time_tracer.hpp:146
ScopedTimeTracer(Tracer &tracer) noexcept
Definition time_tracer.hpp:151
~ScopedTimeTracer()
Stops a tracer.
Definition time_tracer.hpp:156
ScopedTimeTracer(ScopedTimeTracer &&rhs) noexcept
Definition time_tracer.hpp:165
const std::chrono::duration< double > & current_duration() const
Definition time_tracer.hpp:186
void stop()
Definition time_tracer.hpp:176
Definition time_tracer.hpp:20
SetupTimeTracer(bool enabled)
Definition time_tracer.hpp:28
SetupTimeTracer()=default
Constructs an enabled tracer.
const std::chrono::duration< double > & duration() const
Definition time_tracer.hpp:51
void start()
Starts setup time measurement.
Definition time_tracer.hpp:31
void stop()
Stops setup time measurement.
Definition time_tracer.hpp:40
Definition time_tracer.hpp:64
void stop()
Definition time_tracer.hpp:85
const std::chrono::duration< double > & current_duration() const
Definition time_tracer.hpp:108
const std::chrono::duration< double > & total_duration() const
Definition time_tracer.hpp:122
const std::chrono::duration< double > & average_duration() const
Definition time_tracer.hpp:115
SolveTimeTracer(bool enabled)
Definition time_tracer.hpp:72
void start()
Starts solve time measurement.
Definition time_tracer.hpp:75
int num_solves() const
Definition time_tracer.hpp:103
SolveTimeTracer()=default
Constructs an enabled tracer.
Definition time_tracer.hpp:321
consteval TimeTracerIndex(ID id)
Definition time_tracer.hpp:333
constexpr size_t value() const
Definition time_tracer.hpp:347
decltype(Entries[0].id) ID
Time tracer ID enum type.
Definition time_tracer.hpp:324
Definition time_tracer.hpp:360
Tracer & root()
Definition time_tracer.hpp:382
TimeTracerTree(bool enabled)
Definition time_tracer.hpp:368
typename TimeTracerIndex< Entries >::ID ID
Time tracer ID enum type.
Definition time_tracer.hpp:363
static constexpr std::span< const TimeTraceEntry< ID >, Entries.size()> entries()
Definition time_tracer.hpp:388
Tracer & operator[](TimeTracerIndex< Entries > index)
Definition time_tracer.hpp:375
std::span< const Tracer, Entries.size()> tracers() const
Definition time_tracer.hpp:395
Time tracer concept.
Definition time_tracer.hpp:139
Definition time_tracer.hpp:258
std::string_view name
Name of measurement to show in diagnostics.
Definition time_tracer.hpp:263
ID id
Time tracer ID.
Definition time_tracer.hpp:260
int depth
Nesting depth in the time trace. The root has depth 0.
Definition time_tracer.hpp:266