fix(data): level-per-emission pyramid cover, relaxed-atomic ring slots

cover_buckets chose one level per pass, so an odd first whole bucket (half of all

measurement ranges) never reached a level above 0 and folded every remaining

bucket at level 0 -- 15624 entries for a 1e6-sample pyramid. Pick the largest

aligned, in-range, materialised level at each cursor instead; the new cost test

counts folded entries through a PLOT_PYRAMID_COUNT_COVERS-only hook (absent from

normal builds) and fails on the old body.

Ring slots are now relaxed std::atomic: overwrite-on-full means the producer

reuses the slot of a snapshot's oldest sample while the consumer reads it, which

was a data race, not just a stale value. copy_from loads explicitly instead of

std::copy; push stays lock-free. A new producer/consumer case is the one TSan

flags without this.

Also extends the wrapped-window test with x0/bounds/pyramid/sum/sumsq/gather

checks, and corrects the StreamSeries threading note to the sample-count bound.
This commit is contained in:
Martino Ferrari committed 2026-09-27 21:42:53 +02:00
1 parent 138fa478c3
commit d9909f2115
8 files changed
+190 -38

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
#pragma once
#ifdef PLOT_PYRAMID_COUNT_COVERS
#include <atomic>
#include <plot/core/types.hpp>
namespace plot::data::detail {
/// Test-only instrumentation. Counts the pyramid entries the covering
/// decomposition has emitted since the counter was last reset.
///
/// The decomposition's *cost* is invisible in every answer -- a decomposition
/// that walks the range one level-0 bucket at a time returns exactly the same
/// min/max/sum as the O(log n) one -- so a test that wants to pin "at most two
/// entries per level" has to count entries. The counter exists only when
/// PLOT_PYRAMID_COUNT_COVERS is defined (the test build defines it), so every
/// normal build carries no counter and no increment on the query path.
///
/// Not part of the query surface and not meant for production use.
inline std::atomic<u64>& cover_entry_count() {
static std::atomic<u64> count{0};
return count;
}
} // namespace plot::data::detail
#endif // PLOT_PYRAMID_COUNT_COVERS