在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

你可能感兴趣的:(数据结构,windows,api,query,Path,performance)