/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: CpuLoadSampler.cpp Date: 2023-10-28 Author: Reece ***/ #include #include "AuCpuLoadSampler.hpp" namespace Aurora::HWInfo { static thread_local CpuLoadSamplerImpl tlsThreadLocalUsageSamplers[2] { CpuLoadSamplerImpl(AuSToMS(1), true, false), CpuLoadSamplerImpl(AuSToMS(1), true, true) }; static CpuLoadSamplerImpl gProcessUsageSampler(AuSToMS(1), false, true); CpuLoadSamplerImpl::CpuLoadSamplerImpl(AuUInt32 uMinSamplePeriodMS, bool bThreadMode, bool bCountKernelUsage) : uMinSamplePeriod(uMinSamplePeriodMS), bThreadMode(bThreadMode), bCountKernelUsage(bCountKernelUsage) { } CpuLoadSamplerImpl::~CpuLoadSamplerImpl() { } double CpuLoadSamplerImpl::GetLoad() { if (!this->bThreadMode) { return this->processState.GetLoad(this->uMinSamplePeriod, false, this->bCountKernelUsage); } else { return this->threadState->GetLoad(this->uMinSamplePeriod, true, this->bCountKernelUsage); } } double CpuLoadSamplerState::GetLoad(AuUInt32 uMinSamplePeriod, bool bThread, bool bCountKernelUsage) { AuUInt64 now[2] = { AuTime::SteadyClockNS(), bThread ? (bCountKernelUsage ? AuTime::ThreadClockNS() : AuTime::ThreadUserClockNS()) : (bCountKernelUsage ? AuTime::ProcessClockNS() : AuTime::ProcessUserClockNS()) }; double dDeltaSteady = now[0] - this->uPrevTimes[0]; double dDeltaProcess = now[1] - this->uPrevTimes[1]; double dUsage = 0; double dMinSamplePeriod = double(AuMSToNS(uMinSamplePeriod)); if (!bool(this->uPrevTimes[0])) { this->uPrevTimes[1] = now[1]; this->uPrevTimes[0] = now[0]; return 0; } if (!uMinSamplePeriod || dDeltaSteady >= dMinSamplePeriod) { dUsage = dDeltaProcess / dDeltaSteady; this->uPrevTimes[1] = now[1]; this->uPrevTimes[0] = now[0]; #if 1 if (uMinSamplePeriod && this->dPrevLoad) dUsage = AuMin(dUsage, dUsage + this->dPrevLoad / 2.0); #endif this->dPrevLoad = dUsage; } else { dUsage = dDeltaProcess / dDeltaSteady; #if 0 dUsage *= dDeltaSteady / double(dMinSamplePeriod); if (this->dPrevLoad) dUsage = dUsage + this->dPrevLoad / 2.0; #else if (this->dPrevLoad) { double dFrameDelta = dDeltaSteady / double(dMinSamplePeriod); double dFrameDeltaInverse = 1.0 - dFrameDelta; dUsage *= dFrameDelta; dUsage += this->dPrevLoad * dFrameDeltaInverse; } else { dUsage *= dDeltaSteady / double(dMinSamplePeriod); } #endif } { dUsage = dUsage * 100.0; if (dUsage > 100.0) { return 100.0; } else if (dUsage < 0.0) { return 0.0; } else { return dUsage; } } } AUKN_SYM double GetProcessCPUUtilization() { return gProcessUsageSampler.GetLoad(); } AUKN_SYM double GetThreadCPUUtilization(AuOptional optIncludeKernel) { return tlsThreadLocalUsageSamplers[optIncludeKernel.value_or(true)].GetLoad(); } AUKN_SYM ICpuLoadSampler *CpuLoadSamplerNew(AuUInt32 uMinSamplePeriodMS, bool bThreadMode, bool bCountKernelUsage) { return _new CpuLoadSamplerImpl(uMinSamplePeriodMS, bThreadMode, bCountKernelUsage); } AUKN_SYM void CpuLoadSamplerRelease(ICpuLoadSampler *pEvent) { AuSafeDelete(pEvent); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, CpuLoadSampler, CpuLoadSamplerImpl, (AuUInt32, uMinSamplePeriod), (bool, bThreadMode), (bool, bCountKernelUsage)) }