20#if defined(TESS_ENABLE_DIAGNOSTICS)
21#pragma detect_mismatch("tess_diagnostics_mode", "enabled")
23#pragma detect_mismatch("tess_diagnostics_mode", "disabled")
27#if defined(TESS_ENABLE_DIAGNOSTICS)
29#define TESS_DIAGNOSTICS_ENABLED 1
31#define TESS_DIAGNOSTIC_ONLY(expr) \
36#define TESS_DIAGNOSTIC_INC(counter) \
41#define TESS_DIAGNOSTIC_ADD(counter, value) \
43 (counter) += (value); \
46#define TESS_DIAG_EVENT(name) \
48 ::tess::diagnostics::event_##name(); \
51#define TESS_DIAG_EVENT_VALUE(name, value) \
53 ::tess::diagnostics::event_##name(value); \
56#define TESS_DIAGNOSTICS_ENABLED 0
57#define TESS_DIAGNOSTIC_ONLY(expr) \
60#define TESS_DIAGNOSTIC_INC(counter) \
63#define TESS_DIAGNOSTIC_ADD(counter, value) \
66#define TESS_DIAG_EVENT(name) \
69#define TESS_DIAG_EVENT_VALUE(name, value) \
74namespace tess::diagnostics {
76#if TESS_DIAGNOSTICS_ENABLED
79 std::uint64_t scratch_clear_calls = 0;
80 std::uint64_t scratch_clear_nodes = 0;
81 std::uint64_t initializations = 0;
82 std::uint64_t start_passability_checks = 0;
83 std::uint64_t goal_passability_checks = 0;
84 std::uint64_t heap_pushes = 0;
85 std::uint64_t heap_pops = 0;
86 std::uint64_t stale_pops = 0;
87 std::uint64_t closed_pops = 0;
88 std::uint64_t neighbor_candidates = 0;
89 std::uint64_t passability_checks = 0;
90 std::uint64_t cost_reads = 0;
91 std::uint64_t blocked_neighbors = 0;
92 std::uint64_t closed_neighbors = 0;
93 std::uint64_t relax_attempts = 0;
94 std::uint64_t relax_successes = 0;
95 std::uint64_t touched_nodes = 0;
96 std::uint64_t heuristic_calls = 0;
97 std::uint64_t reconstructed_nodes = 0;
104 std::uint64_t allocations = 0;
105 std::uint64_t allocation_bytes = 0;
106 std::uint64_t deallocations = 0;
107 std::uint64_t deallocation_bytes = 0;
111 std::uint64_t live_bytes = 0;
112 std::uint64_t peak_live_bytes = 0;
119 std::uint64_t phase_calls = 0;
120 std::uint64_t phase_operations = 0;
121 std::uint64_t phase_invalid_ranges = 0;
122 std::uint64_t phase_failures = 0;
123 std::uint64_t partitioned_phase_calls = 0;
124 std::uint64_t dirty_partitions = 0;
125 std::uint64_t scoped_thread_calls = 0;
126 std::uint64_t scoped_thread_workers = 0;
127 std::uint64_t worker_pool_calls = 0;
128 std::uint64_t worker_pool_workers = 0;
129 std::uint64_t dirty_records_collected = 0;
130 std::uint64_t dirty_chunks_merged = 0;
135inline thread_local PathCounters* active_path_counters =
nullptr;
137inline thread_local std::uint64_t active_allocation_scope_id = 0;
138inline thread_local std::uint64_t next_allocation_scope_id = 1;
142class ScopedPathCounters {
144 explicit ScopedPathCounters(
PathCounters& counters) noexcept
145 : previous_{active_path_counters} {
146 active_path_counters = &counters;
149 ScopedPathCounters(
const ScopedPathCounters&) =
delete;
150 auto operator=(
const ScopedPathCounters&) -> ScopedPathCounters& =
delete;
152 ~ScopedPathCounters() { active_path_counters = previous_; }
161class ScopedAllocationCounters {
164 : previous_{active_allocation_counters},
165 previous_scope_id_{active_allocation_scope_id},
166 scope_id_{next_allocation_scope_id++} {
167 if (next_allocation_scope_id == 0) {
168 next_allocation_scope_id = 1;
170 active_allocation_counters = &counters;
171 active_allocation_scope_id = scope_id_;
174 ScopedAllocationCounters(
const ScopedAllocationCounters&) =
delete;
175 auto operator=(
const ScopedAllocationCounters&)
176 -> ScopedAllocationCounters& =
delete;
178 ~ScopedAllocationCounters() {
179 active_allocation_counters = previous_;
180 active_allocation_scope_id = previous_scope_id_;
185 std::uint64_t previous_scope_id_;
186 std::uint64_t scope_id_;
192class ScopedQueuedPhaseCounters {
195 : previous_{active_queued_phase_counters} {
196 active_queued_phase_counters = &counters;
199 ScopedQueuedPhaseCounters(
const ScopedQueuedPhaseCounters&) =
delete;
200 auto operator=(
const ScopedQueuedPhaseCounters&)
201 -> ScopedQueuedPhaseCounters& =
delete;
203 ~ScopedQueuedPhaseCounters() { active_queued_phase_counters = previous_; }
210inline void record_allocation(std::size_t size)
noexcept {
211 if (active_allocation_counters !=
nullptr) {
212 auto& counters = *active_allocation_counters;
213 ++counters.allocations;
214 counters.allocation_bytes += size;
215 const auto bytes =
static_cast<std::uint64_t
>(size);
216 const auto maximum = std::numeric_limits<std::uint64_t>::max();
217 counters.live_bytes = bytes > maximum - counters.live_bytes
219 : counters.live_bytes + bytes;
220 if (counters.live_bytes > counters.peak_live_bytes) {
221 counters.peak_live_bytes = counters.live_bytes;
227inline void record_deallocation(std::size_t size = 0) noexcept {
228 if (active_allocation_counters !=
nullptr) {
229 auto& counters = *active_allocation_counters;
230 ++counters.deallocations;
231 counters.deallocation_bytes += size;
232 const auto bytes =
static_cast<std::uint64_t
>(size);
233 counters.live_bytes =
234 bytes > counters.live_bytes ? 0 : counters.live_bytes - bytes;
239inline void event_path_clear(std::uint64_t nodes)
noexcept {
240 if (active_path_counters !=
nullptr) {
241 ++active_path_counters->scratch_clear_calls;
242 active_path_counters->scratch_clear_nodes += nodes;
247inline void event_path_initialize() noexcept {
248 if (active_path_counters !=
nullptr) {
249 ++active_path_counters->initializations;
254inline void event_path_start_passability_check() noexcept {
255 if (active_path_counters !=
nullptr) {
256 ++active_path_counters->start_passability_checks;
261inline void event_path_goal_passability_check() noexcept {
262 if (active_path_counters !=
nullptr) {
263 ++active_path_counters->goal_passability_checks;
268inline void event_path_heap_push() noexcept {
269 if (active_path_counters !=
nullptr) {
270 ++active_path_counters->heap_pushes;
275inline void event_path_heap_pop() noexcept {
276 if (active_path_counters !=
nullptr) {
277 ++active_path_counters->heap_pops;
282inline void event_path_skip_pop(
bool closed)
noexcept {
283 if (active_path_counters !=
nullptr) {
285 ++active_path_counters->closed_pops;
287 ++active_path_counters->stale_pops;
293inline void event_path_neighbor_candidate() noexcept {
294 if (active_path_counters !=
nullptr) {
295 ++active_path_counters->neighbor_candidates;
300inline void event_path_passability_check() noexcept {
301 if (active_path_counters !=
nullptr) {
302 ++active_path_counters->passability_checks;
307inline void event_path_cost_read() noexcept {
308 if (active_path_counters !=
nullptr) {
309 ++active_path_counters->cost_reads;
314inline void event_path_neighbor_blocked() noexcept {
315 if (active_path_counters !=
nullptr) {
316 ++active_path_counters->blocked_neighbors;
321inline void event_path_neighbor_closed() noexcept {
322 if (active_path_counters !=
nullptr) {
323 ++active_path_counters->closed_neighbors;
328inline void event_path_relax_attempt() noexcept {
329 if (active_path_counters !=
nullptr) {
330 ++active_path_counters->relax_attempts;
335inline void event_path_relax_success() noexcept {
336 if (active_path_counters !=
nullptr) {
337 ++active_path_counters->relax_successes;
342inline void event_path_touch_node() noexcept {
343 if (active_path_counters !=
nullptr) {
344 ++active_path_counters->touched_nodes;
349inline void event_path_heuristic() noexcept {
350 if (active_path_counters !=
nullptr) {
351 ++active_path_counters->heuristic_calls;
356inline void event_path_reconstruct_node() noexcept {
357 if (active_path_counters !=
nullptr) {
358 ++active_path_counters->reconstructed_nodes;
363inline void event_queued_phase_execute(std::uint64_t operations)
noexcept {
364 if (active_queued_phase_counters !=
nullptr) {
365 ++active_queued_phase_counters->phase_calls;
366 active_queued_phase_counters->phase_operations += operations;
371inline void event_queued_phase_invalid_range() noexcept {
372 if (active_queued_phase_counters !=
nullptr) {
373 ++active_queued_phase_counters->phase_invalid_ranges;
378inline void event_queued_phase_failure() noexcept {
379 if (active_queued_phase_counters !=
nullptr) {
380 ++active_queued_phase_counters->phase_failures;
385inline void event_queued_partitioned_phase(std::uint64_t partitions)
noexcept {
386 if (active_queued_phase_counters !=
nullptr) {
387 ++active_queued_phase_counters->partitioned_phase_calls;
388 active_queued_phase_counters->dirty_partitions += partitions;
393inline void event_queued_scoped_thread_dispatch(
394 std::uint64_t workers)
noexcept {
395 if (active_queued_phase_counters !=
nullptr) {
396 ++active_queued_phase_counters->scoped_thread_calls;
397 active_queued_phase_counters->scoped_thread_workers += workers;
402inline void event_queued_worker_pool_dispatch(std::uint64_t workers)
noexcept {
403 if (active_queued_phase_counters !=
nullptr) {
404 ++active_queued_phase_counters->worker_pool_calls;
405 active_queued_phase_counters->worker_pool_workers += workers;
410inline void event_queued_dirty_collect(std::uint64_t records)
noexcept {
411 if (active_queued_phase_counters !=
nullptr) {
412 active_queued_phase_counters->dirty_records_collected += records;
417inline void event_queued_dirty_merge(std::uint64_t chunks)
noexcept {
418 if (active_queued_phase_counters !=
nullptr) {
419 active_queued_phase_counters->dirty_chunks_merged += chunks;
473 [[nodiscard]]
constexpr auto terminal() const noexcept -> std::uint64_t {
532 if (
counters.outstanding_current > 0) {
554[[nodiscard]]
inline auto snapshot(
const FlowAccounting& accounting)
noexcept
558 accounting.counters.admission_identity_holds(),
559 accounting.counters.retention_identity_holds(),
Definition diagnostics.h:103
Definition diagnostics.h:505
void observe_tick(std::uint64_t tick) noexcept
Definition diagnostics.h:513
void record_admitted() noexcept
Records one admission at the current observation tick.
Definition diagnostics.h:522
std::uint64_t last_observed_tick
The most recent tick passed to an observation.
Definition diagnostics.h:509
void record_left_outstanding() noexcept
Records one terminal transition leaving the outstanding set.
Definition diagnostics.h:531
FlowCounters counters
The accumulated flow counters.
Definition diagnostics.h:507
Definition diagnostics.h:436
std::uint64_t offered_work_units
Work units offered through explicitly bounded budgets.
Definition diagnostics.h:458
std::uint64_t failed
Items that terminated in an error state.
Definition diagnostics.h:454
std::uint64_t oldest_outstanding_age_ticks
Age in ticks of the oldest still-outstanding item, as last observed.
Definition diagnostics.h:470
std::uint64_t superseded
Items replaced by a newer admission of the same slot or goal.
Definition diagnostics.h:450
std::uint64_t consumed_work_units
Work units actually consumed by flow items.
Definition diagnostics.h:460
std::uint64_t outstanding_current
Admitted, non-terminal items right now.
Definition diagnostics.h:462
std::uint64_t admitted
Offers accepted as new flow items.
Definition diagnostics.h:440
std::uint64_t cancelled
Items explicitly cancelled by the caller.
Definition diagnostics.h:448
constexpr auto retention_identity_holds() const noexcept -> bool
Every admitted item is terminal or still outstanding — never both.
Definition diagnostics.h:485
std::uint64_t residence_ticks_accumulated
Total admission-to-terminal ticks over terminalized items.
Definition diagnostics.h:468
constexpr auto terminal() const noexcept -> std::uint64_t
Sum of every terminal outcome bucket.
Definition diagnostics.h:473
std::uint64_t outstanding_high_water
Highest simultaneous outstanding count observed.
Definition diagnostics.h:464
std::uint64_t stale
Items whose result no longer satisfies its version requirement.
Definition diagnostics.h:452
std::uint64_t rejected
Offers refused at the admission boundary.
Definition diagnostics.h:442
std::uint64_t coalesced_into_pending
Offers absorbed by an item that was already pending.
Definition diagnostics.h:444
void reset() noexcept
Returns the counters to their zero-initialized state.
Definition diagnostics.h:491
std::uint64_t dropped_after_admission
Admitted items discarded before reaching any other terminal state.
Definition diagnostics.h:456
std::uint64_t inventory_tick_weighted
Sum over observed ticks of outstanding items times elapsed ticks.
Definition diagnostics.h:466
constexpr auto admission_identity_holds() const noexcept -> bool
Every offer was admitted, rejected, or coalesced — never lost.
Definition diagnostics.h:479
std::uint64_t completed
Items that reached their intended result.
Definition diagnostics.h:446
std::uint64_t offered
Admission offers, including rejected and coalesced ones.
Definition diagnostics.h:438
Definition diagnostics.h:544
bool retention_identity_ok
Whether every admitted item is terminal or outstanding.
Definition diagnostics.h:550
FlowCounters counters
The counters at snapshot time.
Definition diagnostics.h:546
bool admission_identity_ok
Whether every offer is accounted for.
Definition diagnostics.h:548
Definition diagnostics.h:78
Definition diagnostics.h:118