From 039586e853450fdb75c5a6fce90699c157993971 Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Tue, 5 May 2026 22:20:18 -0700 Subject: [PATCH] ultramodern: add external-requeue counter + accessor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Counts requeues at the three sites in dequeue_external_messages, wait_for_external_message, and wait_for_external_message_timed. A sustained nonzero rate means a target OSMesgQueue is being overrun — the existing requeue mechanism prevents a softlock, but the underlying receiver-thread starvation is worth investigating, so giving runners a way to observe it is useful. Adds: - static std::atomic g_external_requeues - extern "C" uint64_t ultramodern_external_requeues(void) accessor - fetch_add at each of the three requeue sites (one bulk-add for the dequeue path which collects then bulk-requeues, single-adds for the two wait paths which requeue inline) Zero impact on the hot path. Atomics fire only when the requeue path fires; in normal operation that's never. The dequeue site uses a single bulk fetch_add for the whole batch instead of N individual adds. Co-Authored-By: Claude Opus 4.7 (1M context) --- ultramodern/src/mesgqueue.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ultramodern/src/mesgqueue.cpp b/ultramodern/src/mesgqueue.cpp index 9944a02..7714b8f 100644 --- a/ultramodern/src/mesgqueue.cpp +++ b/ultramodern/src/mesgqueue.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -16,6 +17,18 @@ struct QueuedMessage { static moodycamel::BlockingConcurrentQueue external_messages {}; std::bitset<32> requeue_enabled; +// Counter for how many external messages have been re-queued because +// their target OSMesgQueue was full at dequeue time. Bumped at the +// three requeue sites in dequeue_external_messages, +// wait_for_external_message, and wait_for_external_message_timed. A +// sustained nonzero rate indicates a target queue is being overrun +// (receiver thread starved); useful for runner-side observability. +static std::atomic g_external_requeues{0}; + +extern "C" uint64_t ultramodern_external_requeues(void) { + return g_external_requeues.load(std::memory_order_relaxed); +} + void ultramodern::set_message_queue_control(const ultramodern::MessageQueueControl& mqc) { requeue_enabled.reset(); requeue_enabled.set(static_cast(EventMessageSource::Timer), mqc.requeue_timer); @@ -45,8 +58,11 @@ void dequeue_external_messages(RDRAM_ARG1) { requeued_messages.push_back(to_send); } } - for (QueuedMessage& cur_mesg : requeued_messages) { - external_messages.enqueue(cur_mesg); + if (!requeued_messages.empty()) { + g_external_requeues.fetch_add(requeued_messages.size(), std::memory_order_relaxed); + for (QueuedMessage& cur_mesg : requeued_messages) { + external_messages.enqueue(cur_mesg); + } } } @@ -54,6 +70,7 @@ void ultramodern::wait_for_external_message(RDRAM_ARG1) { QueuedMessage to_send; external_messages.wait_dequeue(to_send); if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) { + g_external_requeues.fetch_add(1, std::memory_order_relaxed); external_messages.enqueue(to_send); } } @@ -62,6 +79,7 @@ void ultramodern::wait_for_external_message_timed(RDRAM_ARG u32 millis) { QueuedMessage to_send; if (external_messages.wait_dequeue_timed(to_send, std::chrono::milliseconds{millis})) { if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) { + g_external_requeues.fetch_add(1, std::memory_order_relaxed); external_messages.enqueue(to_send); } }