From 63e44ab4622c907037e907a68a6980be66f9d4d7 Mon Sep 17 00:00:00 2001 From: J Reece Wilson Date: Sun, 15 Dec 2024 21:33:25 +0000 Subject: [PATCH] [+] AuHWInfo::GetPerCoreCPUTimeEx(const AuMemoryViewWrite &arrayOfCpuCoreTimeTimes) [*] Linux: dont use hard-coded macro for kernel frequency when evaluating uptime --- Include/Aurora/HWInfo/CoreLoad.hpp | 17 ++++- Source/HWInfo/AuCpuTimes.cpp | 103 +++++++++++++++++++++-------- 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/Include/Aurora/HWInfo/CoreLoad.hpp b/Include/Aurora/HWInfo/CoreLoad.hpp index fc01af8e..bc3b5da1 100644 --- a/Include/Aurora/HWInfo/CoreLoad.hpp +++ b/Include/Aurora/HWInfo/CoreLoad.hpp @@ -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 ×); + /** + * 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 ×); + + /** + * 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 GetPerCoreCPUTimeEx(const AuMemoryViewWrite &arrayOfCpuCoreTimeTimes); } \ No newline at end of file diff --git a/Source/HWInfo/AuCpuTimes.cpp b/Source/HWInfo/AuCpuTimes.cpp index 47fe4c67..28ad7fef 100644 --- a/Source/HWInfo/AuCpuTimes.cpp +++ b/Source/HWInfo/AuCpuTimes.cpp @@ -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 ×) + static AuOptional PlatformGetCoreTimes(const AuMemoryViewWrite ×) { auto uThreads = AuHwInfo::GetCPUInfo().uThreads; AuList cpuStates; - cpuStates.resize((uThreads + 1) * CPUSTATES); + if (!AuTryResize(cpuStates, (uThreads + 1) * CPUSTATES)) + { + SysPushErrorMemory(); + return {}; + } + + auto uArraySize = times.Count(); + auto pArrayBase = times.Begin(); 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 ×) + static AuOptional PlatformGetCoreTimes(const AuMemoryViewWrite ×) { - bool bStatus { true }; + AuUInt uIndex {}; AuString statFile {}; if (!AuFS::ReadString("/proc/stat", statFile)) { - return false; + return {}; } + auto uArraySize = times.Count(); + auto pArrayBase = times.Begin(); + 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 ×) + static AuOptional PlatformGetCoreTimes(const AuMemoryViewWrite ×) { #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(); + auto pArrayBase = times.Begin(); + 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 ×) + static AuOptional PlatformGetCoreTimes(const AuMemoryViewWrite ×) { - return false; + return {}; } #else - static bool PlatformGetCoreTimes(AuList ×) + static AuOptional PlatformGetCoreTimes(const AuMemoryViewWrite ×) { - return false; + return {}; } #endif + AUKN_SYM AuOptional GetPerCoreCPUTimeEx(const AuMemoryViewWrite &arrayOfCpuCoreTimeTimes) + { + return PlatformGetCoreTimes(arrayOfCpuCoreTimeTimes); + } + AUKN_SYM bool GetPerCoreCPUTime(AuList ×) { - return PlatformGetCoreTimes(times); + if (!AuTryResize(times, 256)) + { + SysPushErrorMemory(); + return false; + } + + if (auto ret = GetPerCoreCPUTimeEx(times)) + { + times.resize(ret.Value()); + return true; + } + else + { + return false; + } } } \ No newline at end of file