使用“超线程”正确测量CPU使用情况

Correctly measure CPU usage with HyperThreading?

本文关键字:超线程 CPU 用情 测量 情况 使用      更新时间:2023-10-16

我知道SO上有几个关于如何使用以下两种方法之一测量CPU使用率的答案:

  • 通过使用性能计数器(PDH API)
  • 通过使用GetProcessTime()并将其除以墙时间或GetSystemTime()中的时间

几天来,我无法用这两种机制中的任何一种对我的程序进行CPU使用率测量,这两种方法的CPU使用率都小于任务管理器或Process Explorer中显示的。这些工具是如何做到这一点的?这与启用超线程有关吗?我将在没有HyperThring的CPU上进行测试,但如果有人能指出我在这里遗漏了什么,我将非常感谢。

为了说明我所尝试的,以下是进行基于PDH的测量的代码:

class CCpuUsageMonitor
{
public:
    CCpuUsageMonitor(const wchar_t* pProcessName)
    {
        GetSystemInfo(&m_SystemInfo);
        auto nStatus = PdhOpenQuery(NULL, NULL, &m_hPdhQuery);
        _ASSERT(nStatus == ERROR_SUCCESS);
        nStatus = PdhAddCounter(m_hPdhQuery, L"\Processor(_Total)\% Processor Time", NULL, &m_hPdhCpuUsageCounter);
        _ASSERT(nStatus == ERROR_SUCCESS);
        wchar_t pCounterPath[PDH_MAX_COUNTER_PATH];
        StringCbPrintf(pCounterPath, PDH_MAX_COUNTER_PATH, L"\Process(%s)\%% Processor Time", pProcessName);
        nStatus = PdhAddCounter(m_hPdhQuery, pCounterPath, NULL, &m_hPhdProcessCpuUsageCounter);
        _ASSERT(nStatus == ERROR_SUCCESS);
    }
    ~CCpuUsageMonitor()
    {
        PdhCloseQuery(&m_hPdhQuery);
    }
    void CollectSample()
    {
        auto nStatus = PdhCollectQueryData(m_hPdhQuery);
        _ASSERT(nStatus == ERROR_SUCCESS);
    }
    double GetCpuUsage()
    {
        DWORD nType;
        PDH_FMT_COUNTERVALUE CounterValue;
        auto nStatus = PdhGetFormattedCounterValue(m_hPdhCpuUsageCounter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &nType, &CounterValue);
        _ASSERT(nStatus == ERROR_SUCCESS);
        return CounterValue.doubleValue;
    }
    double GetProcessCpuUsage()
    {
        DWORD nType;
        PDH_FMT_COUNTERVALUE CounterValue;
        auto nStatus = PdhGetFormattedCounterValue(m_hPhdProcessCpuUsageCounter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &nType, &CounterValue);
        _ASSERT(nStatus == ERROR_SUCCESS);
        return CounterValue.doubleValue / m_SystemInfo.dwNumberOfProcessors;
    }
private:
    SYSTEM_INFO m_SystemInfo;
    HANDLE m_hPdhQuery;
    HANDLE m_hPdhCpuUsageCounter;
    HANDLE m_hPhdProcessCpuUsageCounter;
};

使用第二种方法,我基本上在代码运行前后通过GetProcessTime()获取两个进程时间的快照,根据墙时间乘以处理器数量进行减法和除法。

以下是我过去使用过的几个链接,以及一篇关于GetThreadTimes错误原因的好文章(我不会将其用作可靠的数据源):

http://blog.kalmbachnet.de/?postid=28

https://msdn.microsoft.com/en-us/library/aa392397(VS.85).aspx

http://www.drdobbs.com/windows/win32-performance-measurement-options/184416651

https://msdn.microsoft.com/en-us/library/aa394279(VS.85).aspx

你看起来很顺利,而且知识渊博,这些链接至少会让你朝着正确的方向前进。

从此链接:

从Windows 8开始,任务管理器和性能监视器报告CPU利用率的方式发生了变化。。。

此更改会影响CPU利用率的计算方式。任务管理器中的值现在对应于处理器信息\%Processor Utility处理程序信息\%Privileged Utility能计数器,而不是像Windows 7中那样对应于处理器信息\%Processor Timerocessor Information \%Privilged Time计数器。

您的代码将按照编写的方式工作,而不是更改查询的计数器。您正在使用处理器计数器;您应该切换到在Windows 8中启用的处理器信息;并且还使用";"效用";计数器的版本。

如果您像当前一样查询格式化的值,那么通过1秒的轮询,您将在任务管理器上显示相同的数字。

如果要在较长的时间间隔内进行计算,可以查询原始值;将数字转换为CCD_ 1结构,而不是当前的CCD_。用于计算分子使用的值在PDH_RAW_COUNTER结构的FirstValue中;基本";分母的值在CCD_ 5中。