【问题标题】:Calculating CPU usage per core by WinAPI通过 WinAPI 计算每个内核的 CPU 使用率
【发布时间】:2020-07-28 16:43:00
【问题描述】:

我正在尝试使用 C++ 和 WinAPI 计算每个内核的 CPU 使用率,但我无法正确执行此操作。因此,我设法通过以下方式计算它:

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <windows.h>
#define SystemProcessorPerformanceInformation 0x8
#define SystemBasicInformation    0x0
int _tmain(int argc, _TCHAR* argv[])
{
    typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
    {
        LARGE_INTEGER IdleTime;
        LARGE_INTEGER KernelTime;
        LARGE_INTEGER UserTime;
        LARGE_INTEGER Reserved1[2];
        ULONG Reserved2;
    } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
    typedef struct _SYSTEM_BASIC_INFORMATION {
        ULONG Reserved;
        ULONG TimerResolution;
        ULONG PageSize;
        ULONG NumberOfPhysicalPages;
        ULONG LowestPhysicalPageNumber;
        ULONG HighestPhysicalPageNumber;
        ULONG AllocationGranularity;
        ULONG_PTR MinimumUserModeAddress;
        ULONG_PTR MaximumUserModeAddress;
        KAFFINITY ActiveProcessorsAffinityMask;
        CCHAR NumberOfProcessors;
    } SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
    //  SYSTEM_INFO  sysinf;

    if (argc<2)
    {
        printf("Please specify waiting time in seconds\n");
        return -1;
    }
    int nWaitSec = _wtoi(argv[1]);
    if (nWaitSec <= 0)
    {
        printf("Waiting interval in seconds should be positive integer\n");
        return -1;
    }
    typedef DWORD(WINAPI * PNTQUERYSYSYTEMINFORMATION)(DWORD info_class, void *out, DWORD size, DWORD *out_size);
    PNTQUERYSYSYTEMINFORMATION pNtQuerySystemInformation = NULL;

    pNtQuerySystemInformation = (PNTQUERYSYSYTEMINFORMATION)GetProcAddress(GetModuleHandle(L"NTDLL.DLL"), "NtQuerySystemInformation");
    SYSTEM_BASIC_INFORMATION sbi;
    SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION * spi;

    DWORD returnlength;
    DWORD status = pNtQuerySystemInformation(SystemBasicInformation, &sbi,
        sizeof(SYSTEM_BASIC_INFORMATION), &returnlength);

    spi = new SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[sbi.NumberOfProcessors];

    memset(spi, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*sbi.NumberOfProcessors);

    status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, spi,
        (sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*sbi.NumberOfProcessors), &returnlength);
    int numberOfCores = returnlength / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);

    printf("Number of cores: %d\n", numberOfCores);
    static ULARGE_INTEGER  ul_sys_idle_old[32];
    static ULARGE_INTEGER  ul_sys_kernel_old[32];
    static ULARGE_INTEGER  ul_sys_user_old[32];

    float          usage = 0;
    float          usageAccum = 0;

    printf("\n\nWait for %d seconds\n", nWaitSec);
    Sleep(nWaitSec*1000);
    status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, spi,
        (sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*numberOfCores), &returnlength);
    usageAccum = 0;
    for (int ii = 0; ii<numberOfCores; ii++)
    {
        ULARGE_INTEGER        ul_sys_idle;
        ULARGE_INTEGER        ul_sys_kernel;
        ULARGE_INTEGER        ul_sys_user;

        ul_sys_idle.QuadPart = spi[ii].IdleTime.QuadPart;
        ul_sys_kernel.QuadPart = spi[ii].KernelTime.QuadPart;
        ul_sys_user.QuadPart = spi[ii].UserTime.QuadPart;

        ULONGLONG kernelTime = (ul_sys_kernel.QuadPart - ul_sys_kernel_old[ii].QuadPart);
        ULONGLONG usertime = (ul_sys_user.QuadPart - ul_sys_user_old[ii].QuadPart);
        ULONGLONG idletime = (ul_sys_idle.QuadPart - ul_sys_idle_old[ii].QuadPart);

        ULONGLONG proctime = kernelTime + usertime - idletime;

        ULONGLONG totaltime = kernelTime + usertime;

        usage = (float)(proctime * 100) / totaltime;
        usageAccum += usage;
        printf("Core        : %u: Usage      : %f%%\n", ii + 1, usage);
    }
    usageAccum /= numberOfCores;
    printf("----------------\nAverage for the last %d seconds: %f", nWaitSec, usageAccum);
    delete[] spi;
    return 0;
}

尽管如此,它似乎以错误的方式计算,因为它的输出数据几乎没有变化。如何正确找到每个内核的 CPU 使用率?

【问题讨论】:

  • 好问题!答案可能没有记录。
  • 请看How to Ask。
  • 尝试引用 tp NtQuerySystemInformation。它将返回一个 SYSTEM_PROCESS_INFORMATION 结构的数组,一个用于系统中运行的每个进程。这些结构包含有关每个进程的资源使用情况的信息,包括进程使用的句柄数、页面文件使用峰值以及进程已分配的内存页数。

标签: c++ windows winapi cpu-usage


【解决方案1】:

这三个数组在你的源代码中并不是实时更新的,所以在循环中它们的值总是0。

static ULARGE_INTEGER  ul_sys_idle_old[32];
static ULARGE_INTEGER  ul_sys_kernel_old[32];
static ULARGE_INTEGER  ul_sys_user_old[32];

得到的是长时间运行的CPU使用时间,基数很大,导致基本没有变化。

您可以参考Correct way to get Windows CPU utilization for multiprocessor 并更新您的数组以获得正确的结果。

【讨论】:

    猜你喜欢
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    相关资源
    最近更新 更多