/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuCoreLoadSampler.cpp Date: 2023-12-30 Author: Reece ***/ #include #include "AuCoreLoadSampler.hpp" namespace Aurora::HWInfo { static CoreLoadSamplerImpl gDefaultCoreUsageSampler(AuSToMS(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 times; double dUsage[256] { 0.0f }; double dMinSamplePeriod = double(AuMSToNS(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::epsilon() && this->dPrevLoad[i] > AuNumericLimits::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(pSampler); } AUKN_SYM ICoreLoadSampler *GetDefaultCoreLoadSampler() { return &gDefaultCoreUsageSampler; } }