AuroraRuntime/Source/HWInfo/AuCoreLoadSampler.cpp
Jamie Reece Wilson c64cb0c0e2 [+] AuHWInfo::ICoreLoadSampler
[+] AuHWInfo::CpuCoreTime
[+] AuHWInfo::GetPerCoreCPUTime
2023-12-31 23:14:27 +00:00

232 lines
6.5 KiB
C++

/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuCoreLoadSampler.cpp
Date: 2023-12-30
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuCoreLoadSampler.hpp"
namespace Aurora::HWInfo
{
static CoreLoadSamplerImpl gDefaultCoreUsageSampler(AuSToMS<AuUInt32>(1), true);
CoreLoadSamplerImpl::CoreLoadSamplerImpl(AuUInt32 uMinSamplePeriodMS,
bool bCountKernelUsage) :
uMinSamplePeriod(uMinSamplePeriodMS),
bCountKernelUsage(bCountKernelUsage)
{
}
CoreLoadSamplerImpl::~CoreLoadSamplerImpl()
{
}
double CoreLoadSamplerImpl::GetCoreLoad(AuUInt8 uCore)
{
return this->state.GetLoad(this->uMinSamplePeriod,
uCore,
this->bCountKernelUsage);
}
double CoreLoadSamplerImpl::GetCoreLoadCached(AuUInt8 uCore)
{
if (uCore >= AuArraySize(this->state.dCurrentLoad))
{
return 0.0f;
}
return this->state.dCurrentLoad[uCore];
}
double CoreLoadSamplerImpl::GetTotalLoad()
{
(void)this->GetCoreLoad(0);
return this->GetTotalLoadCached();
}
double CoreLoadSamplerImpl::GetTotalLoadCached()
{
return this->state.dCurrentLoadAll;
}
double CoreLoadSamplerState::GetLoad(AuUInt32 uMinSamplePeriod,
AuUInt8 uThread,
bool bCountKernelUsage)
{
AuUInt64 uCurrentTimes[256] {};
AuUInt64 uNow {};
double dDeltaCore[256];
double dAverage {}, dDeltaSteady {};
AuList<CpuCoreTime> times;
double dUsage[256] { 0.0f };
double dMinSamplePeriod = double(AuMSToNS<AuUInt64>(uMinSamplePeriod));
if (!GetPerCoreCPUTime(times))
{
return 0;
}
uNow = AuTime::SteadyClockNS();
dDeltaSteady = uNow - this->uPrevSteadyTime;
if (!this->uCount)
{
auto uThreads = GetCPUInfo().uThreads;
this->uCount = AuMin(uThreads, AuArraySize(uCurrentTimes));
this->uCount = AuMin(this->uCount, times.size());
}
for (AU_ITERATE_N(i, this->uCount))
{
if (times.size() > i)
{
if (bCountKernelUsage)
{
uCurrentTimes[i] = times[i].uUptime;
}
else
{
uCurrentTimes[i] = times[i].uUserTime;
}
}
dDeltaCore[i] = uCurrentTimes[i] - this->uPrevTimes[i];
}
if (!bool(this->uPrevSteadyTime))
{
this->uPrevSteadyTime = uNow;
AuMemcpy(this->uPrevTimes, uCurrentTimes, sizeof(uCurrentTimes));
return 0;
}
if (!uMinSamplePeriod ||
(dDeltaSteady >= dMinSamplePeriod))
{
AuMemcpy(this->uPrevTimes, uCurrentTimes, sizeof(uCurrentTimes));
this->uPrevSteadyTime = uNow;
this->bSet = true;
for (AU_ITERATE_N(i, this->uCount))
{
dUsage[i] = dDeltaCore[i] / dDeltaSteady;
if (uMinSamplePeriod)
{
if (dUsage[i] > AuNumericLimits<double>::epsilon() &&
this->dPrevLoad[i] > AuNumericLimits<double>::epsilon())
{
dUsage[i] = AuMin(dUsage[i], dUsage[i] + this->dPrevLoad[i] / 2.0);
}
else
{
dUsage[i] = AuMax(this->dPrevLoad[i] / 2.0, 0.0001);
}
}
else if (!dUsage)
{
dUsage[i] = AuMax(this->dPrevLoad[i] / 2.0, 0.0001);
}
this->dPrevLoad[i] = dUsage[i];
}
}
else
{
for (AU_ITERATE_N(i, this->uCount))
{
if (dDeltaCore[i])
{
dUsage[i] = dDeltaCore[i] / dDeltaSteady;
if (this->bSet)
{
#if 0
dUsage[i] *= dDeltaSteady / double(dMinSamplePeriod);
if (this->dPrevLoad[i]) dUsage[i] = dUsage[i] + this->dPrevLoad[i] / 2.0;
#else
if (this->dPrevLoad[i])
{
auto dFrameDelta = dDeltaSteady / dMinSamplePeriod;
auto dFrameDeltaInverse = 1.0 - dFrameDelta;
dUsage[i] *= dFrameDelta;
dUsage[i] += this->dPrevLoad[i] * dFrameDeltaInverse;
}
else
{
dUsage[i] *= dDeltaSteady / dMinSamplePeriod;
}
#endif
}
}
else
{
dUsage[i] = this->dPrevLoad[i];
}
}
}
for (AU_ITERATE_N(i, this->uCount))
{
dUsage[i] = dUsage[i] * 100.0;
if (dUsage[i] > 100.0)
{
dUsage[i] = 100.0;
}
else if (dUsage[i] < 0.0)
{
dUsage[i] = 0.0;
}
dAverage += dUsage[i];
}
dAverage /= this->uCount;
this->dCurrentLoadAll = dAverage;
AuMemcpy(this->dCurrentLoad, dUsage, sizeof(dUsage));
if (uThread >= AuArraySize(dUsage))
{
return 0;
}
else
{
return dUsage[uThread];
}
}
double *CoreLoadSamplerImpl::GetCoreLoadsCached(AuUInt32 *pOut)
{
if (!this->state.uCount ||
!pOut)
{
return nullptr;
}
*pOut = this->state.uCount;
return this->state.dCurrentLoad;
}
AUKN_SYM ICoreLoadSampler *CoreLoadSamplerNew(AuUInt32 uMinSamplePeriodMS,
bool bCountKernelUsage)
{
return _new CoreLoadSamplerImpl(uMinSamplePeriodMS, bCountKernelUsage);
}
AUKN_SYM void CoreLoadSamplerRelease(ICoreLoadSampler *pSampler)
{
AuSafeDelete<CoreLoadSamplerImpl *>(pSampler);
}
AUKN_SYM ICoreLoadSampler *GetDefaultCoreLoadSampler()
{
return &gDefaultCoreUsageSampler;
}
}