首页 > 解决方案 > 获取多处理器的 Windows CPU 利用率的正确方法

问题描述

我想要实现的是我可以获得每个 CPU 的利用率(我有 4 个 CPU 核心,所以我希望我可以resmon.exeTaskManager.exe

resmon.exe

我已经阅读了一些关于如何通过对 CPU 时间进行数学计算来获得处理器利用率的问题。我试图用它NtQuerySystemInformation来获取必要的数据。

#include <windows.h>
#include <vector>
#include <iostream>
#include <winternl.h>

#pragma comment(lib, "Ntdll.lib")

typedef struct
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R {
    LARGE_INTEGER IdleTime;
    LARGE_INTEGER KernelTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER DpcTime;
    LARGE_INTEGER InterruptTime;
    ULONG InterruptCount;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R;

static long long toInteger(LARGE_INTEGER const & integer)
{
#ifdef INT64_MAX // Does the compiler natively support 64-bit integers?
        return integer.QuadPart;
#else
        return (static_cast<long long>(integer.HighPart) << 32) | integer.LowPart;
#endif
}

class CPU
{
public:
    uint64_t prev_idle = 0;
    uint64_t prev_ker = 0;
    uint64_t prev_user = 0;
    uint64_t cur_idle = 0;
    uint64_t cur_ker = 0;
    uint64_t cur_user = 0;

    double get()
    {
        SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R *a = new SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R[4];
        // 4 is the total of CPU (4 cores)
        NtQuerySystemInformation(SystemProcessorPerformanceInformation, a, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R) * 4, NULL);

        prev_idle = cur_idle;
        prev_ker = cur_ker;
        prev_user = cur_user;

        cur_idle = 0;
        cur_ker = 0;
        cur_user = 0;

        // 4 is the total of CPU (4 cores)
        // Sum up the SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R array so I can get the utilization from all of the CPU
        for (int i = 0; i < 4; ++i)
        {
            SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R b = a[i];
            cur_idle += toInteger(b.IdleTime);
            cur_ker += toInteger(b.KernelTime);
            cur_user += toInteger(b.UserTime);
        }

        std::cout << "Cur idle " << cur_idle << '\n';
        std::cout << "Cur ker " << cur_ker << '\n';
        std::cout << "Cur user " << cur_user << '\n';

        uint64_t delta_idle = cur_idle - prev_idle;
        uint64_t delta_kernel = cur_ker - prev_ker;
        uint64_t delta_user = cur_user - prev_user;
        
        std::cout << "Delta idle " << delta_idle << '\n';
        std::cout << "Delta ker " << delta_kernel << '\n';
        std::cout << "Delta user " << delta_user << '\n';

        uint64_t total_sys = delta_kernel + delta_user;
        uint64_t kernel_total = delta_kernel - delta_idle;

        delete[] a;
        // return (total_sys - delta_idle) * 100.0 / total_sys;
        return (kernel_total + delta_user) * 100.0 / total_sys;
    }
};

int main()
{
    CPU a;
    std::cout << "starting" << '\n';
    while(1)
    {
        std::cout << a.get() << '\n';
        Sleep(1000);
    }
    return 0;
}

为了获得单个 CPU 利用率,我不必对所有 CPU 求和,只需选择一个SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R数组元素即可。

我的问题是

  1. 我做对了吗?因为当我在 TaskManager.exe 中检查我的程序的 CPU 利用率时,它有些不同。

在此处输入图像描述

  1. 除了使用之外还有什么更好的方法NtQuerySystemInformation(因为微软已经提到“NtQuerySystemInformation 在未来的 Windows 版本中可能会被更改或不可用。应用程序应该使用本主题中列出的替代功能。”)?

标签: c++windowswinapi

解决方案


推荐阅读