From a201f1791d2231ec3d4e4c66272e6f4b7317fa1e Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 12 Nov 2026 19:22:45 +0100 Subject: [PATCH] receiver: stills live counts a frame as received before it takes a slot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The live status's images_received, the frame rate and the end latency of a stills collection ran from StillsGPUAnalysis::Hold, which only sees the frames that got a slot of the image buffer: a frame dropped at a full buffer was not counted, so after a loss the "N / M ยท Hz" header and the latency figure ran from the last frame rugnux kept, not the last frame the detector sent. The receiver now reports the frame to the live status in OnImage, before the slot is taken, as the rotation receiver does; the drop itself is unchanged. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01HVeDQsU5a8AJUdJPgWevAK --- receiver/JFJochReceiverRugnuxStills.cpp | 1 + receiver/StillsGPUAnalysis.cpp | 1 - tests/StillsGPUAnalysisTest.cpp | 4 +++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/receiver/JFJochReceiverRugnuxStills.cpp b/receiver/JFJochReceiverRugnuxStills.cpp index 511335781..b82734d14 100644 --- a/receiver/JFJochReceiverRugnuxStills.cpp +++ b/receiver/JFJochReceiverRugnuxStills.cpp @@ -66,6 +66,7 @@ void JFJochReceiverRugnuxStills::OnImage(uint32_t id, DataMessage &message, std: logger.Error("Dropping image {} - the collection has {} images", message.number, experiment.GetImageNum()); return; } + live_status.ImageReceived(received); CountImage(message); const size_t size = message.image.GetCompressedSize(); diff --git a/receiver/StillsGPUAnalysis.cpp b/receiver/StillsGPUAnalysis.cpp index 65721f92c..cd8e5328f 100644 --- a/receiver/StillsGPUAnalysis.cpp +++ b/receiver/StillsGPUAnalysis.cpp @@ -67,7 +67,6 @@ void StillsGPUAnalysis::Publish() { } void StillsGPUAnalysis::Hold(const std::shared_ptr &image) { - status.ImageReceived(std::chrono::steady_clock::now()); queue.PutBlocking(image); { std::unique_lock ul(prepass_mutex); diff --git a/tests/StillsGPUAnalysisTest.cpp b/tests/StillsGPUAnalysisTest.cpp index 23c44e234..bacdfa9b2 100644 --- a/tests/StillsGPUAnalysisTest.cpp +++ b/tests/StillsGPUAnalysisTest.cpp @@ -114,8 +114,10 @@ TEST_CASE("StillsGPUAnalysis_FailingFrameDoesNotStopAnalysis", "[StillsGPUAnalys }; StillsGPUAnalysis gpu(x, mask, Start(x), nullptr, 1, 100, logger, sink, status); // The frames carry no image, so their analysis fails too - they are passed on all the same. - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { + status.ImageReceived(std::chrono::steady_clock::now()); // as the receiver does before it holds a frame gpu.Hold(Frame(buffer, i)); + } REQUIRE_NOTHROW(gpu.Finish()); CHECK(sunk == 3); // The outcome waits for everything to be written, and comes after the latency.