[*] Clean up grug and auasync scheduler / improved idle cpu usage
This commit is contained in:
parent
8a9c45c213
commit
30fa15b726
@ -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
|
||||||
|
@ -80,23 +80,27 @@ namespace Aurora::Async
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SchedNextTime(AuUInt64 uNSAbs)
|
static void SchedNextTime(AuUInt64 uNSAbs)
|
||||||
{
|
|
||||||
if (uNextSysTickGuessed > uNSAbs ||
|
|
||||||
!uNextSysTickGuessed)
|
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
auto uCurrent = uNextSysTickGuessed;
|
auto uCurrent = AuAtomicLoad(&uNextSysTickGuessed);
|
||||||
|
|
||||||
if (uCurrent &&
|
if (uCurrent &&
|
||||||
uCurrent <= uNSAbs)
|
uCurrent <= uNSAbs)
|
||||||
{
|
{
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uNextWakeuptimeRateLimit > uNSAbs)
|
auto uRateLimit = AuAtomicLoad(&uNextWakeuptimeRateLimit);
|
||||||
|
if (uRateLimit &&
|
||||||
|
uRateLimit > uNSAbs)
|
||||||
{
|
{
|
||||||
uNSAbs = uNextWakeuptimeRateLimit;
|
uNSAbs = uRateLimit;
|
||||||
|
|
||||||
|
if (uRateLimit == uCurrent)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AuAtomicCompareExchange(&uNextSysTickGuessed, uNSAbs, uCurrent) == uCurrent)
|
if (AuAtomicCompareExchange(&uNextSysTickGuessed, uNSAbs, uCurrent) == uCurrent)
|
||||||
@ -107,7 +111,6 @@ namespace Aurora::Async
|
|||||||
|
|
||||||
gSchedCondvar->Signal();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -62,6 +62,9 @@ namespace Aurora::Async
|
|||||||
|
|
||||||
struct ThreadStateBase
|
struct ThreadStateBase
|
||||||
{
|
{
|
||||||
|
ThreadStateBase();
|
||||||
|
~ThreadStateBase();
|
||||||
|
|
||||||
AuWPtr<GroupState> parent;
|
AuWPtr<GroupState> parent;
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
ThreadStateShutdown shutdown;
|
ThreadStateShutdown shutdown;
|
||||||
|
@ -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);
|
||||||
|
@ -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,16 +62,7 @@ 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();
|
||||||
@ -80,29 +70,24 @@ namespace Aurora::Grug
|
|||||||
// 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 -> *
|
|
||||||
if (gArrows)
|
|
||||||
{
|
|
||||||
// grug sleep for 100ms or until poked
|
// grug sleep for 100ms or until poked
|
||||||
if (gArrows->LockMS(kGrugSleepMs))
|
if (gArrowsRetarded->TryLock() ||
|
||||||
|
gArrows->LockMS(kGrugSleepMs))
|
||||||
{
|
{
|
||||||
DequeueOneArrow();
|
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,10 +99,15 @@ 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"
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -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()
|
||||||
@ -151,23 +140,13 @@ 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()
|
||||||
|
Loading…
Reference in New Issue
Block a user