190 lines
5.7 KiB
C++
190 lines
5.7 KiB
C++
/***
|
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuCpuLoadSampler.cpp
|
|
Date: 2023-10-28
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuCpuLoadSampler.hpp"
|
|
|
|
namespace Aurora::HWInfo
|
|
{
|
|
static thread_local ProcessLoadSamplerImpl tlsThreadLocalUsageSamplers[2] {
|
|
ProcessLoadSamplerImpl(AuSToMS<AuUInt32>(1), true, false),
|
|
ProcessLoadSamplerImpl(AuSToMS<AuUInt32>(1), true, true)
|
|
};
|
|
|
|
static ProcessLoadSamplerImpl gProcessUsageSampler(AuSToMS<AuUInt32>(1), false, true);
|
|
|
|
ProcessLoadSamplerImpl::ProcessLoadSamplerImpl(AuUInt32 uMinSamplePeriodMS,
|
|
bool bThreadMode,
|
|
bool bCountKernelUsage) :
|
|
uMinSamplePeriod(uMinSamplePeriodMS),
|
|
bThreadMode(bThreadMode),
|
|
bCountKernelUsage(bCountKernelUsage)
|
|
{
|
|
|
|
}
|
|
|
|
ProcessLoadSamplerImpl::~ProcessLoadSamplerImpl()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
double ProcessLoadSamplerImpl::GetLoad()
|
|
{
|
|
if (!this->bThreadMode)
|
|
{
|
|
return this->processState.GetLoad(this->uMinSamplePeriod, false, this->bCountKernelUsage);
|
|
}
|
|
else
|
|
{
|
|
return this->threadState->GetLoad(this->uMinSamplePeriod, true, this->bCountKernelUsage);
|
|
}
|
|
}
|
|
|
|
double ProcessLoadSamplerState::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<AuUInt64>(uMinSamplePeriod));
|
|
double dDeltaSteady2;
|
|
double dThreads = 1.0;
|
|
|
|
if (bThread)
|
|
{
|
|
dThreads = GetCPUInfo().uThreads;
|
|
dDeltaSteady2 = dDeltaSteady * dThreads;
|
|
}
|
|
else
|
|
{
|
|
dDeltaSteady2 = dDeltaSteady;
|
|
}
|
|
|
|
if (!bool(this->uPrevTimes[0]))
|
|
{
|
|
this->uPrevTimes[0] = now[0];
|
|
this->uPrevTimes[1] = now[1];
|
|
return 0;
|
|
}
|
|
|
|
if (!uMinSamplePeriod ||
|
|
(dDeltaSteady >= dMinSamplePeriod))
|
|
{
|
|
dUsage = dDeltaProcess / dDeltaSteady2;
|
|
this->uPrevTimes[1] = now[1];
|
|
this->uPrevTimes[0] = now[0];
|
|
if (uMinSamplePeriod)
|
|
{
|
|
if (dUsage > AuNumericLimits<double>::epsilon() &&
|
|
this->dPrevLoad > AuNumericLimits<double>::epsilon())
|
|
{
|
|
dUsage = AuMin(dUsage, dUsage + this->dPrevLoad / 2.0);
|
|
}
|
|
else
|
|
{
|
|
dUsage = AuMax(this->dPrevLoad / 2.0, 0.0001);
|
|
}
|
|
}
|
|
else if (!dUsage)
|
|
{
|
|
dUsage = AuMax(this->dPrevLoad / 2.0, 0.0001);
|
|
}
|
|
this->dPrevLoad = dUsage;
|
|
this->bSet = true;
|
|
}
|
|
else if (!dDeltaProcess &&
|
|
!this->bSet)
|
|
{
|
|
// well, we obviously have some uptime. but how much?
|
|
auto uDeltaNS = AuMin(dDeltaSteady, dMinSamplePeriod);
|
|
|
|
if (uDeltaNS > AuMSToNS<double>(1000 / 250))
|
|
{
|
|
uDeltaNS = 100;
|
|
}
|
|
|
|
dUsage = uDeltaNS / dDeltaSteady2;
|
|
}
|
|
else if (dDeltaProcess &&
|
|
!this->bSet)
|
|
{
|
|
dUsage = dDeltaProcess / dDeltaSteady2;
|
|
}
|
|
else if (dDeltaProcess)
|
|
{
|
|
dUsage = dDeltaProcess / dDeltaSteady2;
|
|
#if 0
|
|
dUsage *= dDeltaSteady2 / double(dMinSamplePeriod);
|
|
if (this->dPrevLoad) dUsage = dUsage + this->dPrevLoad / 2.0;
|
|
#else
|
|
if (this->dPrevLoad)
|
|
{
|
|
auto dFrameDelta = dDeltaSteady / dMinSamplePeriod;
|
|
auto dFrameDeltaInverse = 1.0 - dFrameDelta;
|
|
dUsage *= dFrameDelta;
|
|
dUsage += this->dPrevLoad * dFrameDeltaInverse;
|
|
}
|
|
else
|
|
{
|
|
dUsage *= dDeltaSteady / dMinSamplePeriod;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
dUsage = this->dPrevLoad;
|
|
}
|
|
|
|
{
|
|
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<bool> optIncludeKernel)
|
|
{
|
|
return tlsThreadLocalUsageSamplers[optIncludeKernel.value_or(true)].GetLoad();
|
|
}
|
|
|
|
AUKN_SYM IProcessLoadSampler *ProcessLoadSamplerNew(AuUInt32 uMinSamplePeriodMS,
|
|
bool bThreadMode,
|
|
bool bCountKernelUsage)
|
|
{
|
|
return _new ProcessLoadSamplerImpl(uMinSamplePeriodMS, bThreadMode, bCountKernelUsage);
|
|
}
|
|
|
|
AUKN_SYM void ProcessLoadSamplerRelease(IProcessLoadSampler *pEvent)
|
|
{
|
|
AuSafeDelete<ProcessLoadSamplerImpl *>(pEvent);
|
|
}
|
|
|
|
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, ProcessLoadSampler, ProcessLoadSamplerImpl, (AuUInt32, uMinSamplePeriod), (bool, bThreadMode), (bool, bCountKernelUsage))
|
|
} |