From 30fa15b7267eb9851cf79b0303d1bdb3cb2a0886 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Tue, 26 Mar 2024 18:37:24 +0000 Subject: [PATCH] [*] Clean up grug and auasync scheduler / improved idle cpu usage --- Include/Aurora/RuntimeConfig.hpp | 8 +-- Source/Async/AuSchedular.cpp | 49 +++++++++-------- Source/Async/AuThreadState.cpp | 18 +++++++ Source/Async/AuThreadState.hpp | 3 ++ Source/Async/ThreadWorkerQueueShim.cpp | 4 ++ Source/Grug/AuGrug.cpp | 75 ++++++++++---------------- 6 files changed, 84 insertions(+), 73 deletions(-) diff --git a/Include/Aurora/RuntimeConfig.hpp b/Include/Aurora/RuntimeConfig.hpp index 04f62da8..57def1cc 100644 --- a/Include/Aurora/RuntimeConfig.hpp +++ b/Include/Aurora/RuntimeConfig.hpp @@ -111,11 +111,11 @@ namespace Aurora struct AsyncConfig { - bool bStartSchedularOnStartup { true }; // turn this off to make your application lighter-weight; turn this on for higher performance (+expensive) scheduling - bool bEnableLegacyTicks { false }; // turn this on to enable an async apps singleton threadpool to SysPump on worker id zero. Alternatively, use SetMainThreadForSysPumpScheduling once you have a thread pool and worker id. + bool bStartSchedularOnStartup { true }; // spawns the sched thread during the runtime initialization process, otherwise delegate it until the last min + bool bEnableLegacyTicks { false }; // turn this on to enable an async apps singleton threadpool to SysPump on worker id zero. Alternatively, use SetMainThreadForSysPumpScheduling once you have a thread pool and worker id. AuUInt32 threadPoolDefaultStackSize { }; - AuUInt32 dwSchedulerRateLimitMS { 2 }; // - AuUInt32 dwLegacyMainThreadSystemTickMS { 25 }; // nowadays this is primarily used to dispatch main-thread posted (AuConsole) commands + AuUInt32 dwSchedulerRateLimitNS { AuMSToNS(2) }; // + AuUInt32 dwLegacyMainThreadSystemTickMS { 60 }; // nowadays this is primarily used to dispatch main-thread posted (AuConsole) commands }; struct FIOConfig diff --git a/Source/Async/AuSchedular.cpp b/Source/Async/AuSchedular.cpp index 111e6393..e5769ce2 100644 --- a/Source/Async/AuSchedular.cpp +++ b/Source/Async/AuSchedular.cpp @@ -81,32 +81,35 @@ namespace Aurora::Async static void SchedNextTime(AuUInt64 uNSAbs) { - if (uNextSysTickGuessed > uNSAbs || - !uNextSysTickGuessed) + while (true) { - while (true) - { - auto uCurrent = uNextSysTickGuessed; + auto uCurrent = AuAtomicLoad(&uNextSysTickGuessed); - if (uCurrent && - uCurrent <= uNSAbs) - { - break; - } + if (uCurrent && + uCurrent <= uNSAbs) + { + return; + } - if (uNextWakeuptimeRateLimit > uNSAbs) - { - uNSAbs = uNextWakeuptimeRateLimit; - } + auto uRateLimit = AuAtomicLoad(&uNextWakeuptimeRateLimit); + if (uRateLimit && + uRateLimit > uNSAbs) + { + uNSAbs = uRateLimit; - if (AuAtomicCompareExchange(&uNextSysTickGuessed, uNSAbs, uCurrent) == uCurrent) + if (uRateLimit == uCurrent) { - break; + return; } } - gSchedCondvar->Signal(); + if (AuAtomicCompareExchange(&uNextSysTickGuessed, uNSAbs, uCurrent) == uCurrent) + { + break; + } } + + gSchedCondvar->Signal(); } static void SchedThread() @@ -123,7 +126,7 @@ namespace Aurora::Async { AU_LOCK_GUARD(gSchedLock); - auto uNextTick = uNextSysTickGuessed; + auto uNextTick = AuAtomicLoad(&uNextSysTickGuessed); auto uNow = AuTime::SteadyClockNS(); if (uNow < uNextTick) @@ -142,9 +145,13 @@ namespace Aurora::Async 0); } - GetDispatchableTasks(pending); + if (gRuntimeConfig.async.dwSchedulerRateLimitNS) + { + uNextWakeuptimeRateLimit = + AuTime::SteadyClockNS() + gRuntimeConfig.async.dwSchedulerRateLimitNS; + } - uNextWakeuptimeRateLimit = AuTime::SteadyClockNS() + AuMSToNS(gRuntimeConfig.async.dwSchedulerRateLimitMS); + GetDispatchableTasks(pending); } for (auto &entry : pending) @@ -155,7 +162,7 @@ namespace Aurora::Async } catch (...) { - Debug::PrintError(); + SysPushErrorCatch(); } } diff --git a/Source/Async/AuThreadState.cpp b/Source/Async/AuThreadState.cpp index f09e0013..33cf1ce6 100644 --- a/Source/Async/AuThreadState.cpp +++ b/Source/Async/AuThreadState.cpp @@ -18,6 +18,24 @@ namespace Aurora::Async { } + ThreadStateBase::ThreadStateBase() + { + + } + + ThreadStateBase::~ThreadStateBase() + { + if (this->asyncLoop) + { + this->asyncLoop->pParent = nullptr; + + if (this->asyncLoop) + { + (void)this->asyncLoop->SourceRemove(this->sync.eventLs); + } + } + } + bool ThreadStateSync::Init() { this->eventLs = AuLoop::NewLSAsync(); diff --git a/Source/Async/AuThreadState.hpp b/Source/Async/AuThreadState.hpp index 52893231..de42fd34 100644 --- a/Source/Async/AuThreadState.hpp +++ b/Source/Async/AuThreadState.hpp @@ -62,6 +62,9 @@ namespace Aurora::Async struct ThreadStateBase { + ThreadStateBase(); + ~ThreadStateBase(); + AuWPtr parent; ///////////////////////////////// ThreadStateShutdown shutdown; diff --git a/Source/Async/ThreadWorkerQueueShim.cpp b/Source/Async/ThreadWorkerQueueShim.cpp index 2bf3780a..0145cda9 100644 --- a/Source/Async/ThreadWorkerQueueShim.cpp +++ b/Source/Async/ThreadWorkerQueueShim.cpp @@ -54,6 +54,10 @@ namespace Aurora::Async void AsyncLoop::Schedule() { + if (!this->pParent) + { + return; + } if (AuThreads::GetThread() != this->pParent->thread.pThread.get()) { AuAtomicAdd(&this->commitPending_, 1u); diff --git a/Source/Grug/AuGrug.cpp b/Source/Grug/AuGrug.cpp index 7e863736..f0870bdc 100644 --- a/Source/Grug/AuGrug.cpp +++ b/Source/Grug/AuGrug.cpp @@ -27,13 +27,12 @@ namespace Aurora::Grug { - static const auto kGrugSleepMs = 100; - static const auto kGrugFlushMs = 500; + static const auto kGrugSleepMs = 300; + static const auto kGrugFlushMs = 600; static AuThreads::ThreadUnique_t gGrugsBigWorld; - static AuCondMutex gMutex; // ^ that - static AuConditionVariable gCondVar(AuUnsafeRaiiToShared(gMutex.AsPointer())); // slow logger work queue static AuSemaphore gArrows; + static AuBinarySemaphore gArrowsRetarded(false, true, true); static AuMutex gOtherMutex; static AuList> gHandlesToClose; static AuList gEventsToTrigger; @@ -46,16 +45,16 @@ namespace Aurora::Grug // grug require only 1 strand static void GrugWorld() { + // ignorerino #if defined(AURORA_IS_LINUX_DERIVED) - LinuxSuperSecretFuckGlibc(); + ::LinuxSuperSecretFuckGlibc(); #endif // grug surive first night SlowStartupTasks(); - AU_LOCK_GUARD(gMutex); - - AuDebug::AddMemoryCrunch(); // this thread must never encounter an out of memory condition. begin out of memory mitigations. + // this thread must never encounter an out of memory condition. begin out of memory mitigations. + AuDebug::AddMemoryCrunch(); Utility::RateLimiter limiter; limiter.SetNextStep(AuMSToNS(kGrugFlushMs)); @@ -63,46 +62,32 @@ namespace Aurora::Grug // grug has cave while (AuIsThreadRunning()) { - // * -> grug wake up from 100ms (kGrugSleepMs) - // grug smashy alarm - gCondVar->WaitForSignal(kGrugFlushMs); - - // grug anoy - if (gArrows && gArrows->TryLock()) - { - // grug yeet - DequeueOneArrow(); - } - + // grug anoyd + // grug pump all async log messages GrugFlushWrites(); // adhd grug wonder around the log pool every 500ms (rate limited to 100ms sleeps) if (limiter.CheckExchangePass()) { + // poo2loo GrugFlushFlushs(); } // grug give up - // grug yield for at least 100ms -> * - if (gArrows) + // grug sleep for 100ms or until poked + if (gArrowsRetarded->TryLock() || + gArrows->LockMS(kGrugSleepMs)) { - // grug sleep for 100ms or until poked - if (gArrows->LockMS(kGrugSleepMs)) - { - DequeueOneArrow(); - } - } - else - { - // grug sleep 100ms - AuThreading::Sleep(kGrugSleepMs); + DequeueOneArrow(); } + // grug has to carry stupid platforms #if defined(AURORA_IS_LINUX_DERIVED) ::LinuxSuperSecretIOTick(); #endif + // grug done GrugDoIoWork(); } } @@ -114,11 +99,16 @@ namespace Aurora::Grug static void InitFlushThread() { + if (gGrugsBigWorld) + { + return; + } + // Startup a runner thread that will take care of all the stress of triggering IO every so often on a remote thread - gGrugsBigWorld = AuThreads::ThreadUnique(AuThreads::ThreadInfo( - AuMakeShared(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(GrugWorld)), - AuThreads::IThreadVectorsFunctional::OnExit_t{}), - "Cave Grug" + gGrugsBigWorld = AuMove(AuThreads::Spawn(std::bind(GrugWorld), + false, + {}, + "Cave Grug" )); if (!gGrugsBigWorld) @@ -129,7 +119,6 @@ namespace Aurora::Grug // he's a lazy bastard gGrugsBigWorld->SetThrottle(AuThreads::EThreadThrottle::eEfficient); gGrugsBigWorld->SetPriority(AuThreads::EThreadPriority::ePrioLow); - gGrugsBigWorld->Run(); } void InitGrug() @@ -152,22 +141,12 @@ namespace Aurora::Grug void NotifyGrugOfTelemetry() { - if (gArrows) - { - gArrows->Unlock(1); - } - - DrachenlordScreech(); + gArrows->Unlock(1); } void DrachenlordScreech() { - if (!gCondVar) - { - return; - } - - gCondVar->Signal(); + gArrowsRetarded->Set(); } bool IsGrug()