232 lines
6.5 KiB
C++
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[i])
|
|
{
|
|
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;
|
|
}
|
|
} |