Windows性能计数器

一、性能计数器概述
  性能监视,是Windows NT提供的一种系统功能。Windows NT一直以来总是集成了性能监视工具,它提供有关操作系统当前运行状况的信息,针对各种对象提供了数百个性能计数器。性能对象,就是被监视的对象,典型例子有Processor、Process、Memory、TCP/UDP/IP/ICMP、PhysicalDisk等。计数器通常提供操作系统、应用程序、服务、驱动程序等的性能相关信息,以此来分析系统瓶颈和对系统及应用程序性能进行诊断和调优。性能计数器机制让应用程序和操作系统组件可以向性能监视应用程序,比如性能监视器(Performance Monitor),报告一些与性能有关的统计信息。PerfMon.exe中可以查看性能对象、性能计数器和对象实例,可通过添加计数器来查看相关描述信息。

  实际上,可以通过编写程序来访问所有的Windows性能计数器。Windows中,注册表是访问性能计数器的一种机制。性能信息并不实际存在于注册表中,在注册表编辑器RegEdit.exe中是无法查看的,但可以通过注册表函数来访问,利用注册表键来获得从性能数据提供者那里提供的数据。打开名为HKEY_PERFORMANCE_DATA的特殊键,利用RegQueryValueEx函数查询键下面的值,就可以直接访问注册表性能计数器信息。当然,也可以利用性能数据帮助器(PDH, Performance Data Helper) API (Pdh.dll)来访问性能计数器信息。

二、相关术语
性能对象(Performance Object):被监视的性能对象,如Processor、Process、Memory、PhysicalDisk等,相当于类(Class)。
性能计数器(Performance Counter):描述性能对象性能信息的方式,相当于类属性。
对象实例(Object Instance):相同性能对象可能有多个,把它们表示为该对象类型的不同实例,相当于类实例。

三、HKEY_PERFORMANCE_DATA数据组织
  性能数据的头部是一个PERF_DATA_BLOCK结构(如图1所示),它描述系统和性能数据总体信息,可从Global键值处查询得到该结构数据。PERF_DATA_BLOCK之后,定义了系统中的全部性能对象类型(PERF_OBJECT_TYPE),其中每个对象类型头部中描述了下一个性能对象类型的偏移量Offset。
图1  图1图2图2


  性能对象有两种:一种是单实例对象,另一种是多实例对象。图2和图3分别描述了这两种性能对象的数据组织方式。每个对象数据块包含了一个PERF_OBJECT_TYPE结构,描述对象的性能数据。紧随其后是PERF_COUNTER_DEFINITION结构列表,描述了性能对象的全部计数器定义。对于单实例对象,计数器定义列表后是一个PERF_COUNTER_BLOCK结构,计数器数据紧随其后。每个PERF_COUNTER_DEFINITION结构中定义了计数器数据相对于PERF_COUNTER_BLOCK的偏移量,因此可以非常方便地获得全部计数器的值。对支持多实例性能对象来说,PERF_COUNTER_DEFINITION结构列表之后是一组实例信息数据块,每个表示代表一个对象实例。每个实例信息数据块由一个PERF_INSTANCE_DEFINITION结构体、实例名和一个PERF_COUNTER_BLOCK结构体组成。后面是计数器值数据,与单实例对象相同。

图3图3

四、一个简单性能计数器查看器的实现
  基于以上的知识和一些参考文献,本人在Windows Xp Sp3 + VS2003环境下实现了一个Windows性能计数器查看器。界面如图4所示,核心部分代码如下:

图4

1、头文件winperf.h

#ifndef _WINPERF #define _WINPERF #include "stdafx.h" #include <windows.h> #include <tchar.h> #include <io.h> #include <conio.h> #include <string.h> #include <stdio.h> #include <strsafe.h> #include <winperf.h> #include <String> #include <vector> #include <map> #include <iostream> using namespace std; #define INITIAL_SIZE 51200 #define EXTEND_SIZE 25600 #define PERF_SUBKEY_GLOBAL _T("Global") #define REGSUBKEY_COUNTERS _T("Counters") typedef map <DWORD, DWORD>::const_iterator CIT; BOOL ConnectComputerPerformanceRegistry(LPCSTR lpMachineName, HKEY &hKey); BOOL GetNameStrings(HKEY hKey, map <DWORD, LPSTR> &mPerfObjectIndex); BOOL EnumPerfObjects(HKEY hKey, vector <PERF_OBJECT_TYPE> &vPerfObjects); BOOL LoadObjectData(HKEY hKey, DWORD dwObjIndex, map <DWORD, LPSTR> mPerfCountersIndex, / CListBox *pCListBoxCounters, CListCtrl *pCListCtrlInstances); #endif
2、连接(远程)计算机性能计数器注册表

BOOL ConnectComputerPerformanceRegistry(LPCSTR lpMachineName, HKEY &hKey) { DWORD retCode; retCode = RegConnectRegistry(lpMachineName, HKEY_PERFORMANCE_DATA, &hKey); return (retCode == ERROR_SUCCESS) ? TRUE : FALSE; }

3、枚举性能对象

static inline PPERF_OBJECT_TYPE FirstObject(PPERF_DATA_BLOCK PerfData) { return((PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength)); } static inline PPERF_OBJECT_TYPE NextObject(PPERF_OBJECT_TYPE PerfObj) { return((PPERF_OBJECT_TYPE)((PBYTE)PerfObj + PerfObj->TotalByteLength)); } BOOL EnumPerfObjects(HKEY hKey, vector <PERF_OBJECT_TYPE> &vPerfObjects) { DWORD retCode = ERROR_MORE_DATA; DWORD dwType = 0; DWORD dwSize = 0; PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK)malloc(INITIAL_SIZE); PPERF_OBJECT_TYPE PPerfObj; while (retCode == ERROR_MORE_DATA) { dwSize += EXTEND_SIZE; PerfData = (PPERF_DATA_BLOCK)realloc(PerfData, dwSize); retCode = RegQueryValueEx(hKey, PERF_SUBKEY_GLOBAL, 0, &dwType, (LPBYTE)PerfData, &dwSize); } if (retCode != ERROR_SUCCESS) return FALSE; PPerfObj = FirstObject(PerfData); for (int i = 0; i < PerfData->NumObjectTypes; i++) { PERF_OBJECT_TYPE PerfObj; memcpy(&PerfObj, PPerfObj, sizeof(PERF_OBJECT_TYPE)); vPerfObjects.push_back(PerfObj); PPerfObj = NextObject(PPerfObj); } return TRUE; }

4、获取性能计数器名字

BOOL GetNameStrings(HKEY hKey, map <DWORD, LPSTR> &mPerfObjectIndex) { DWORD retCode = 0; DWORD dwType = 0; DWORD dwSize = 0; LPBYTE buffer = NULL; LPSTR p, p2; LPSTR lpCurrentString; DWORD dwCounter = 0; retCode = RegQueryValueEx(hKey, REGSUBKEY_COUNTERS, NULL, &dwType, NULL, &dwSize); if (retCode != ERROR_SUCCESS) { perror("RegQueryValueEx REGSUBKEY_COUNTERS Size"); return FALSE; } buffer = (LPBYTE)malloc(dwSize); memset(buffer, 0, dwSize); retCode = RegQueryValueEx(hKey, REGSUBKEY_COUNTERS, NULL, &dwType, buffer, &dwSize); if (retCode != ERROR_SUCCESS) { perror("RegQueryValueEx REGSUBKEY_COUNTERS Content"); return FALSE; } p = (LPSTR) buffer; for(lpCurrentString = p; *lpCurrentString; lpCurrentString += (lstrlen(lpCurrentString) + 1)) { dwCounter = atol(lpCurrentString); lpCurrentString += (lstrlen(lpCurrentString) + 1); mPerfObjectIndex[dwCounter] = (LPSTR)lpCurrentString; } return TRUE; }

5、枚举性能对象实例和计数器值

BOOL LoadObjectData(HKEY hKey, DWORD dwObjIndex, map <DWORD, LPSTR> mPerfCountersIndex, / CListBox *pCListBoxCounters, CListCtrl *pCListCtrlInstances) { TCHAR szSubKey[1024] = {0}; DWORD rt = 0; DWORD dwType = 0; DWORD dwSize = 0; LPBYTE buffer = NULL; BOOL bPass = TRUE; map <DWORD, string> mCounters; map <DWORD, DWORD> mOffsets; map <DWORD, int> mIndexs; LPSTR p; PPERF_DATA_BLOCK pPerf; PPERF_OBJECT_TYPE pObj; PPERF_INSTANCE_DEFINITION pInst; PPERF_COUNTER_BLOCK pCounter; PPERF_COUNTER_DEFINITION pCounterDef; buffer = NULL; dwSize = INITIAL_SIZE; buffer = (LPBYTE) malloc(dwSize); memset(buffer, 0, dwSize); wsprintf(szSubKey, "%u", dwObjIndex); // get Object PERF_DATA_BLOCK while (bPass) { rt = RegQueryValueEx(hKey, szSubKey, NULL, &dwType, buffer, &dwSize); pPerf = (PPERF_DATA_BLOCK) buffer; if ((rt == ERROR_SUCCESS) && (dwSize > 0) && pPerf->Signature[0] == (WCHAR)'P' && pPerf->Signature[1] == (WCHAR)'E' && pPerf->Signature[2] == (WCHAR)'R' && pPerf->Signature[3] == (WCHAR)'F') { break; } if (rt == ERROR_MORE_DATA) { dwSize += EXTEND_SIZE; buffer = (LPBYTE)realloc(buffer, dwSize ); memset(buffer, 0, dwSize ); } else { bPass = FALSE; } } if (bPass) { // get Counters pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf->HeaderLength); pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD)pObj + pObj->HeaderLength); pCListCtrlInstances->InsertColumn(0, (LPCTSTR)(mPerfCountersIndex[dwObjIndex]), LVCFMT_LEFT, 120); for (DWORD i = 0; i < (DWORD)pObj->NumCounters; i++) { mOffsets[pCounterDef->CounterNameTitleIndex] = pCounterDef->CounterOffset; mIndexs[pCounterDef->CounterNameTitleIndex] = i + 1; pCListBoxCounters->InsertString(i, (LPCTSTR)(mPerfCountersIndex[pCounterDef->CounterNameTitleIndex])); pCListCtrlInstances->InsertColumn(i + 1, (LPCTSTR)(mPerfCountersIndex[pCounterDef->CounterNameTitleIndex]), LVCFMT_LEFT, 120); pCounterDef++; } // get instances if (pObj->NumInstances == 0 || PERF_NO_INSTANCES == pObj->NumInstances) { // no instances pCounter = (PPERF_COUNTER_BLOCK)((DWORD)pObj + pObj->DefinitionLength); pCListCtrlInstances->InsertItem(0, "None"); for(CIT p = mOffsets.begin(); p != mOffsets.end(); ++p) { DWORD counterVal = *((LPDWORD) ((DWORD)pCounter + p->second)); char info[256] = {0}; wsprintf(info, "%u", counterVal); pCListCtrlInstances->SetItemText(0, mIndexs[p->first], info); } } else { // muiti-instances case TCHAR szInstanceName[MAX_PATH]; pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj->DefinitionLength); for (i = 0; i < (DWORD)pObj->NumInstances; i++) { p = (LPSTR) ((DWORD)pInst + pInst->NameOffset); rt = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)p, -1, szInstanceName, sizeof(szInstanceName), NULL, NULL); pCListCtrlInstances->InsertItem(i, szInstanceName); for(CIT p = mOffsets.begin(); p != mOffsets.end(); ++p) { pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst->ByteLength); DWORD counterVal = *((LPDWORD) ((DWORD)pCounter + p->second)); char info[256] = {0}; wsprintf(info, "%u", counterVal); pCListCtrlInstances->SetItemText(i, mIndexs[p->first], info); } // Point to the next process pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter->ByteLength); } } }// end if (bPass) if (buffer) { free(buffer); buffer = NULL; } return bPass; }

五、参考文献
[1] 深入解析Windows操作系统(第四版), Mark E.Russinovich & David A.Solomon.
[2] Using Performance Counters, MSDN. http://msdn.microsoft.com/en-us/library/aa373209(VS.85).aspx.
[3] 纵谈进程枚举, 陆其明. http://jasonye.bokee.com/432054.html.
[4] 如何编程获取Windows NT的性能数据, 周京生. http://www.comprg.com.cn/detail.asp?hw_id=2643.

(Aiguille LIU / 刘爱贵 / Aigui.liu@gmail.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值