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

本文介绍如何使用 C/C++ 和 Windows 的性能监视器 API (PDH) 来监控 CPU 使用率。通过创建查询、添加计数器、收集数据等步骤,实现了一个简单的 CPU 使用率监测程序。

《编程之美》中的“让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。
以上五步中第二步构造描述计数器的字符串有些陌生。它牵扯到一个数据结构,这个数据结构的定义如下:

  1. typedef struct _PDH_COUNTER_PATH_ELEMENTS {  
  2.   LPTSTR  szMachineName;  
  3.   LPTSTR  szObjectName;  
  4.   LPTSTR  szInstanceName;  
  5.   LPTSTR  szParentInstance;  
  6.   DWORD   dwInstanceIndex;  
  7.   LPTSTR  szCounterName;  
  8. } PDH_COUNTER_PATH_ELEMENTS, *PPDH_COUNTER_PATH_ELEMENTS;  
 

  如果不知道如何填充这个数据结构,最好的办法就是打开性能监视器(开始——运行——输入“perfmon.msc”),在图表框中右击,选择添加计数器,在弹出的“添加计数器”对话框中,可以通过下柆列表或列表框选择计算机(数据结构的szMachineName项)、性能对象(szObjectName)、选择计数器(与Object对应的szCounterName)、选择范例(szInstanceName)。可以照着填充。
   在我的程序中需要获取CPU使用率。所以选择的对象是Processor,计数器是% Processor Time,范例是_Total。完整的程序代码如下:

  1. #undef UNICODE   
  2. #undef _UNICODE   
  3. #include <windows.h>   
  4. #include <tchar.h>   
  5. #include <stdio.h>   
  6. #include <pdh.h>   
  7.   
  8. #pragma comment(lib, "pdh.lib")   
  9.   
  10. HQUERY hQuery = NULL;  
  11.   
  12. // 处理ctrl-c异常   
  13. BOOL WINAPI HandlerRoutine(  
  14.   DWORD dwCtrlType   //  control signal type   
  15.   ) {  
  16.       if(dwCtrlType == CTRL_C_EVENT) {  
  17.           printf("ctrl c exception/n");  
  18.           if(hQuery) PdhCloseQuery(hQuery);  
  19.       }  
  20.       return false;  
  21. }  
  22.   
  23.   
  24. int main() {  
  25.     SetConsoleCtrlHandler(HandlerRoutine, TRUE);  
  26.   
  27.     PDH_STATUS pdhStatus;  
  28.   
  29.     // open query   
  30.     pdhStatus = PdhOpenQuery(0, 0, &hQuery);  
  31.     if(pdhStatus != ERROR_SUCCESS) {  
  32.         printf("PdhOpenQuery failed/n");  
  33.         exit(1);  
  34.     }  
  35.   
  36.     // construct a counter path   
  37.     PDH_COUNTER_PATH_ELEMENTS pcpe;  
  38.     TCHAR szFullPathBuffer[MAX_PATH] = TEXT("");  
  39.     DWORD dwSize = sizeof(szFullPathBuffer);  
  40.   
  41.     pcpe.szMachineName = TEXT("WANGHAIBIN");  
  42.     pcpe.szObjectName = TEXT("Processor");  
  43.     pcpe.szInstanceName = TEXT("_Total");  
  44.     pcpe.szCounterName = TEXT("% Processor Time");  
  45.     pcpe.dwInstanceIndex = -1;  
  46.     pcpe.szParentInstance = NULL;  
  47.   
  48.     pdhStatus = PdhMakeCounterPath(&pcpe, szFullPathBuffer, &dwSize, 0);  
  49.     if(pdhStatus != ERROR_SUCCESS) {  
  50.         printf("PdhMakeCounterPath failed/n");  
  51.         goto exit_prog;  
  52.     }  
  53.     _tprintf(TEXT("path: %s/n"), szFullPathBuffer);  
  54.   
  55.     // add a counter    
  56.     HCOUNTER hCounter;  
  57.     pdhStatus = PdhAddCounter(hQuery, szFullPathBuffer, 0, &hCounter);  
  58.     //pdhStatus = PdhAddCounter(hQuery, TEXT("//Processor(_Total)//% Processor Time"), 0, &hCounter);   
  59.     if(pdhStatus != ERROR_SUCCESS) {  
  60.         printf("PdhAddCounter failed/n");  
  61.         goto exit_prog;  
  62.     }  
  63.   
  64.     // collect query data   
  65.     pdhStatus = PdhCollectQueryData(hQuery);  
  66.     //pdhStatus = PdhCollectQueryDataEx(hQuery, 1, NULL);   
  67.     if(pdhStatus != ERROR_SUCCESS) {  
  68.         printf("PdhCollectQueryData failed/n");  
  69.         goto exit_prog;  
  70.     }  
  71.   
  72.     // get counter value   
  73.     PDH_FMT_COUNTERVALUE pfc;  
  74.     DWORD dwOpt;  
  75.   
  76.     pdhStatus = PdhGetFormattedCounterValue(  
  77.         hCounter,PDH_FMT_DOUBLE,&dwOpt,&pfc);  
  78.     while(pdhStatus == ERROR_SUCCESS) {  
  79.         //printf("%lf/n", pfc.doubleValue);   
  80.         pdhStatus = PdhCollectQueryData(hQuery);  
  81.         PdhGetFormattedCounterValue(hCounter, PDH_FMT_DOUBLE, &dwOpt, &pfc);  
  82.     }  
  83.   
  84. exit_prog:  
  85.     PdhCloseQuery(hQuery);  
  86.     return 0;  
  87. }  

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值