在C/C++代码中使用windows性能监视器

               

《编程之美》中的“让CPU占用率曲线听你指挥”一题,作者给出的解法3非常清晰简洁。其思想就是直接查询当前CPU占用率,若过高则Sleep一段时间,否则一直循环。代码使用C#编写。于是自己想将这一思路使用C/C++来实现。
那么首先需要查清楚windows提供了哪些操作性能监视器(perfmon.msc)的API。在网上搜索一下,在vckbase上有一篇文章恰好是讲解这一主题的。这些操作性能监视器的API都以pdh开头。只要知道这一点,就可以在MSDN上查到完整资料。
在MSDN中的索引中输入PDH,列出的第一条主题就是:Platform SDK: Performance Monitoring—Using the PDH Interface.这篇概述文章中描述了PDH可以做什么以及如何使用它们。使用PDH接口操作性能监视器的方法可以概括为以下五个步骤:
1. 创建一个查询(Create a query)。相关的API是PdhOpenQuery。
2. 在已创建的查询中添加一个或多个计数器(Add counters to the query)。相关的API是PdhAddCounter。这个API需要一个描述计数器的字符串参数。MSDN上给出了四种构造符合语法的字符串的方法。其中最容易的方法是使用PdhMakeCounterPath函数。
3. 收集性能数据(collect the performance data)。与此相关的API是PdhCollectQueryData。
4. 处理这此收集到的性能数据(Process the performance data)。与此相关的有数个API。PdhGetFormattedCounterValue这个函数用来获得指定格式的数据。
5. 完成任务后,关闭这个查询(Close the query)。相关的API是PdhCloseQuery。
以上五步中第二步构造描述计数器的字符串有些陌生。它牵扯到一个数据结构,这个数据结构的定义如下:typedef struct _PDH_COUNTER_PATH_ELEMENTS {  LPTSTR  szMachineName;  LPTSTR  szObjectName;  LPTSTR  szInstanceName;  LPTSTR  szParentInstance;  DWORD   dwInstanceIndex;  LPTSTR  szCounterName;} PDH_COUNTER_PATH_ELEMENTS, *PPDH_COUNTER_PATH_ELEMENTS;  

  如果不知道如何填充这个数据结构,最好的办法就是打开性能监视器(开始——运行——输入“perfmon.msc”),在图表框中右击,选择添加计数器,在弹出的“添加计数器”对话框中,可以通过下柆列表或列表框选择计算机(数据结构的szMachineName项)、性能对象(szObjectName)、选择计数器(与Object对应的szCounterName)、选择范例(szInstanceName)。可以照着填充。
   在我的程序中需要获取CPU使用率。所以选择的对象是Processor,计数器是% Processor Time,范例是_Total。完整的程序代码如下:#undef UNICODE#undef _UNICODE#include <windows.h>#include <tchar.h>#include <stdio.h>#include <pdh.h>#pragma comment(lib, "pdh.lib")HQUERY hQuery = NULL;// 处理ctrl-c异常BOOL WINAPI HandlerRoutine(  DWORD dwCtrlType   //  control signal type  ) {   if(dwCtrlType == CTRL_C_EVENT) {    printf("ctrl c exception/n");    if(hQuery) PdhCloseQuery(hQuery);   }   return false;}int main() { SetConsoleCtrlHandler(HandlerRoutine, TRUE); PDH_STATUS pdhStatus; // open query pdhStatus = PdhOpenQuery(0, 0, &hQuery); if(pdhStatus != ERROR_SUCCESS) {  printf("PdhOpenQuery failed/n");  exit(1); } // construct a counter path PDH_COUNTER_PATH_ELEMENTS pcpe; TCHAR szFullPathBuffer[MAX_PATH] = TEXT(""); DWORD dwSize = sizeof(szFullPathBuffer); pcpe.szMachineName = TEXT("WANGHAIBIN"); pcpe.szObjectName = TEXT("Processor"); pcpe.szInstanceName = TEXT("_Total"); pcpe.szCounterName = TEXT("% Processor Time"); pcpe.dwInstanceIndex = -1; pcpe.szParentInstance = NULL; pdhStatus = PdhMakeCounterPath(&pcpe, szFullPathBuffer, &dwSize, 0); if(pdhStatus != ERROR_SUCCESS) {  printf("PdhMakeCounterPath failed/n");  goto exit_prog; } _tprintf(TEXT("path: %s/n"), szFullPathBuffer); // add a counter  HCOUNTER hCounter; pdhStatus = PdhAddCounter(hQuery, szFullPathBuffer, 0, &hCounter); //pdhStatus = PdhAddCounter(hQuery, TEXT("//Processor(_Total)//% Processor Time"), 0, &hCounter); if(pdhStatus != ERROR_SUCCESS) {  printf("PdhAddCounter failed/n");  goto exit_prog; } // collect query data pdhStatus = PdhCollectQueryData(hQuery); //pdhStatus = PdhCollectQueryDataEx(hQuery, 1, NULL); if(pdhStatus != ERROR_SUCCESS) {  printf("PdhCollectQueryData failed/n");  goto exit_prog; } // get counter value PDH_FMT_COUNTERVALUE pfc; DWORD dwOpt; pdhStatus = PdhGetFormattedCounterValue(  hCounter,PDH_FMT_DOUBLE,&dwOpt,&pfc); while(pdhStatus == ERROR_SUCCESS) {  //printf("%lf/n", pfc.doubleValue);  pdhStatus = PdhCollectQueryData(hQuery);  PdhGetFormattedCounterValue(hCounter, PDH_FMT_DOUBLE, &dwOpt, &pfc); }exit_prog: PdhCloseQuery(hQuery); return 0;}

    需要注意的是,上面的% Processor Time中的%和Processor之间有一个空格。不要写错了。
VCKBASE的那篇文章链接:http://www.vckbase.com/document/viewdoc/?id=1434

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自blog.csdn.net/qq_43668159/article/details/87114482