feat: the status bar and the exit dump report resequencing, holes and stale packets
This commit is contained in:
1 parent
d38ab3f9c9
commit
fc81e661d0
5 files changed
+59
-2
No files matched your search
@@ -91,6 +91,9 @@ void Acquisition::run() {
|
||||
out.packets.store(s.packets_received, std::memory_order_relaxed);
|
||||
out.frames.store(s.frames_delivered, std::memory_order_relaxed);
|
||||
out.gaps.store(s.counter_gaps, std::memory_order_relaxed);
|
||||
out.resequenced.store(s.late_resequenced, std::memory_order_relaxed);
|
||||
out.late.store(s.late_delivered, std::memory_order_relaxed);
|
||||
out.stale.store(s.stale_packets, std::memory_order_relaxed);
|
||||
out.reconnects.store(s.reconnects, std::memory_order_relaxed);
|
||||
out.connected.store(udps_client_is_connected(client_) != 0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@@ -195,6 +195,21 @@ struct StreamStats {
|
||||
std::atomic<bool> have_config{false};
|
||||
std::atomic<std::uint64_t> holes{0}; ///< reserved invalidated spans
|
||||
std::atomic<std::uint64_t> hole_slots{0}; ///< stored slots those spans cover
|
||||
/// Out-of-order packets put back in order inside the reorder window: no hole was ever
|
||||
/// seen for these.
|
||||
std::atomic<std::uint64_t> resequenced{0};
|
||||
/// Out-of-order packets delivered behind the sequence, past the window.
|
||||
std::atomic<std::uint64_t> late{0};
|
||||
/// Packets the client still refused outright (a duplicate, or any late packet while
|
||||
/// resequencing is disabled). Counted since the beginning and displayed nowhere until
|
||||
/// now, which is why an inversion had to be inferred from `packets` and `frames`
|
||||
/// diverging.
|
||||
std::atomic<std::uint64_t> stale{0};
|
||||
/// Stored slots a late packet repaired. Declared here rather than with the backfill that
|
||||
/// writes it, because the display segment below is built once and reads it from the start:
|
||||
/// a reading of 0 beside a non-zero `holes` is exactly the honest answer until the
|
||||
/// backfill lands.
|
||||
std::atomic<std::uint64_t> backfilled{0};
|
||||
};
|
||||
|
||||
/// What the plot is showing, which is one decision made once per frame: the bind, the
|
||||
|
||||
@@ -79,6 +79,21 @@ std::string format_detail(const StatusSnapshot& s) {
|
||||
s.plot1_traces, s.plot1_samples, s.buffer_mb, s.span_s,
|
||||
static_cast<unsigned long long>(s.time_stride));
|
||||
std::string out = buf;
|
||||
// Nothing about resequencing is said at all while all six read zero, which is a stream that
|
||||
// never lost ordering: the field would otherwise be six zeros on every clean run, and this
|
||||
// string is read by eye out of the exit dump.
|
||||
if (s.resequenced || s.late || s.stale || s.holes || s.hole_slots || s.backfilled) {
|
||||
char note[160];
|
||||
std::snprintf(note, sizeof(note),
|
||||
" | reseq %llu late %llu stale %llu holes %llu (%llu slots, %llu filled)",
|
||||
static_cast<unsigned long long>(s.resequenced),
|
||||
static_cast<unsigned long long>(s.late),
|
||||
static_cast<unsigned long long>(s.stale),
|
||||
static_cast<unsigned long long>(s.holes),
|
||||
static_cast<unsigned long long>(s.hole_slots),
|
||||
static_cast<unsigned long long>(s.backfilled));
|
||||
out += note;
|
||||
}
|
||||
if (s.paused) out += " | paused for " + format_elapsed(s.paused_for_s);
|
||||
if (s.trigger_on) {
|
||||
out += s.have_event ? " | last event " + format_elapsed(s.since_event_s) + " ago"
|
||||
|
||||
@@ -56,6 +56,16 @@ struct StatusSnapshot {
|
||||
/// the plot.
|
||||
bool paused = false;
|
||||
double paused_for_s = 0.0;
|
||||
|
||||
/// The resequencing counters, gathered with `packets`/`frames`/`gaps` so the detail tier and
|
||||
/// the dump quote one consistent set. All six zero means the stream never lost ordering, and
|
||||
/// the detail tier then says nothing about it at all.
|
||||
std::uint64_t resequenced = 0;
|
||||
std::uint64_t late = 0;
|
||||
std::uint64_t stale = 0;
|
||||
std::uint64_t holes = 0;
|
||||
std::uint64_t hole_slots = 0;
|
||||
std::uint64_t backfilled = 0;
|
||||
};
|
||||
|
||||
/// The bar: "live · 10 kS/s · 2 s window", plus " · event 4.2 s ago" in trigger mode, " · for
|
||||
|
||||
+16
-2
@@ -6898,6 +6898,12 @@ gboolean tick(gpointer user) {
|
||||
snap.packets = st.packets.load();
|
||||
snap.frames = st.frames.load();
|
||||
snap.gaps = st.gaps.load();
|
||||
snap.resequenced = st.resequenced.load();
|
||||
snap.late = st.late.load();
|
||||
snap.stale = st.stale.load();
|
||||
snap.holes = st.holes.load();
|
||||
snap.hole_slots = st.hole_slots.load();
|
||||
snap.backfilled = st.backfilled.load();
|
||||
snap.signals = signal_count;
|
||||
snap.channels = channel_count;
|
||||
snap.plot1_traces = bound;
|
||||
@@ -10718,12 +10724,20 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
||||
if (exit_after_ms > 0.0) {
|
||||
const Partition& part = model.partition();
|
||||
std::printf("[udpscope] frames=%llu packets=%llu gaps=%llu channels=%zu span=%.3fs "
|
||||
"stride=%llu\n",
|
||||
"stride=%llu"
|
||||
" reseq=%llu late=%llu stale=%llu holes=%llu hole_slots=%llu backfilled=%llu"
|
||||
"\n",
|
||||
static_cast<unsigned long long>(model.stats().frames.load()),
|
||||
static_cast<unsigned long long>(model.stats().packets.load()),
|
||||
static_cast<unsigned long long>(model.stats().gaps.load()),
|
||||
model.channel_count(), part.span_s,
|
||||
static_cast<unsigned long long>(part.time_stride));
|
||||
static_cast<unsigned long long>(part.time_stride),
|
||||
static_cast<unsigned long long>(model.stats().resequenced.load()),
|
||||
static_cast<unsigned long long>(model.stats().late.load()),
|
||||
static_cast<unsigned long long>(model.stats().stale.load()),
|
||||
static_cast<unsigned long long>(model.stats().holes.load()),
|
||||
static_cast<unsigned long long>(model.stats().hole_slots.load()),
|
||||
static_cast<unsigned long long>(model.stats().backfilled.load()));
|
||||
for (std::size_t i = 0; i < model.channel_count(); ++i) {
|
||||
std::printf("[udpscope] channel %zu '%s' stored=%llu published=%llu\n", i,
|
||||
model.channels()[i].name.c_str(),
|
||||
|
||||
Reference in new issue
Block a user