16 #ifndef hifi_WindowSystemInfo_h
17 #define hifi_WindowSystemInfo_h
19 #include <qsystemdetection.h>
25 #pragma comment(lib, "pdh.lib")
26 #pragma comment(lib, "ntdll.lib")
32 #include <glm/glm.hpp>
38 #include "ThreadHelpers.h"
41 enum SYSTEM_INFORMATION_CLASS {
42 SystemBasicInformation = 0,
43 SystemProcessorPerformanceInformation = 8,
46 struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
47 LARGE_INTEGER IdleTime;
48 LARGE_INTEGER KernelTime;
49 LARGE_INTEGER UserTime;
50 LARGE_INTEGER DpcTime;
51 LARGE_INTEGER InterruptTime;
55 struct SYSTEM_BASIC_INFORMATION {
57 ULONG TimerResolution;
59 ULONG NumberOfPhysicalPages;
60 ULONG LowestPhysicalPageNumber;
61 ULONG HighestPhysicalPageNumber;
62 ULONG AllocationGranularity;
63 ULONG_PTR MinimumUserModeAddress;
64 ULONG_PTR MaximumUserModeAddress;
65 ULONG_PTR ActiveProcessorsAffinityMask;
66 CCHAR NumberOfProcessors;
69 NTSYSCALLAPI LONG NTAPI NtQuerySystemInformation(
70 _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
71 _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
72 _In_ ULONG SystemInformationLength,
73 _Out_opt_ PULONG ReturnLength
78 LONG NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, T& t) {
79 return NtQuerySystemInformation(SystemInformationClass, &t, (ULONG)
sizeof(T),
nullptr);
83 LONG NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, std::vector<T>& t) {
84 return NtQuerySystemInformation(SystemInformationClass, t.data(), (ULONG)(
sizeof(T) * t.size()),
nullptr);
89 void updateValueAndDelta(std::pair<T, T>& pair, T newValue) {
90 auto& value = pair.first;
91 auto& delta = pair.second;
92 delta = (value != 0) ? newValue - value : 0;
97 using ValueAndDelta = std::pair<LONGLONG, LONGLONG>;
99 ValueAndDelta kernel { 0, 0 };
100 ValueAndDelta user { 0, 0 };
101 ValueAndDelta idle { 0, 0 };
102 float kernelUsage { 0.0f };
103 float userUsage { 0.0f };
105 void update(
const SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpuInfo) {
106 updateValueAndDelta(kernel, cpuInfo.KernelTime.QuadPart);
107 updateValueAndDelta(user, cpuInfo.UserTime.QuadPart);
108 updateValueAndDelta(idle, cpuInfo.IdleTime.QuadPart);
109 auto totalTime = kernel.second + user.second + idle.second;
110 if (totalTime != 0) {
111 kernelUsage = (FLOAT)kernel.second / totalTime;
112 userUsage = (FLOAT)user.second / totalTime;
114 kernelUsage = userUsage = 0.0f;
119 void updateCpuInformation() {
120 static std::once_flag once;
121 static SYSTEM_BASIC_INFORMATION systemInfo {};
122 static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuTotals;
123 static std::vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> cpuInfos;
124 static std::vector<MyCpuInfo> myCpuInfos;
125 static MyCpuInfo myCpuTotals;
126 std::call_once(once, [&] {
127 NtQuerySystemInformation( SystemBasicInformation, systemInfo);
128 cpuInfos.resize(systemInfo.NumberOfProcessors);
129 myCpuInfos.resize(systemInfo.NumberOfProcessors);
130 for (
size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {
131 myCpuInfos[i].name =
"cpu." + std::to_string(i);
133 myCpuTotals.name =
"cpu.total";
135 NtQuerySystemInformation(SystemProcessorPerformanceInformation, cpuInfos);
138 memset(&cpuTotals, 0,
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
139 for (
size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {
140 auto& cpuInfo = cpuInfos[i];
142 cpuInfo.KernelTime.QuadPart -= cpuInfo.IdleTime.QuadPart;
145 cpuTotals.IdleTime.QuadPart += cpuInfo.IdleTime.QuadPart;
146 cpuTotals.KernelTime.QuadPart += cpuInfo.KernelTime.QuadPart;
147 cpuTotals.UserTime.QuadPart += cpuInfo.UserTime.QuadPart;
150 auto& myCpuInfo = myCpuInfos[i];
151 myCpuInfo.update(cpuInfo);
152 PROFILE_COUNTER(app, myCpuInfo.name.c_str(), {
153 {
"kernel", myCpuInfo.kernelUsage },
154 {
"user", myCpuInfo.userUsage }
158 myCpuTotals.update(cpuTotals);
159 PROFILE_COUNTER(app, myCpuTotals.name.c_str(), {
160 {
"kernel", myCpuTotals.kernelUsage },
161 {
"user", myCpuTotals.userUsage }
166 static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;
167 static int numProcessors;
169 static PDH_HQUERY cpuQuery;
170 static PDH_HCOUNTER cpuTotal;
172 void initCpuUsage() {
174 FILETIME ftime, fsys, fuser;
176 GetSystemInfo(&sysInfo);
177 numProcessors = sysInfo.dwNumberOfProcessors;
179 GetSystemTimeAsFileTime(&ftime);
180 memcpy(&lastCPU, &ftime,
sizeof(FILETIME));
182 self = GetCurrentProcess();
183 GetProcessTimes(
self, &ftime, &ftime, &fsys, &fuser);
184 memcpy(&lastSysCPU, &fsys,
sizeof(FILETIME));
185 memcpy(&lastUserCPU, &fuser,
sizeof(FILETIME));
187 PdhOpenQuery(NULL, NULL, &cpuQuery);
188 PdhAddCounter(cpuQuery,
"\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);
189 PdhCollectQueryData(cpuQuery);
192 void getCpuUsage(glm::vec3& systemAndUser) {
193 FILETIME ftime, fsys, fuser;
194 ULARGE_INTEGER now, sys, user;
196 GetSystemTimeAsFileTime(&ftime);
197 memcpy(&now, &ftime,
sizeof(FILETIME));
199 GetProcessTimes(
self, &ftime, &ftime, &fsys, &fuser);
200 memcpy(&sys, &fsys,
sizeof(FILETIME));
201 memcpy(&user, &fuser,
sizeof(FILETIME));
202 systemAndUser.x = (sys.QuadPart - lastSysCPU.QuadPart);
203 systemAndUser.y = (user.QuadPart - lastUserCPU.QuadPart);
204 systemAndUser /= (float)(now.QuadPart - lastCPU.QuadPart);
205 systemAndUser /= (float)numProcessors;
206 systemAndUser *= 100.0f;
211 PDH_FMT_COUNTERVALUE counterVal;
212 PdhCollectQueryData(cpuQuery);
213 PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
214 systemAndUser.z = (float)counterVal.doubleValue;
217 void setupCpuMonitorThread() {
219 auto cpuMonitorThread = QThread::currentThread();
220 setThreadName(
"CPU Monitor Thread");
222 QTimer* timer =
new QTimer();
223 timer->setInterval(50);
224 QObject::connect(timer, &QTimer::timeout, [] {
225 updateCpuInformation();
226 glm::vec3 kernelUserAndSystem;
227 getCpuUsage(kernelUserAndSystem);
228 PROFILE_COUNTER(app,
"cpuProcess", { {
"system", kernelUserAndSystem.x }, {
"user", kernelUserAndSystem.y } });
229 PROFILE_COUNTER(app,
"cpuSystem", { {
"system", kernelUserAndSystem.z } });
231 QObject::connect(cpuMonitorThread, &QThread::finished, [=] {
232 timer->deleteLater();
233 cpuMonitorThread->deleteLater();