Правильный способ получения Windows загрузки ЦП для мультипроцессора - PullRequest
2 голосов
/ 14 июля 2020

Чего я хочу достичь, так это того, что я могу получить все загрузки ЦП (у меня 4 ядра ЦП, поэтому я ожидаю, что смогу получить их все, как в resmon.exe) и их сумму (как в TaskManager.exe)

resmon.exe

I have read on some soure on how I can get the processors utilization is by doing some math on the CPU time. I tried to use 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;
}

И чтобы получить индивидуальную загрузку ЦП, мне не нужно суммировать все процессоры, просто выберите один из элементов массива SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_R.

Мой вопрос:

  1. Правильно ли я делаю? Потому что, когда я проверяю свою программу с использованием ЦП в TaskManager.exe, она несколько отличается.

enter image description here

  1. Есть ли лучший подход, кроме использования NtQuerySystemInformation ( Поскольку Microsoft упомянула «NtQuerySystemInformation может быть изменен или недоступен в будущих версиях Windows. Приложения должны использовать альтернативные функции, перечисленные в этом топе c.»)?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...