320 lines
8.6 KiB
C++
320 lines
8.6 KiB
C++
/***
|
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuCpuTimes.cpp
|
|
Date: 2023-12-30
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuCpuTimes.hpp"
|
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
#include <errno.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/resource.h>
|
|
|
|
#elif defined(AURORA_IS_XNU_DERIVED)
|
|
|
|
#include <sys/dkstat.h>
|
|
|
|
#elif defined(AURORA_IS_LINUX_DERIVED)
|
|
|
|
#if !defined(USER_HZ)
|
|
#define USER_HZ 100
|
|
#endif
|
|
|
|
#endif
|
|
|
|
namespace Aurora::HWInfo
|
|
{
|
|
static AuUInt64 ConvertTicks(AuUInt64 uTicks)
|
|
{
|
|
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
|
return uTicks * 100ull;
|
|
#else
|
|
static const auto kFreq =
|
|
#if defined(AURORA_IS_LINUX_DERIVED)
|
|
USER_HZ
|
|
#else
|
|
CLOCKS_PER_SEC
|
|
#endif
|
|
;
|
|
|
|
if (kFreq == 10000000)
|
|
{
|
|
return uTicks * 100ull;
|
|
}
|
|
else if (kFreq == 1000000)
|
|
{
|
|
return uTicks * 1000ull;
|
|
}
|
|
else if (kFreq == 100000)
|
|
{
|
|
return uTicks * 10000ull;
|
|
}
|
|
else if (kFreq == 10000)
|
|
{
|
|
return uTicks * 100000ull;
|
|
}
|
|
else if (kFreq == 1000)
|
|
{
|
|
return uTicks * 1000000ull;
|
|
}
|
|
else if (kFreq == 100)
|
|
{
|
|
return uTicks * 10000000ull;
|
|
}
|
|
else if (kFreq == 100000000)
|
|
{
|
|
return uTicks * 10ull;
|
|
}
|
|
else if (kFreq == 1000000000ull)
|
|
{
|
|
return uTicks;
|
|
}
|
|
else
|
|
{
|
|
const long long uWhole = (uTicks / kFreq) * 1'000'000'000ull;
|
|
const long long uPart = (uTicks % kFreq) * 1'000'000'000ull / kFreq;
|
|
return uWhole + uPart;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
static int CpuSysctl(const char *pName, void *pBuffer, size_t *pLength)
|
|
{
|
|
int error = sysctlbyname(pName, pBuffer, pLength, NULL, 0);
|
|
if (error != 0 && errno != ENOMEM)
|
|
{
|
|
SysPushErrorGeneric(errno);
|
|
return -1;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static void PlatformGetCoreTimes(AuList<CpuCoreTime> ×)
|
|
{
|
|
auto uThreads = AuHwInfo::GetCPUInfo().uThreads;
|
|
|
|
AuList<long> cpuStates;
|
|
cpuStates.resize((uThreads + 1) * CPUSTATES);
|
|
|
|
size_t len { cpuStates.size() * sizeof(long) };
|
|
|
|
if (CpuSysctl("kern.cp_times", cpuStates.data(), &len) < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
times.resize(uThreads);
|
|
for (AU_ITERATE_N(uCore, uThreads))
|
|
{
|
|
auto &coreTimes = times[uCore];
|
|
|
|
coreTimes.uKernelTime = cpuStates[(CPUSTATES * uCore) + CP_SYS];
|
|
#if defined(CP_INTR)
|
|
coreTimes.uInterruptTime = cpuStates[(CPUSTATES * uCore) + CP_INTR];
|
|
#endif
|
|
coreTimes.uUserTime = cpuStates[(CPUSTATES * uCore) + CP_USER];
|
|
coreTimes.uIdleTime = cpuStates[(CPUSTATES * uCore) + CP_IDLE];
|
|
|
|
coreTimes.uIdleTime = ConvertTicks(coreTimes.uIdleTime);
|
|
coreTimes.uInterruptTime = ConvertTicks(coreTimes.uInterruptTime);
|
|
coreTimes.uKernelTime = ConvertTicks(coreTimes.uKernelTime);
|
|
coreTimes.uUserTime = ConvertTicks(coreTimes.uUserTime);
|
|
|
|
coreTimes.uUptime = coreTimes.uKernelTime + coreTimes.uUserTime + coreTimes.uInterruptTime;
|
|
|
|
coreTimes.uAllPowerUpTime = coreTimes.uIdleTime +
|
|
coreTimes.uUptime;
|
|
|
|
}
|
|
}
|
|
|
|
#elif defined(AURORA_IS_LINUX_DERIVED)
|
|
|
|
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> ×)
|
|
{
|
|
bool bStatus { true };
|
|
AuString statFile {};
|
|
|
|
if (!AuFS::ReadString("/proc/stat", statFile))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
AuParse::SplitNewlines(statFile, [&](const AuROString &line)
|
|
{
|
|
CpuCoreTime coreTimes;
|
|
|
|
if (!AuStartsWith(line, "cpu"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto line2 = line;
|
|
auto intStrs = AuSplitString(line2, " ");
|
|
|
|
intStrs.erase(intStrs.begin());
|
|
|
|
if (intStrs.size() > 0)
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[0]))
|
|
{
|
|
coreTimes.uUserTime = result.value();
|
|
}
|
|
}
|
|
|
|
if (intStrs.size() > 1)
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[1]))
|
|
{
|
|
coreTimes.uUserTime += result.value();
|
|
}
|
|
}
|
|
|
|
if (intStrs.size() > 2)
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[2]))
|
|
{
|
|
coreTimes.uKernelTime = result.value();
|
|
}
|
|
}
|
|
|
|
if (intStrs.size() > 3)
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[3]))
|
|
{
|
|
coreTimes.uIdleTime = result.value();
|
|
}
|
|
}
|
|
|
|
if (intStrs.size() > 4)
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[4]))
|
|
{
|
|
coreTimes.uKernelTime += result.value();
|
|
}
|
|
}
|
|
|
|
if (intStrs.size() > 5)
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[5]))
|
|
{
|
|
coreTimes.uInterruptTime += result.value();
|
|
}
|
|
}
|
|
|
|
if (intStrs.size() > 6)
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[6]))
|
|
{
|
|
coreTimes.uInterruptTime += result.value();
|
|
}
|
|
}
|
|
|
|
for (AU_ITERATE_N_TO_X(i, 7, intStrs.size()))
|
|
{
|
|
if (auto result = AuParse::ParseUInt(intStrs[i]))
|
|
{
|
|
coreTimes.uKernelTime += result.value();
|
|
}
|
|
}
|
|
|
|
coreTimes.uIdleTime = ConvertTicks(coreTimes.uIdleTime);
|
|
coreTimes.uInterruptTime = ConvertTicks(coreTimes.uInterruptTime);
|
|
coreTimes.uKernelTime = ConvertTicks(coreTimes.uKernelTime);
|
|
coreTimes.uUserTime = ConvertTicks(coreTimes.uUserTime);
|
|
|
|
coreTimes.uUptime = coreTimes.uKernelTime +
|
|
coreTimes.uUserTime +
|
|
coreTimes.uInterruptTime;
|
|
|
|
coreTimes.uAllPowerUpTime = coreTimes.uIdleTime +
|
|
coreTimes.uUptime;
|
|
|
|
times.push_back(coreTimes);
|
|
});
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
#elif defined(AURORA_IS_MODERNNT_DERIVED)
|
|
|
|
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> ×)
|
|
{
|
|
#if defined(_AU_MASSIVE_CPUID)
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION processorInfo[256];
|
|
#else
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION processorInfo[128];
|
|
#endif
|
|
|
|
if (!pNtQuerySystemInformation)
|
|
{
|
|
SysPushErrorFeatureMissing();
|
|
return false;
|
|
}
|
|
|
|
ULONG uOutLen {};
|
|
if (FAILED(pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
|
|
&processorInfo,
|
|
sizeof(processorInfo),
|
|
&uOutLen)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto uCount = uOutLen / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
|
|
|
|
if (!AuTryResize(times, uCount))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (AU_ITERATE_N(uCore, uCount))
|
|
{
|
|
auto &coreTimes = times[uCore];
|
|
|
|
coreTimes.uIdleTime = ConvertTicks(processorInfo[uCore].IdleTime.QuadPart);
|
|
coreTimes.uInterruptTime = 0;
|
|
coreTimes.uKernelTime = ConvertTicks(processorInfo[uCore].KernelTime.QuadPart);
|
|
coreTimes.uUserTime = ConvertTicks(processorInfo[uCore].UserTime.QuadPart);
|
|
coreTimes.uKernelTime -= coreTimes.uIdleTime;
|
|
|
|
coreTimes.uUptime = coreTimes.uKernelTime +
|
|
coreTimes.uUserTime +
|
|
coreTimes.uInterruptTime;
|
|
|
|
coreTimes.uAllPowerUpTime = coreTimes.uIdleTime +
|
|
coreTimes.uUptime;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
#elif defined(AURORA_IS_POSIX_DERIVED)
|
|
|
|
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> ×)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#else
|
|
|
|
static bool PlatformGetCoreTimes(AuList<CpuCoreTime> ×)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
|
|
AUKN_SYM bool GetPerCoreCPUTime(AuList<CpuCoreTime> ×)
|
|
{
|
|
return PlatformGetCoreTimes(times);
|
|
}
|
|
} |