[*] Clean up grug and auasync scheduler / improved idle cpu usage

This commit is contained in:
Reece Wilson 2024-03-26 18:37:24 +00:00
parent 8a9c45c213
commit 30fa15b726
6 changed files with 84 additions and 73 deletions

View File

@ -111,11 +111,11 @@ namespace Aurora
struct AsyncConfig struct AsyncConfig
{ {
bool bStartSchedularOnStartup { true }; // turn this off to make your application lighter-weight; turn this on for higher performance (+expensive) scheduling 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. 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 threadPoolDefaultStackSize { };
AuUInt32 dwSchedulerRateLimitMS { 2 }; // AuUInt32 dwSchedulerRateLimitNS { AuMSToNS<AuUInt64>(2) }; //
AuUInt32 dwLegacyMainThreadSystemTickMS { 25 }; // nowadays this is primarily used to dispatch main-thread posted (AuConsole) commands AuUInt32 dwLegacyMainThreadSystemTickMS { 60 }; // nowadays this is primarily used to dispatch main-thread posted (AuConsole) commands
}; };
struct FIOConfig struct FIOConfig

View File

@ -81,32 +81,35 @@ namespace Aurora::Async
static void SchedNextTime(AuUInt64 uNSAbs) static void SchedNextTime(AuUInt64 uNSAbs)
{ {
if (uNextSysTickGuessed > uNSAbs || while (true)
!uNextSysTickGuessed)
{ {
while (true) auto uCurrent = AuAtomicLoad(&uNextSysTickGuessed);
{
auto uCurrent = uNextSysTickGuessed;
if (uCurrent && if (uCurrent &&
uCurrent <= uNSAbs) uCurrent <= uNSAbs)
{ {
break; return;
} }
if (uNextWakeuptimeRateLimit > uNSAbs) auto uRateLimit = AuAtomicLoad(&uNextWakeuptimeRateLimit);
{ if (uRateLimit &&
uNSAbs = uNextWakeuptimeRateLimit; 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() static void SchedThread()
@ -123,7 +126,7 @@ namespace Aurora::Async
{ {
AU_LOCK_GUARD(gSchedLock); AU_LOCK_GUARD(gSchedLock);
auto uNextTick = uNextSysTickGuessed; auto uNextTick = AuAtomicLoad(&uNextSysTickGuessed);
auto uNow = AuTime::SteadyClockNS(); auto uNow = AuTime::SteadyClockNS();
if (uNow < uNextTick) if (uNow < uNextTick)
@ -142,9 +145,13 @@ namespace Aurora::Async
0); 0);
} }
GetDispatchableTasks(pending); if (gRuntimeConfig.async.dwSchedulerRateLimitNS)
{
uNextWakeuptimeRateLimit =
AuTime::SteadyClockNS() + gRuntimeConfig.async.dwSchedulerRateLimitNS;
}
uNextWakeuptimeRateLimit = AuTime::SteadyClockNS() + AuMSToNS<AuUInt64>(gRuntimeConfig.async.dwSchedulerRateLimitMS); GetDispatchableTasks(pending);
} }
for (auto &entry : pending) for (auto &entry : pending)
@ -155,7 +162,7 @@ namespace Aurora::Async
} }
catch (...) catch (...)
{ {
Debug::PrintError(); SysPushErrorCatch();
} }
} }

View File

@ -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() bool ThreadStateSync::Init()
{ {
this->eventLs = AuLoop::NewLSAsync(); this->eventLs = AuLoop::NewLSAsync();

View File

@ -62,6 +62,9 @@ namespace Aurora::Async
struct ThreadStateBase struct ThreadStateBase
{ {
ThreadStateBase();
~ThreadStateBase();
AuWPtr<GroupState> parent; AuWPtr<GroupState> parent;
///////////////////////////////// /////////////////////////////////
ThreadStateShutdown shutdown; ThreadStateShutdown shutdown;

View File

@ -54,6 +54,10 @@ namespace Aurora::Async
void AsyncLoop::Schedule() void AsyncLoop::Schedule()
{ {
if (!this->pParent)
{
return;
}
if (AuThreads::GetThread() != this->pParent->thread.pThread.get()) if (AuThreads::GetThread() != this->pParent->thread.pThread.get())
{ {
AuAtomicAdd(&this->commitPending_, 1u); AuAtomicAdd(&this->commitPending_, 1u);

View File

@ -27,13 +27,12 @@
namespace Aurora::Grug namespace Aurora::Grug
{ {
static const auto kGrugSleepMs = 100; static const auto kGrugSleepMs = 300;
static const auto kGrugFlushMs = 500; static const auto kGrugFlushMs = 600;
static AuThreads::ThreadUnique_t gGrugsBigWorld; static AuThreads::ThreadUnique_t gGrugsBigWorld;
static AuCondMutex gMutex; // ^ that
static AuConditionVariable gCondVar(AuUnsafeRaiiToShared(gMutex.AsPointer())); // slow logger work queue
static AuSemaphore gArrows; static AuSemaphore gArrows;
static AuBinarySemaphore gArrowsRetarded(false, true, true);
static AuMutex gOtherMutex; static AuMutex gOtherMutex;
static AuList<AuPair<AuUInt, bool>> gHandlesToClose; static AuList<AuPair<AuUInt, bool>> gHandlesToClose;
static AuList<AuThreadPrimitives::IEvent *> gEventsToTrigger; static AuList<AuThreadPrimitives::IEvent *> gEventsToTrigger;
@ -46,16 +45,16 @@ namespace Aurora::Grug
// grug require only 1 strand // grug require only 1 strand
static void GrugWorld() static void GrugWorld()
{ {
// ignorerino
#if defined(AURORA_IS_LINUX_DERIVED) #if defined(AURORA_IS_LINUX_DERIVED)
LinuxSuperSecretFuckGlibc(); ::LinuxSuperSecretFuckGlibc();
#endif #endif
// grug surive first night // grug surive first night
SlowStartupTasks(); SlowStartupTasks();
AU_LOCK_GUARD(gMutex); // this thread must never encounter an out of memory condition. begin out of memory mitigations.
AuDebug::AddMemoryCrunch();
AuDebug::AddMemoryCrunch(); // this thread must never encounter an out of memory condition. begin out of memory mitigations.
Utility::RateLimiter limiter; Utility::RateLimiter limiter;
limiter.SetNextStep(AuMSToNS<AuUInt64>(kGrugFlushMs)); limiter.SetNextStep(AuMSToNS<AuUInt64>(kGrugFlushMs));
@ -63,46 +62,32 @@ namespace Aurora::Grug
// grug has cave // grug has cave
while (AuIsThreadRunning()) while (AuIsThreadRunning())
{ {
// * -> grug wake up from 100ms (kGrugSleepMs) // grug anoyd
// grug smashy alarm
gCondVar->WaitForSignal(kGrugFlushMs);
// grug anoy
if (gArrows && gArrows->TryLock())
{
// grug yeet
DequeueOneArrow();
}
// grug pump all async log messages // grug pump all async log messages
GrugFlushWrites(); GrugFlushWrites();
// adhd grug wonder around the log pool every 500ms (rate limited to 100ms sleeps) // adhd grug wonder around the log pool every 500ms (rate limited to 100ms sleeps)
if (limiter.CheckExchangePass()) if (limiter.CheckExchangePass())
{ {
// poo2loo
GrugFlushFlushs(); GrugFlushFlushs();
} }
// grug give up // grug give up
// grug yield for at least 100ms -> * // grug sleep for 100ms or until poked
if (gArrows) if (gArrowsRetarded->TryLock() ||
gArrows->LockMS(kGrugSleepMs))
{ {
// grug sleep for 100ms or until poked DequeueOneArrow();
if (gArrows->LockMS(kGrugSleepMs))
{
DequeueOneArrow();
}
}
else
{
// grug sleep 100ms
AuThreading::Sleep(kGrugSleepMs);
} }
// grug has to carry stupid platforms
#if defined(AURORA_IS_LINUX_DERIVED) #if defined(AURORA_IS_LINUX_DERIVED)
::LinuxSuperSecretIOTick(); ::LinuxSuperSecretIOTick();
#endif #endif
// grug done
GrugDoIoWork(); GrugDoIoWork();
} }
} }
@ -114,11 +99,16 @@ namespace Aurora::Grug
static void InitFlushThread() 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 // 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( gGrugsBigWorld = AuMove(AuThreads::Spawn(std::bind(GrugWorld),
AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(GrugWorld)), false,
AuThreads::IThreadVectorsFunctional::OnExit_t{}), {},
"Cave Grug" "Cave Grug"
)); ));
if (!gGrugsBigWorld) if (!gGrugsBigWorld)
@ -129,7 +119,6 @@ namespace Aurora::Grug
// he's a lazy bastard // he's a lazy bastard
gGrugsBigWorld->SetThrottle(AuThreads::EThreadThrottle::eEfficient); gGrugsBigWorld->SetThrottle(AuThreads::EThreadThrottle::eEfficient);
gGrugsBigWorld->SetPriority(AuThreads::EThreadPriority::ePrioLow); gGrugsBigWorld->SetPriority(AuThreads::EThreadPriority::ePrioLow);
gGrugsBigWorld->Run();
} }
void InitGrug() void InitGrug()
@ -152,22 +141,12 @@ namespace Aurora::Grug
void NotifyGrugOfTelemetry() void NotifyGrugOfTelemetry()
{ {
if (gArrows) gArrows->Unlock(1);
{
gArrows->Unlock(1);
}
DrachenlordScreech();
} }
void DrachenlordScreech() void DrachenlordScreech()
{ {
if (!gCondVar) gArrowsRetarded->Set();
{
return;
}
gCondVar->Signal();
} }
bool IsGrug() bool IsGrug()