StimProd,DevReattacher: use CDaemon nonviral nursery coro

We ported these two daemons over to the new nursery mechanism and
they work nicely.
This commit is contained in:
2026-06-09 19:47:44 -04:00
parent 165c846700
commit 87a8de9a2b
6 changed files with 136 additions and 124 deletions
@@ -6,13 +6,67 @@
#include <opts.h>
#include <componentThread.h>
#include <adapters/boostAsio/deadlineTimerAReq.h>
#include <spinscale/spinLock.h>
#include <user/stimulusProducer.h>
#include <user/stimulusBuffer.h>
namespace smo {
namespace stim_buff {
namespace {
long computeTimesliceResidueMs(
long productionDurationMs, long periodMs)
{
if (productionDurationMs >= periodMs) {
return 0;
}
return periodMs - productionDurationMs;
}
void logProductionOverrunIfNeeded(
const char *daemonName,
long productionDurationMs, long periodMs,
size_t &nTimesliceOverruns)
{
if (productionDurationMs <= periodMs) {
return;
}
++nTimesliceOverruns;
const long overrunByMs = productionDurationMs - periodMs;
std::cerr << daemonName << ": production overrun: actual="
<< productionDurationMs << "ms budget=" << periodMs
<< "ms overrunBy=" << overrunByMs << "ms nOverruns="
<< nTimesliceOverruns << std::endl;
}
long durationMsSince(
const std::chrono::high_resolution_clock::time_point &startStamp,
const std::chrono::high_resolution_clock::time_point &endStamp)
{
const auto duration = endStamp - startStamp;
return std::chrono::duration_cast<std::chrono::milliseconds>(
duration).count();
}
void logDaemonDurationsIfVerbose(
const char *daemonName,
long productionDurationMs,
long timesliceDurationMs,
long periodMs)
{
if (0 && !OptionParser::getOptions().verbose) {
return;
}
std::cerr << daemonName << ": daemon durations: production="
<< productionDurationMs << "ms timeslice="
<< timesliceDurationMs << "ms period=" << periodMs
<< "ms" << std::endl;
}
} // namespace
std::shared_ptr<StimulusBuffer> StimulusProducer::getAttachedStimulusBuffer(
const std::shared_ptr<device::DeviceAttachmentSpec>& spec) const
{
@@ -91,98 +145,55 @@ sscl::co::NonViralNonPostingInvoker StimulusProducer::productionCDaemon(
std::exception_ptr &, std::function<void()>,
sscl::SyncCancelerForAsyncWork &canceler)
{
int nextDelayMs = CONFIG_STIMBUFF_FRAME_PERIOD_MS;
const long framePeriodMs = CONFIG_STIMBUFF_FRAME_PERIOD_MS;
do
{
bool shouldProduceFrame = false;
if (!canceler.execUncancelableSegmentOrAbort([&]()
{
/** EXPLANATION:
* We need to ensure that there's only ever one stimframe being
* produced during any CONFIG_STIMBUFF_FRAME_PERIOD_MS period. To
* guarantee this, we use a spinlock.
*
* When a new frame is to be produced, the async producer will
* first acquire the frameAssemblyLimiter spinlock. This ensures
* that only one stimframe is produced during any
* CONFIG_STIMBUFF_FRAME_PERIOD_MS interval. When the next
* timeout fires, it checks if the previous stimframe has
* finished production. If the previous stimframe is still
* being produced, we will sleep for
* CONFIG_STIMBUFF_FRAME_RETRY_DELAY_MS ms before retrying.
*/
if (frameAssemblyRateLimiter.tryAcquire())
{
nextDelayMs = CONFIG_STIMBUFF_FRAME_PERIOD_MS;
// Check if we're ending a deferral period
if (nDeferrals > 0)
{
auto deferralEndTime =
std::chrono::high_resolution_clock::now();
auto duration = deferralEndTime - deferralStartTime;
auto durationMs = std::chrono::duration_cast<
std::chrono::milliseconds>(duration);
std::cout << "productionCDaemon: Deferral period ended. "
<< "Total deferrals: " << nDeferrals
<< ", Duration: " << durationMs.count()
<< "ms" << std::endl;
nDeferrals = 0;
}
shouldProduceFrame = true;
}
else
{
nextDelayMs = CONFIG_STIMBUFF_FRAME_RETRY_DELAY_MS;
++nDeferrals;
// If this is first deferral, capture start stamp and print message
if (nDeferrals == 1)
{
deferralStartTime =
std::chrono::high_resolution_clock::now();
std::cerr << "productionCDaemon: Deferral period "
"beginning. Configured deferral period: "
<< nextDelayMs << "ms" << std::endl;
}
}
}))
{ break; }
if (shouldProduceFrame)
{
/** EXPLANATION:
* Call the derived class's frame production handler
* Note: The derived class's frame production handler (aka
* its implementation of stimFrameProductionTimesliceCInd()) must
* release the lock when frame production completes
*/
co_await stimFrameProductionTimesliceCInd(canceler);
}
else if (OptionParser::getOptions().verbose)
{
std::cerr << "productionCDaemon: Deferring frame by "
<< nextDelayMs << "ms due to rate limit." << std::endl;
if (canceler.isCancellationRequested()) {
break;
}
// Schedule the next timeout using the provided delay
const auto timesliceStartStamp =
std::chrono::high_resolution_clock::now();
const auto productionStartStamp =
std::chrono::high_resolution_clock::now();
co_await stimFrameProductionTimesliceCInd(canceler);
const auto productionEndStamp =
std::chrono::high_resolution_clock::now();
const long productionDurationMs = durationMsSince(
productionStartStamp, productionEndStamp);
logProductionOverrunIfNeeded(
"productionCDaemon",
productionDurationMs, framePeriodMs, nTimesliceOverruns);
const long residueMs = computeTimesliceResidueMs(
productionDurationMs, framePeriodMs);
// Schedule the next timeout based on timeslice remaining time.
const bool expiredNormally = co_await
adapters::boostAsio::getDeadlineTimerAReqAwaiter(
ioContext,
daemonTimer,
boost::posix_time::milliseconds(nextDelayMs));
boost::posix_time::milliseconds(residueMs));
if (!expiredNormally) {
// Timer was cancelled, which is expected when stopping
break;
}
// FIXME: We should be able to release the start/stop lock at this point.
const auto timesliceEndStamp =
std::chrono::high_resolution_clock::now();
const long timesliceDurationMs = durationMsSince(
timesliceStartStamp, timesliceEndStamp);
logDaemonDurationsIfVerbose(
"productionCDaemon",
productionDurationMs, timesliceDurationMs,
framePeriodMs);
} while (!canceler.isCancellationRequested());
@@ -194,7 +205,7 @@ void StimulusProducer::start()
std::cout << __func__ << ": Starting stimulus producer for device "
<< deviceAttachmentSpec->deviceSelector << std::endl;
nDeferrals = 0;
nTimesliceOverruns = 0;
taskNursery.openAdmission();
taskNursery.launch(
[this](sscl::co::NonViralTaskNursery::Slot::Lease &lease)