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

+6 -1
View File
@@ -22,6 +22,8 @@ else()
"or mesa-libEGL-devel) or configure with -DPLOT_BUILD_TESTS=OFF.")
endif()
find_package(Threads REQUIRED) # std::thread in the push/read race test
add_executable(plot_tests
main.cpp
test_transform.cpp
@@ -31,7 +33,10 @@ add_executable(plot_tests
test_series.cpp
egl_headless.cpp
)
target_link_libraries(plot_tests PRIVATE plot::core ${plot_egl_library})
target_link_libraries(plot_tests PRIVATE plot::core ${plot_egl_library} Threads::Threads)
# Same switch the library is built with: the decomposition-cost test reads the
# counter behind it (see include/plot/data/detail/cover_count.hpp).
target_compile_definitions(plot_tests PRIVATE PLOT_PYRAMID_COUNT_COVERS)
plot_apply_warnings(plot_tests)
add_test(NAME plot_tests COMMAND plot_tests)