tess 0.4.0
Performance-first tile and path simulation substrate
Loading...
Searching...
No Matches
diagnostics.h
1#pragma once
2
3#include <cstddef>
4#include <cstdint>
5
6#if defined(TESS_ENABLE_DIAGNOSTICS)
8#define TESS_DIAGNOSTICS_ENABLED 1
10#define TESS_DIAGNOSTIC_ONLY(expr) \
11 do { \
12 expr; \
13 } while (false)
15#define TESS_DIAGNOSTIC_INC(counter) \
16 do { \
17 ++(counter); \
18 } while (false)
20#define TESS_DIAGNOSTIC_ADD(counter, value) \
21 do { \
22 (counter) += (value); \
23 } while (false)
25#define TESS_DIAG_EVENT(name) \
26 do { \
27 ::tess::diagnostics::event_##name(); \
28 } while (false)
30#define TESS_DIAG_EVENT_VALUE(name, value) \
31 do { \
32 ::tess::diagnostics::event_##name(value); \
33 } while (false)
34#else
35#define TESS_DIAGNOSTICS_ENABLED 0
36#define TESS_DIAGNOSTIC_ONLY(expr) \
37 do { \
38 } while (false)
39#define TESS_DIAGNOSTIC_INC(counter) \
40 do { \
41 } while (false)
42#define TESS_DIAGNOSTIC_ADD(counter, value) \
43 do { \
44 } while (false)
45#define TESS_DIAG_EVENT(name) \
46 do { \
47 } while (false)
48#define TESS_DIAG_EVENT_VALUE(name, value) \
49 do { \
50 } while (false)
51#endif
52
53namespace tess::diagnostics {
54
55#if TESS_DIAGNOSTICS_ENABLED
58 std::uint64_t scratch_clear_calls = 0;
59 std::uint64_t scratch_clear_nodes = 0;
60 std::uint64_t initializations = 0;
61 std::uint64_t start_passability_checks = 0;
62 std::uint64_t goal_passability_checks = 0;
63 std::uint64_t heap_pushes = 0;
64 std::uint64_t heap_pops = 0;
65 std::uint64_t stale_pops = 0;
66 std::uint64_t closed_pops = 0;
67 std::uint64_t neighbor_candidates = 0;
68 std::uint64_t passability_checks = 0;
69 std::uint64_t cost_reads = 0;
70 std::uint64_t blocked_neighbors = 0;
71 std::uint64_t closed_neighbors = 0;
72 std::uint64_t relax_attempts = 0;
73 std::uint64_t relax_successes = 0;
74 std::uint64_t touched_nodes = 0;
75 std::uint64_t heuristic_calls = 0;
76 std::uint64_t reconstructed_nodes = 0;
77
78 void reset() noexcept { *this = PathCounters{}; }
79};
80
83 std::uint64_t allocations = 0;
84 std::uint64_t allocation_bytes = 0;
85 std::uint64_t deallocations = 0;
86 std::uint64_t deallocation_bytes = 0;
87
88 void reset() noexcept { *this = AllocationCounters{}; }
89};
90
93 std::uint64_t phase_calls = 0;
94 std::uint64_t phase_operations = 0;
95 std::uint64_t phase_invalid_ranges = 0;
96 std::uint64_t phase_failures = 0;
97 std::uint64_t partitioned_phase_calls = 0;
98 std::uint64_t dirty_partitions = 0;
99 std::uint64_t scoped_thread_calls = 0;
100 std::uint64_t scoped_thread_workers = 0;
101 std::uint64_t worker_pool_calls = 0;
102 std::uint64_t worker_pool_workers = 0;
103 std::uint64_t dirty_records_collected = 0;
104 std::uint64_t dirty_chunks_merged = 0;
105
106 void reset() noexcept { *this = QueuedPhaseCounters{}; }
107};
108
109inline thread_local PathCounters* active_path_counters = nullptr;
110inline thread_local AllocationCounters* active_allocation_counters = nullptr;
111inline thread_local QueuedPhaseCounters* active_queued_phase_counters = nullptr;
112
114class ScopedPathCounters {
115 public:
116 explicit ScopedPathCounters(PathCounters& counters) noexcept
117 : previous_{active_path_counters} {
118 active_path_counters = &counters;
119 }
120
121 ScopedPathCounters(const ScopedPathCounters&) = delete;
122 auto operator=(const ScopedPathCounters&) -> ScopedPathCounters& = delete;
123
124 ~ScopedPathCounters() { active_path_counters = previous_; }
125
126 private:
127 PathCounters* previous_;
128};
129
133class ScopedAllocationCounters {
134 public:
135 explicit ScopedAllocationCounters(AllocationCounters& counters) noexcept
136 : previous_{active_allocation_counters} {
137 active_allocation_counters = &counters;
138 }
139
140 ScopedAllocationCounters(const ScopedAllocationCounters&) = delete;
141 auto operator=(const ScopedAllocationCounters&)
142 -> ScopedAllocationCounters& = delete;
143
144 ~ScopedAllocationCounters() { active_allocation_counters = previous_; }
145
146 private:
147 AllocationCounters* previous_;
148};
149
153class ScopedQueuedPhaseCounters {
154 public:
155 explicit ScopedQueuedPhaseCounters(QueuedPhaseCounters& counters) noexcept
156 : previous_{active_queued_phase_counters} {
157 active_queued_phase_counters = &counters;
158 }
159
160 ScopedQueuedPhaseCounters(const ScopedQueuedPhaseCounters&) = delete;
161 auto operator=(const ScopedQueuedPhaseCounters&)
162 -> ScopedQueuedPhaseCounters& = delete;
163
164 ~ScopedQueuedPhaseCounters() { active_queued_phase_counters = previous_; }
165
166 private:
167 QueuedPhaseCounters* previous_;
168};
169
171inline void record_allocation(std::size_t size) noexcept {
172 if (active_allocation_counters != nullptr) {
173 ++active_allocation_counters->allocations;
174 active_allocation_counters->allocation_bytes += size;
175 }
176}
177
179inline void record_deallocation(std::size_t size = 0) noexcept {
180 if (active_allocation_counters != nullptr) {
181 ++active_allocation_counters->deallocations;
182 active_allocation_counters->deallocation_bytes += size;
183 }
184}
185
187inline void event_path_clear(std::uint64_t nodes) noexcept {
188 if (active_path_counters != nullptr) {
189 ++active_path_counters->scratch_clear_calls;
190 active_path_counters->scratch_clear_nodes += nodes;
191 }
192}
193
195inline void event_path_initialize() noexcept {
196 if (active_path_counters != nullptr) {
197 ++active_path_counters->initializations;
198 }
199}
200
202inline void event_path_start_passability_check() noexcept {
203 if (active_path_counters != nullptr) {
204 ++active_path_counters->start_passability_checks;
205 }
206}
207
209inline void event_path_goal_passability_check() noexcept {
210 if (active_path_counters != nullptr) {
211 ++active_path_counters->goal_passability_checks;
212 }
213}
214
216inline void event_path_heap_push() noexcept {
217 if (active_path_counters != nullptr) {
218 ++active_path_counters->heap_pushes;
219 }
220}
221
223inline void event_path_heap_pop() noexcept {
224 if (active_path_counters != nullptr) {
225 ++active_path_counters->heap_pops;
226 }
227}
228
230inline void event_path_skip_pop(bool closed) noexcept {
231 if (active_path_counters != nullptr) {
232 if (closed) {
233 ++active_path_counters->closed_pops;
234 } else {
235 ++active_path_counters->stale_pops;
236 }
237 }
238}
239
241inline void event_path_neighbor_candidate() noexcept {
242 if (active_path_counters != nullptr) {
243 ++active_path_counters->neighbor_candidates;
244 }
245}
246
248inline void event_path_passability_check() noexcept {
249 if (active_path_counters != nullptr) {
250 ++active_path_counters->passability_checks;
251 }
252}
253
255inline void event_path_cost_read() noexcept {
256 if (active_path_counters != nullptr) {
257 ++active_path_counters->cost_reads;
258 }
259}
260
262inline void event_path_neighbor_blocked() noexcept {
263 if (active_path_counters != nullptr) {
264 ++active_path_counters->blocked_neighbors;
265 }
266}
267
269inline void event_path_neighbor_closed() noexcept {
270 if (active_path_counters != nullptr) {
271 ++active_path_counters->closed_neighbors;
272 }
273}
274
276inline void event_path_relax_attempt() noexcept {
277 if (active_path_counters != nullptr) {
278 ++active_path_counters->relax_attempts;
279 }
280}
281
283inline void event_path_relax_success() noexcept {
284 if (active_path_counters != nullptr) {
285 ++active_path_counters->relax_successes;
286 }
287}
288
290inline void event_path_touch_node() noexcept {
291 if (active_path_counters != nullptr) {
292 ++active_path_counters->touched_nodes;
293 }
294}
295
297inline void event_path_heuristic() noexcept {
298 if (active_path_counters != nullptr) {
299 ++active_path_counters->heuristic_calls;
300 }
301}
302
304inline void event_path_reconstruct_node() noexcept {
305 if (active_path_counters != nullptr) {
306 ++active_path_counters->reconstructed_nodes;
307 }
308}
309
311inline void event_queued_phase_execute(std::uint64_t operations) noexcept {
312 if (active_queued_phase_counters != nullptr) {
313 ++active_queued_phase_counters->phase_calls;
314 active_queued_phase_counters->phase_operations += operations;
315 }
316}
317
319inline void event_queued_phase_invalid_range() noexcept {
320 if (active_queued_phase_counters != nullptr) {
321 ++active_queued_phase_counters->phase_invalid_ranges;
322 }
323}
324
326inline void event_queued_phase_failure() noexcept {
327 if (active_queued_phase_counters != nullptr) {
328 ++active_queued_phase_counters->phase_failures;
329 }
330}
331
333inline void event_queued_partitioned_phase(std::uint64_t partitions) noexcept {
334 if (active_queued_phase_counters != nullptr) {
335 ++active_queued_phase_counters->partitioned_phase_calls;
336 active_queued_phase_counters->dirty_partitions += partitions;
337 }
338}
339
341inline void event_queued_scoped_thread_dispatch(
342 std::uint64_t workers) noexcept {
343 if (active_queued_phase_counters != nullptr) {
344 ++active_queued_phase_counters->scoped_thread_calls;
345 active_queued_phase_counters->scoped_thread_workers += workers;
346 }
347}
348
350inline void event_queued_worker_pool_dispatch(std::uint64_t workers) noexcept {
351 if (active_queued_phase_counters != nullptr) {
352 ++active_queued_phase_counters->worker_pool_calls;
353 active_queued_phase_counters->worker_pool_workers += workers;
354 }
355}
356
358inline void event_queued_dirty_collect(std::uint64_t records) noexcept {
359 if (active_queued_phase_counters != nullptr) {
360 active_queued_phase_counters->dirty_records_collected += records;
361 }
362}
363
365inline void event_queued_dirty_merge(std::uint64_t chunks) noexcept {
366 if (active_queued_phase_counters != nullptr) {
367 active_queued_phase_counters->dirty_chunks_merged += chunks;
368 }
369}
370#endif
371
372} // namespace tess::diagnostics
Definition diagnostics.h:82
Definition diagnostics.h:57
Definition diagnostics.h:92