#pragma once #ifdef PLOT_RING_STATS #include #include namespace plot::render::detail { /// Test-only instrumentation for the persistent-mapped instance ring (see /// `InstanceStore`). Every counter exists only when PLOT_RING_STATS is defined /// -- the test build defines it, on the library and on the suite -- and none of /// them is a data member of any class, so a consumer compiled without the macro /// still lays `InstanceStore` out identically. No other build carries a counter /// or an increment on the upload, frame or wait path. /// /// The properties they pin are invisible in the pixels a frame draws: a ring that /// syncs mid-frame rasterises exactly what one that does not does, and a ring that /// recycles a slot within a frame draws correctly until the GPU happens to be /// slower than the CPU. So `InstanceStore` counts /// /// * `ring_uploads()` -- one per upload, i.e. a frame's upload count; /// * `ring_waits()` -- one per fence wait. At most one per store per frame: /// the wait is at the start of the frame, on the previous frame's fence; /// * `ring_slots()` -- the largest ring any store has grown to, which must /// cover the uploads a frame performs. /// /// They are process-global rather than per-store because a test that drives one /// `InstanceStore` reads them directly; a test that drives the whole `Renderer` /// reads the aggregate, where there are two stores and so at most two waits a /// frame. /// /// Not part of any query surface and not meant for production use. inline std::atomic& ring_uploads() { static std::atomic count{0}; return count; } inline std::atomic& ring_waits() { static std::atomic count{0}; return count; } inline std::atomic& ring_slots() { static std::atomic count{0}; return count; } /// Records `slots` as the ring's largest size so far. A compare-exchange loop /// rather than a store because two stores report into one counter. inline void note_ring_slots(u64 slots) noexcept { std::atomic& count = ring_slots(); u64 largest = count.load(std::memory_order_relaxed); while (largest < slots && !count.compare_exchange_weak(largest, slots, std::memory_order_relaxed)) { } } } // namespace plot::render::detail #endif // PLOT_RING_STATS