feat: relative mode keeps the stream's absolute clock for the export

This commit is contained in:
Martino Ferrari committed 2026-10-08 17:20:47 +02:00
1 parent d11e7d48c4
commit 57e2f6aa8b
6 files changed
+87 -9

No files matched your search

+18 -2
View File
@@ -93,6 +93,11 @@ struct Partition {
double base_dt = 1.0; ///< seconds per base tick
double span_s = 0.0; ///< stream seconds one buffer covers
/// True when a second f64 ring parallel to the clock was planned and paid for in the
/// byte budget. Relative mode only -- in stream mode `time()` already *is* the absolute
/// clock and a copy would cost ~22% of the user's `--buffer-mb` for nothing.
bool abs_time = false;
/// Seconds between two time-base slots (the sample interval of every channel).
double slot_dt() const noexcept { return base_dt * static_cast<double>(time_stride); }
/// The rate samples are actually stored at, in samples per second.
@@ -109,9 +114,10 @@ struct Partition {
/// Plans a partition for `channel_dt` cadences within `buffer_bytes`, covering at least
/// `target_span_s` seconds of stream -- decimating (with the ingest filter) by whatever
/// power of two that takes. Throws std::runtime_error when the budget cannot hold even
/// one sample per channel.
/// one sample per channel. `with_abs_time` adds a second f64 per time slot to the budget
/// and sets `Partition::abs_time`.
Partition plan_partition(const std::vector<double>& channel_dt, double buffer_bytes,
double target_span_s);
double target_span_s, bool with_abs_time = false);
/// One of the two identical sample buffers: a shared time-base ring plus one
/// value ring and one `ChannelBuffer` per channel.
@@ -132,6 +138,15 @@ class BufferStore {
/// bits is plenty; a *timestamp's* is a property of how long the scope has been running.
plot::data::RingBuffer<f64>& time() noexcept { return *time_; }
const plot::data::RingBuffer<f64>& time() const noexcept { return *time_; }
/// The stream's **absolute** clock, parallel to `time()` and on the same slots, or
/// `nullptr` when the store was planned without it.
///
/// There is exactly one time ring per store, shared by every channel, and relative mode
/// fills it with counter-derived stamps -- so without this ring, selecting relative mode
/// would silently drop absolute time from an export, the one output `todo.md` item 2 says
/// must keep it. Allocated in relative mode only; read only by the export path.
plot::data::RingBuffer<f64>* abs_time() noexcept { return abs_time_.get(); }
const plot::data::RingBuffer<f64>* abs_time() const noexcept { return abs_time_.get(); }
plot::data::RingBuffer<f32>& values(std::size_t channel) { return *values_[channel]; }
ChannelBuffer& channel(std::size_t channel) { return *channels_[channel]; }
/// Shared handle to a channel view: the caller keeps the storage alive even if
@@ -147,6 +162,7 @@ class BufferStore {
private:
Partition part_;
std::shared_ptr<plot::data::RingBuffer<f64>> time_;
std::shared_ptr<plot::data::RingBuffer<f64>> abs_time_;
std::vector<std::shared_ptr<plot::data::RingBuffer<f32>>> values_;
std::vector<std::shared_ptr<ChannelBuffer>> channels_;
};