aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/system.cpp
diff options
context:
space:
mode:
authorzousar <[email protected]>2026-02-18 23:19:14 -0700
committerzousar <[email protected]>2026-02-18 23:19:14 -0700
commit2ba28acaf034722452f82cfb07afc0a4bb90eeab (patch)
treec00dea385597180673be6e02aca6c07d9ef6ec00 /src/zencore/system.cpp
parentupdatefrontend (diff)
parentstructured compute basics (#714) (diff)
downloadzen-2ba28acaf034722452f82cfb07afc0a4bb90eeab.tar.xz
zen-2ba28acaf034722452f82cfb07afc0a4bb90eeab.zip
Merge branch 'main' into zs/web-ui-improvements
Diffstat (limited to 'src/zencore/system.cpp')
-rw-r--r--src/zencore/system.cpp169
1 files changed, 133 insertions, 36 deletions
diff --git a/src/zencore/system.cpp b/src/zencore/system.cpp
index e92691781..267c87e12 100644
--- a/src/zencore/system.cpp
+++ b/src/zencore/system.cpp
@@ -13,6 +13,8 @@
ZEN_THIRD_PARTY_INCLUDES_START
# include <iphlpapi.h>
# include <winsock2.h>
+# include <pdh.h>
+# pragma comment(lib, "pdh.lib")
ZEN_THIRD_PARTY_INCLUDES_END
#elif ZEN_PLATFORM_LINUX
# include <sys/utsname.h>
@@ -65,55 +67,98 @@ GetSystemMetrics()
// Determine physical core count
- DWORD BufferSize = 0;
- BOOL Result = GetLogicalProcessorInformationEx(RelationAll, nullptr, &BufferSize);
- if (int32_t Error = GetLastError(); Error != ERROR_INSUFFICIENT_BUFFER)
{
- ThrowSystemError(Error, "Failed to get buffer size for logical processor information");
- }
-
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)Memory::Alloc(BufferSize);
+ DWORD BufferSize = 0;
+ BOOL Result = GetLogicalProcessorInformationEx(RelationAll, nullptr, &BufferSize);
+ if (int32_t Error = GetLastError(); Error != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ThrowSystemError(Error, "Failed to get buffer size for logical processor information");
+ }
- Result = GetLogicalProcessorInformationEx(RelationAll, Buffer, &BufferSize);
- if (!Result)
- {
- Memory::Free(Buffer);
- throw std::runtime_error("Failed to get logical processor information");
- }
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)Memory::Alloc(BufferSize);
- DWORD ProcessorPkgCount = 0;
- DWORD ProcessorCoreCount = 0;
- DWORD ByteOffset = 0;
- while (ByteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) <= BufferSize)
- {
- const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX& Slpi = Buffer[ByteOffset / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)];
- if (Slpi.Relationship == RelationProcessorCore)
+ Result = GetLogicalProcessorInformationEx(RelationAll, Buffer, &BufferSize);
+ if (!Result)
{
- ProcessorCoreCount++;
+ Memory::Free(Buffer);
+ throw std::runtime_error("Failed to get logical processor information");
}
- else if (Slpi.Relationship == RelationProcessorPackage)
+
+ DWORD ProcessorPkgCount = 0;
+ DWORD ProcessorCoreCount = 0;
+ DWORD LogicalProcessorCount = 0;
+
+ BYTE* Ptr = reinterpret_cast<BYTE*>(Buffer);
+ BYTE* const End = Ptr + BufferSize;
+ while (Ptr < End)
{
- ProcessorPkgCount++;
+ const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX& Slpi = *reinterpret_cast<const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(Ptr);
+ if (Slpi.Relationship == RelationProcessorCore)
+ {
+ ++ProcessorCoreCount;
+
+ // Count logical processors (threads) across all processor groups for this core.
+ // Each core entry lists one GROUP_AFFINITY per group it spans; each set bit
+ // in the Mask represents one logical processor (HyperThreading sibling).
+ for (WORD g = 0; g < Slpi.Processor.GroupCount; ++g)
+ {
+ LogicalProcessorCount += static_cast<DWORD>(__popcnt64(Slpi.Processor.GroupMask[g].Mask));
+ }
+ }
+ else if (Slpi.Relationship == RelationProcessorPackage)
+ {
+ ++ProcessorPkgCount;
+ }
+ Ptr += Slpi.Size;
}
- ByteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX);
- }
- Metrics.CoreCount = ProcessorCoreCount;
- Metrics.CpuCount = ProcessorPkgCount;
+ Metrics.CoreCount = ProcessorCoreCount;
+ Metrics.CpuCount = ProcessorPkgCount;
+ Metrics.LogicalProcessorCount = LogicalProcessorCount;
- Memory::Free(Buffer);
+ Memory::Free(Buffer);
+ }
// Query memory status
- MEMORYSTATUSEX MemStatus{.dwLength = sizeof(MEMORYSTATUSEX)};
- GlobalMemoryStatusEx(&MemStatus);
+ {
+ MEMORYSTATUSEX MemStatus{.dwLength = sizeof(MEMORYSTATUSEX)};
+ GlobalMemoryStatusEx(&MemStatus);
+
+ Metrics.SystemMemoryMiB = MemStatus.ullTotalPhys / 1024 / 1024;
+ Metrics.AvailSystemMemoryMiB = MemStatus.ullAvailPhys / 1024 / 1024;
+ Metrics.VirtualMemoryMiB = MemStatus.ullTotalVirtual / 1024 / 1024;
+ Metrics.AvailVirtualMemoryMiB = MemStatus.ullAvailVirtual / 1024 / 1024;
+ Metrics.PageFileMiB = MemStatus.ullTotalPageFile / 1024 / 1024;
+ Metrics.AvailPageFileMiB = MemStatus.ullAvailPageFile / 1024 / 1024;
+ }
+
+ // Query CPU usage using PDH
+ //
+ // TODO: This should be changed to not require a Sleep, perhaps by using some
+ // background metrics gathering mechanism.
+
+ {
+ PDH_HQUERY QueryHandle = nullptr;
+ PDH_HCOUNTER CounterHandle = nullptr;
- Metrics.SystemMemoryMiB = MemStatus.ullTotalPhys / 1024 / 1024;
- Metrics.AvailSystemMemoryMiB = MemStatus.ullAvailPhys / 1024 / 1024;
- Metrics.VirtualMemoryMiB = MemStatus.ullTotalVirtual / 1024 / 1024;
- Metrics.AvailVirtualMemoryMiB = MemStatus.ullAvailVirtual / 1024 / 1024;
- Metrics.PageFileMiB = MemStatus.ullTotalPageFile / 1024 / 1024;
- Metrics.AvailPageFileMiB = MemStatus.ullAvailPageFile / 1024 / 1024;
+ if (PdhOpenQueryW(nullptr, 0, &QueryHandle) == ERROR_SUCCESS)
+ {
+ if (PdhAddEnglishCounterW(QueryHandle, L"\\Processor(_Total)\\% Processor Time", 0, &CounterHandle) == ERROR_SUCCESS)
+ {
+ PdhCollectQueryData(QueryHandle);
+ Sleep(100);
+ PdhCollectQueryData(QueryHandle);
+
+ PDH_FMT_COUNTERVALUE CounterValue;
+ if (PdhGetFormattedCounterValue(CounterHandle, PDH_FMT_DOUBLE, nullptr, &CounterValue) == ERROR_SUCCESS)
+ {
+ Metrics.CpuUsagePercent = static_cast<float>(CounterValue.doubleValue);
+ }
+ }
+ PdhCloseQuery(QueryHandle);
+ }
+ }
return Metrics;
}
@@ -190,6 +235,39 @@ GetSystemMetrics()
}
}
+ // Query CPU usage
+ Metrics.CpuUsagePercent = 0.0f;
+ if (FILE* Stat = fopen("/proc/stat", "r"))
+ {
+ char Line[256];
+ unsigned long User, Nice, System, Idle, IoWait, Irq, SoftIrq;
+ static unsigned long PrevUser = 0, PrevNice = 0, PrevSystem = 0, PrevIdle = 0, PrevIoWait = 0, PrevIrq = 0, PrevSoftIrq = 0;
+
+ if (fgets(Line, sizeof(Line), Stat))
+ {
+ if (sscanf(Line, "cpu %lu %lu %lu %lu %lu %lu %lu", &User, &Nice, &System, &Idle, &IoWait, &Irq, &SoftIrq) == 7)
+ {
+ unsigned long TotalDelta = (User + Nice + System + Idle + IoWait + Irq + SoftIrq) -
+ (PrevUser + PrevNice + PrevSystem + PrevIdle + PrevIoWait + PrevIrq + PrevSoftIrq);
+ unsigned long IdleDelta = Idle - PrevIdle;
+
+ if (TotalDelta > 0)
+ {
+ Metrics.CpuUsagePercent = 100.0f * (TotalDelta - IdleDelta) / TotalDelta;
+ }
+
+ PrevUser = User;
+ PrevNice = Nice;
+ PrevSystem = System;
+ PrevIdle = Idle;
+ PrevIoWait = IoWait;
+ PrevIrq = Irq;
+ PrevSoftIrq = SoftIrq;
+ }
+ }
+ fclose(Stat);
+ }
+
// Get memory information
long Pages = sysconf(_SC_PHYS_PAGES);
long PageSize = sysconf(_SC_PAGE_SIZE);
@@ -270,6 +348,25 @@ GetSystemMetrics()
sysctlbyname("hw.packages", &Packages, &Size, nullptr, 0);
Metrics.CpuCount = Packages > 0 ? Packages : 1;
+ // Query CPU usage using host_statistics64
+ Metrics.CpuUsagePercent = 0.0f;
+ host_cpu_load_info_data_t CpuLoad;
+ mach_msg_type_number_t CpuCount = sizeof(CpuLoad) / sizeof(natural_t);
+ if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&CpuLoad, &CpuCount) == KERN_SUCCESS)
+ {
+ unsigned long TotalTicks = 0;
+ for (int i = 0; i < CPU_STATE_MAX; ++i)
+ {
+ TotalTicks += CpuLoad.cpu_ticks[i];
+ }
+
+ if (TotalTicks > 0)
+ {
+ unsigned long IdleTicks = CpuLoad.cpu_ticks[CPU_STATE_IDLE];
+ Metrics.CpuUsagePercent = 100.0f * (TotalTicks - IdleTicks) / TotalTicks;
+ }
+ }
+
// Get memory information
uint64_t MemSize = 0;
Size = sizeof(MemSize);