HifiExperimentsrefactor application.cppe6d7ffd2 years agoHistory
240 lines · 7.6 KB · C
RawDownload
////  WindowSystemInfo.h//  interface/src////  Split from Application.cpp by HifiExperiments on 3/30/24//  Created by Andrzej Kapolka on 5/10/13.//  Copyright 2013 High Fidelity, Inc.//  Copyright 2020 Vircadia contributors.//  Copyright 2022-2023 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//  SPDX-License-Identifier: Apache-2.0// #ifndef hifi_WindowSystemInfo_h#define hifi_WindowSystemInfo_h #include <qsystemdetection.h> #ifdef Q_OS_WIN#include <Windows.h>#include <TCHAR.h>#include <pdh.h>#pragma comment(lib, "pdh.lib")#pragma comment(lib, "ntdll.lib") #include <mutex>#include <string>#include <vector> #include <glm/glm.hpp> #include <QThread>#include <QTimer> #include "Profile.h"#include "ThreadHelpers.h" extern "C" {    enum SYSTEM_INFORMATION_CLASS {        SystemBasicInformation = 0,        SystemProcessorPerformanceInformation = 8,    };     struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {        LARGE_INTEGER IdleTime;        LARGE_INTEGER KernelTime;        LARGE_INTEGER UserTime;        LARGE_INTEGER DpcTime;        LARGE_INTEGER InterruptTime;        ULONG InterruptCount;    };     struct SYSTEM_BASIC_INFORMATION {        ULONG Reserved;        ULONG TimerResolution;        ULONG PageSize;        ULONG NumberOfPhysicalPages;        ULONG LowestPhysicalPageNumber;        ULONG HighestPhysicalPageNumber;        ULONG AllocationGranularity;        ULONG_PTR MinimumUserModeAddress;        ULONG_PTR MaximumUserModeAddress;        ULONG_PTR ActiveProcessorsAffinityMask;        CCHAR NumberOfProcessors;    };     NTSYSCALLAPI LONG NTAPI NtQuerySystemInformation(        _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,        _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,        _In_ ULONG SystemInformationLength,        _Out_opt_ PULONG ReturnLength    ); }template <typename T>LONG NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, T& t) {    return NtQuerySystemInformation(SystemInformationClass, &t, (ULONG)sizeof(T), nullptr);} template <typename T>LONG NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, std::vector<T>& t) {    return NtQuerySystemInformation(SystemInformationClass, t.data(), (ULONG)(sizeof(T) * t.size()), nullptr);}  template <typename T>void updateValueAndDelta(std::pair<T, T>& pair, T newValue) {    auto& value = pair.first;    auto& delta = pair.second;    delta = (value != 0) ? newValue - value : 0;    value = newValue;} struct MyCpuInfo {    using ValueAndDelta = std::pair<LONGLONG, LONGLONG>;    std::string name;    ValueAndDelta kernel { 0, 0 };    ValueAndDelta user { 0, 0 };    ValueAndDelta idle { 0, 0 };    float kernelUsage { 0.0f };    float userUsage { 0.0f };     void update(const SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpuInfo) {        updateValueAndDelta(kernel, cpuInfo.KernelTime.QuadPart);        updateValueAndDelta(user, cpuInfo.UserTime.QuadPart);        updateValueAndDelta(idle, cpuInfo.IdleTime.QuadPart);        auto totalTime = kernel.second + user.second + idle.second;        if (totalTime != 0) {            kernelUsage = (FLOAT)kernel.second / totalTime;            userUsage = (FLOAT)user.second / totalTime;        } else {            kernelUsage = userUsage = 0.0f;        }    }}; void updateCpuInformation() {    static std::once_flag once;    static SYSTEM_BASIC_INFORMATION systemInfo {};    static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuTotals;    static std::vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> cpuInfos;    static std::vector<MyCpuInfo> myCpuInfos;    static MyCpuInfo myCpuTotals;    std::call_once(once, [&] {        NtQuerySystemInformation( SystemBasicInformation, systemInfo);        cpuInfos.resize(systemInfo.NumberOfProcessors);        myCpuInfos.resize(systemInfo.NumberOfProcessors);        for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {            myCpuInfos[i].name = "cpu." + std::to_string(i);        }        myCpuTotals.name = "cpu.total";    });    NtQuerySystemInformation(SystemProcessorPerformanceInformation, cpuInfos);     // Zero the CPU totals.    memset(&cpuTotals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));    for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {        auto& cpuInfo = cpuInfos[i];        // KernelTime includes IdleTime.        cpuInfo.KernelTime.QuadPart -= cpuInfo.IdleTime.QuadPart;         // Update totals        cpuTotals.IdleTime.QuadPart += cpuInfo.IdleTime.QuadPart;        cpuTotals.KernelTime.QuadPart += cpuInfo.KernelTime.QuadPart;        cpuTotals.UserTime.QuadPart += cpuInfo.UserTime.QuadPart;         // Update friendly structure        auto& myCpuInfo = myCpuInfos[i];        myCpuInfo.update(cpuInfo);        PROFILE_COUNTER(app, myCpuInfo.name.c_str(), {            { "kernel", myCpuInfo.kernelUsage },            { "user", myCpuInfo.userUsage }        });    }     myCpuTotals.update(cpuTotals);    PROFILE_COUNTER(app, myCpuTotals.name.c_str(), {        { "kernel", myCpuTotals.kernelUsage },        { "user", myCpuTotals.userUsage }    });}  static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;static int numProcessors;static HANDLE self;static PDH_HQUERY cpuQuery;static PDH_HCOUNTER cpuTotal; void initCpuUsage() {    SYSTEM_INFO sysInfo;    FILETIME ftime, fsys, fuser;     GetSystemInfo(&sysInfo);    numProcessors = sysInfo.dwNumberOfProcessors;     GetSystemTimeAsFileTime(&ftime);    memcpy(&lastCPU, &ftime, sizeof(FILETIME));     self = GetCurrentProcess();    GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser);    memcpy(&lastSysCPU, &fsys, sizeof(FILETIME));    memcpy(&lastUserCPU, &fuser, sizeof(FILETIME));     PdhOpenQuery(NULL, NULL, &cpuQuery);    PdhAddCounter(cpuQuery, "\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);    PdhCollectQueryData(cpuQuery);} void getCpuUsage(glm::vec3& systemAndUser) {    FILETIME ftime, fsys, fuser;    ULARGE_INTEGER now, sys, user;     GetSystemTimeAsFileTime(&ftime);    memcpy(&now, &ftime, sizeof(FILETIME));     GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser);    memcpy(&sys, &fsys, sizeof(FILETIME));    memcpy(&user, &fuser, sizeof(FILETIME));    systemAndUser.x = (sys.QuadPart - lastSysCPU.QuadPart);    systemAndUser.y = (user.QuadPart - lastUserCPU.QuadPart);    systemAndUser /= (float)(now.QuadPart - lastCPU.QuadPart);    systemAndUser /= (float)numProcessors;    systemAndUser *= 100.0f;    lastCPU = now;    lastUserCPU = user;    lastSysCPU = sys;     PDH_FMT_COUNTERVALUE counterVal;    PdhCollectQueryData(cpuQuery);    PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);    systemAndUser.z = (float)counterVal.doubleValue;} void setupCpuMonitorThread() {    initCpuUsage();    auto cpuMonitorThread = QThread::currentThread();    setThreadName("CPU Monitor Thread");     QTimer* timer = new QTimer();    timer->setInterval(50);    QObject::connect(timer, &QTimer::timeout, [] {        updateCpuInformation();        glm::vec3 kernelUserAndSystem;        getCpuUsage(kernelUserAndSystem);        PROFILE_COUNTER(app, "cpuProcess", { { "system", kernelUserAndSystem.x }, { "user", kernelUserAndSystem.y } });        PROFILE_COUNTER(app, "cpuSystem", { { "system", kernelUserAndSystem.z } });    });    QObject::connect(cpuMonitorThread, &QThread::finished, [=] {        timer->deleteLater();        cpuMonitorThread->deleteLater();    });    timer->start();} #endif #endif  // hifi_WindowSystemInfo_h