[+] AuHWInfo::GetPerCoreCPUTimeEx(const AuMemoryViewWrite &arrayOfCpuCoreTimeTimes)

[*] Linux: dont use hard-coded macro for kernel frequency when evaluating uptime
This commit is contained in:
Reece Wilson 2024-12-15 21:33:25 +00:00
parent 6b0ca15cdb
commit 63e44ab462
2 changed files with 91 additions and 29 deletions

View File

@ -1,5 +1,5 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
Copyright (C) 2023 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CoreLoad.hpp
Date: 2023-12-30
@ -19,5 +19,18 @@ namespace Aurora::HWInfo
AuUInt64 uUserTime {};
};
AUKN_SYM bool GetPerCoreCPUTime(AuList<CpuCoreTime> &times);
/**
* Internally calls GetPerCoreCPUTimeEx with a reserved times array of the maximum bounds of CpuBitId.
* Recompile the world, if your platform targets >= 128 threads.
*/
AUKN_SYM bool GetPerCoreCPUTime(AuList<CpuCoreTime> &times);
/**
* Emplaces CpuCoreTime into a virtually contiguous array of CpuCoreTime elements for each core in
* order of the platforms convention. See: const CpuInfo & AuHwInfo::GetCPUInfo().
* May return less or greater than the reported cores by GetCPUInfo(), if the underlying platform
* decides to return wonky values.
* Returns an empty optional on failure.
*/
AUKN_SYM AuOptional<AuUInt32> GetPerCoreCPUTimeEx(const AuMemoryViewWrite &arrayOfCpuCoreTimeTimes);
}

View File

@ -20,9 +20,20 @@
#elif defined(AURORA_IS_LINUX_DERIVED)
#if !defined(USER_HZ)
#define USER_HZ 100
#endif
namespace Aurora::HWInfo
{
static AuUInt64 GetKernelFrequency()
{
static AuUInt64 gRet = 0;
if (!gRet)
{
gRet = sysconf(_SC_CLK_TCK);
}
return gRet;
}
}
#endif
@ -35,7 +46,7 @@ namespace Aurora::HWInfo
#else
static const auto kFreq =
#if defined(AURORA_IS_LINUX_DERIVED)
USER_HZ
GetKernelFrequency()
#else
CLOCKS_PER_SEC
#endif
@ -89,31 +100,42 @@ namespace Aurora::HWInfo
int error = sysctlbyname(pName, pBuffer, pLength, NULL, 0);
if (error != 0 && errno != ENOMEM)
{
SysPushErrorGeneric(errno);
SysPushErrorHAL("CpuTimes: {}", errno);
return -1;
}
return (error);
}
static void PlatformGetCoreTimes(AuList<CpuCoreTime> &times)
static AuOptional<AuUInt32> PlatformGetCoreTimes(const AuMemoryViewWrite &times)
{
auto uThreads = AuHwInfo::GetCPUInfo().uThreads;
AuList<long> cpuStates;
cpuStates.resize((uThreads + 1) * CPUSTATES);
if (!AuTryResize(cpuStates, (uThreads + 1) * CPUSTATES))
{
SysPushErrorMemory();
return {};
}
auto uArraySize = times.Count<CpuCoreTime>();
auto pArrayBase = times.Begin<CpuCoreTime>();
size_t len { cpuStates.size() * sizeof(long) };
if (CpuSysctl("kern.cp_times", cpuStates.data(), &len) < 0)
{
return;
return {};
}
if (uThreads > uArraySize)
{
return {};
}
times.resize(uThreads);
for (AU_ITERATE_N(uCore, uThreads))
{
auto &coreTimes = times[uCore];
auto &coreTimes = pArrayBase[uCore];
coreTimes.uKernelTime = cpuStates[(CPUSTATES * uCore) + CP_SYS];
#if defined(CP_INTR)
@ -133,20 +155,25 @@ namespace Aurora::HWInfo
coreTimes.uUptime;
}
return AuUInt32 { uThreads };
}
#elif defined(AURORA_IS_LINUX_DERIVED)
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> &times)
static AuOptional<AuUInt32> PlatformGetCoreTimes(const AuMemoryViewWrite &times)
{
bool bStatus { true };
AuUInt uIndex {};
AuString statFile {};
if (!AuFS::ReadString("/proc/stat", statFile))
{
return false;
return {};
}
auto uArraySize = times.Count<CpuCoreTime>();
auto pArrayBase = times.Begin<CpuCoreTime>();
AuParse::SplitNewlines(statFile, [&](const AuROString &line)
{
CpuCoreTime coreTimes;
@ -237,15 +264,15 @@ namespace Aurora::HWInfo
coreTimes.uAllPowerUpTime = coreTimes.uIdleTime +
coreTimes.uUptime;
times.push_back(coreTimes);
pArrayBase[(uIndex++) % uArraySize] = coreTimes;
});
return bStatus;
return AuUInt32 { uIndex };
}
#elif defined(AURORA_IS_MODERNNT_DERIVED)
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> &times)
static AuOptional<AuUInt32> PlatformGetCoreTimes(const AuMemoryViewWrite &times)
{
#if defined(_AU_MASSIVE_CPUID)
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION processorInfo[256];
@ -253,10 +280,13 @@ namespace Aurora::HWInfo
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION processorInfo[128];
#endif
auto uArraySize = times.Count<CpuCoreTime>();
auto pArrayBase = times.Begin<CpuCoreTime>();
if (!pNtQuerySystemInformation)
{
SysPushErrorFeatureMissing();
return false;
return {};
}
ULONG uOutLen {};
@ -265,19 +295,19 @@ namespace Aurora::HWInfo
sizeof(processorInfo),
&uOutLen)))
{
return false;
return {};
}
auto uCount = uOutLen / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
if (!AuTryResize(times, uCount))
if (uCount > uArraySize)
{
return false;
return {};
}
for (AU_ITERATE_N(uCore, uCount))
{
auto &coreTimes = times[uCore];
auto &coreTimes = pArrayBase[uCore];
coreTimes.uIdleTime = ConvertTicks(processorInfo[uCore].IdleTime.QuadPart);
coreTimes.uInterruptTime = 0;
@ -293,28 +323,47 @@ namespace Aurora::HWInfo
coreTimes.uUptime;
}
return true;
return AuUInt32 { uCount };
}
#elif defined(AURORA_IS_POSIX_DERIVED)
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> &times)
static AuOptional<AuUInt32> PlatformGetCoreTimes(const AuMemoryViewWrite &times)
{
return false;
return {};
}
#else
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> &times)
static AuOptional<AuUInt32> PlatformGetCoreTimes(const AuMemoryViewWrite &times)
{
return false;
return {};
}
#endif
AUKN_SYM AuOptional<AuUInt32> GetPerCoreCPUTimeEx(const AuMemoryViewWrite &arrayOfCpuCoreTimeTimes)
{
return PlatformGetCoreTimes(arrayOfCpuCoreTimeTimes);
}
AUKN_SYM bool GetPerCoreCPUTime(AuList<CpuCoreTime> &times)
{
return PlatformGetCoreTimes(times);
if (!AuTryResize(times, 256))
{
SysPushErrorMemory();
return false;
}
if (auto ret = GetPerCoreCPUTimeEx(times))
{
times.resize(ret.Value());
return true;
}
else
{
return false;
}
}
}