1. performance counters Overview
Performance monitoring is a system function provided by Windows NT. Windows NT has always integrated a performance monitoring tool that provides information about the current operating status of the operating system and provides hundreds of performance counters for various objects. A performance object is a Monitored object. Typical examples include processor, process, memory, TCP/UDP/IP/ICMP, and physicaldisk. Counters generally provide performance-related information about operating systems, applications, services, and drivers to analyze system bottlenecks and diagnose and Optimize System and Application Performance. The performance counter mechanism allows applications and operating system components to monitor performance applications, such as performance monitor, and report performance-related statistics. Perfmon.exe allows you to view performance objects, performance counters, and object instances. You can add counters to view related descriptions.
In fact, you can write programs to access all Windows performance counters. In Windows, the Registry is a mechanism for accessing performance counters. The property information does not exist in the registration table. It cannot be viewed in the Registration Table editor regedit.exe, but can be accessed through the registry function. The registry key is used to obtain the data provided from the performance data provider. Open the special key named hkey_performance_data and use the regqueryvalueex function to query the values under the key to directly access the Registry performance counter information. Of course, you can also use the performance data helper (PDH, performance data helper) API (PDH. dll) to access the performance counter information.
Ii. Related Terms
Performance object: a monitored performance object, such as processor, process, memory, and physicaldisk, which is equivalent to a class ).
Performance counters: Describes the performance information of performance objects, which is equivalent to class attributes.
Object instance: There may be multiple objects with the same performance, and they are represented as different instances of the object type, which is equivalent to class instances.
3. hkey_performance_data Data Organization
The header of the performance data is a perf_data_block structure (1), which describes the overall information of the system and performance data. You can obtain the structure data from the global key value query. Perf_data_block defines all the performance object types (perf_object_type) in the system. The offset of the next performance object type is described in the header of each object type.
Figure 1 Figure 2
There are two types of performance objects: one is a single instance object and the other is a multi-instance object. Figure 2 and Figure 3 respectively describe the data organization methods of these two performance objects. Each object data block contains a perf_object_type structure that describes the object's performance data. Followed by the perf_counter_definition structure list, which describes all the counter definitions of performance objects. For a single instance object, the counter definition list is followed by a perf_counter_block structure, followed by counter data. Each perf_counter_definition structure defines the offset between the counter data and the perf_counter_block, so you can easily obtain all the counter values. For multi-instance performance objects, the perf_counter_definition structure list is followed by a group of instance information data blocks, each representing an object instance. Each instance information data block consists of a perf_instance_definition struct, Instance name, and a perf_counter_block struct. The following is the counter value data, which is the same as the single instance object.
Figure 3
IV. Implementation of a simple performance counter Viewer
Based on the above knowledge and some references, I have implemented a Windows performance counter viewer in the Windows XP SP3 + vs2003 environment. As shown in interface 4, the core code is as follows:
1. the header file winperf. h
# Ifndef _ winperf <br/> # DEFINE _ winperf </P> <p> # include "stdafx. H "<br/> # include <windows. h> <br/> # include <tchar. h> <br/> # include <Io. h> <br/> # include <conio. h> <br/> # include <string. h> <br/> # include <stdio. h> <br/> # include <strsafe. h> <br/> # include <winperf. h> <br/> # include <string> <br/> # include <vector> <br/> # include <map> <br/> # include <iostream> <br /> using namespace STD; </P> <p> # define initial_size 51200 <br/> # define extend_size 25600 <br/> # define perf_subkey_global_t ("Global ") <br/> # define regsubkey_counters _ T ("counters") </P> <p> typedef Map <DWORD, DWORD >:: const_iterator cit; </P> <p> bool connectcomputerperformanceregistry (lpcstr lpmachinename, hkey & hkey); <br/> bool getnamestrings (hkey, Map <DWORD, lpstr> & mperfobjectindex ); <br/> bool aggregate (hkey, vector <perf_object_type> & vperfobjects); <br/> bool loadobjectdata (hkey, DWORD dwobjindex, Map <DWORD, lpstr> mperfcountersindex, /<br/> clistbox * pclistboxcounters, clistctrl * pclistctrlinstances); </P> <p> # endif
2. Connect to the (remote) computer performance counter Registry
Bool encode (lpcstr lpmachinename, hkey & hkey) <br/>{< br/> DWORD retcode; </P> <p> retcode = regconnectregistry (lpmachinename, hkey_performance_data, & hkey); <br/> return (retcode = error_success )? True: false; <br/>}
3. enumerate performance objects
Static inline pperf_object_type firstobject (pperf_data_block perfdata) <br/>{< br/> return (pperf_object_type) (pbyte) perfdata + perfdata-> headerlength )); <br/>}</P> <p> static inline pperf_object_type nextobject (pperf_object_type perfobj) <br/>{< br/> return (pperf_object_type) (pbyte) perfobj + perfobj-> totalbytelength); <br/>}</P> <p> bool enumperfobjects (hkey, vector <perf_object_type> & vperfob Jects) <br/>{< br/> DWORD retcode = error_more_data; <br/> DWORD dwtype = 0; <br/> DWORD dwsize = 0; <br/> pperf_data_block perfdata = (pperf_data_block) malloc (initial_size); <br/> pperf_object_type pperfobj; </P> <p> while (retcode = error_more_data) <br/>{< br/> dwsize + = extend_size; <br/> perfdata = (pperf_data_block) realloc (perfdata, dwsize); <br/> retcode = regqueryvalueex (hkey, perf_subkey_global, 0, & Dwtype, (lpbyte) perfdata, & dwsize); <br/>}< br/> If (retcode! = Error_success) <br/> return false; </P> <p> pperfobj = firstobject (perfdata); <br/> for (INT I = 0; I <perfdata-> numobjecttypes; I ++) <br/>{< br/> perf_object_type perfobj; <br/> memcpy (& perfobj, pperfobj, sizeof (perf_object_type )); <br/> vperfobjects. push_back (perfobj); <br/> pperfobj = nextobject (pperfobj); <br/>}</P> <p> return true; <br/>}
4. Get the performance counter name
Bool getnamestrings (hkey, Map <DWORD, lpstr> & mperfobjectindex) <br/>{< br/> DWORD retcode = 0; <br/> DWORD dwtype = 0; <br/> DWORD dwsize = 0; <br/> lpbyte buffer = NULL; <br/> lpstr P, P2; <br/> lpstr lpcurrentstring; <br/> DWORD dwcounter = 0; </P> <p> retcode = regqueryvalueex (hkey, regsubkey_counters, null, & dwtype, null, & dwsize ); <br/> If (retcode! = Error_success) <br/>{< br/> perror ("regqueryvalueex regsubkey_counters size"); <br/> return false; <br/>}</P> <p> buffer = (lpbyte) malloc (dwsize); <br/> memset (buffer, 0, dwsize ); <br/> retcode = regqueryvalueex (hkey, regsubkey_counters, null, & dwtype, buffer, & dwsize); <br/> If (retcode! = Error_success) <br/>{< br/> perror ("regqueryvalueex regsubkey_counters content"); <br/> return false; <br/>}</P> <p> P = (lpstr) buffer; <br/>) + 1) <br/>{< br/> dwcounter = atol (lpcurrentstring); <br/> lpcurrentstring ++ = (lstrlen (lpcurrentstring) + 1 ); <br/> mperfobjectindex [dwcounter] = (lpstr) lpcurrentstring; <br/>}</P> <p> return true; <br/>}
5. enumerate performance object instances and counter values
Bool loadobjectdata (hkey, DWORD dwobjindex, Map <DWORD, lpstr> mperfcountersindex,/<br/> clistbox * pclistboxcounters, clistctrl * pclistctrlinstances) <br/>{< br/> tchar szsubkey [1024] = {0 }; <br/> dword rt = 0; <br/> DWORD dwtype = 0; <br/> DWORD dwsize = 0; <br/> lpbyte buffer = NULL; <br/> bool bpass = true; <br/> Map <DWORD, string> mcounters; <br/> Map <DWORD, DWORD> moffsets; <br/> Map <DWORD, in T> mindexs; </P> <p> lpstr P; <br/> pperf_data_block pperf; <br/> pperf_object_type pobj; <br/> pperf_instance_definition pinst; <br/> pperf_counter_block pcounter; <br/> pperf_counter_definition pcounterdef; </P> <p> buffer = NULL; <br/> dwsize = initial_size; <br/> buffer = (lpbyte) malloc (dwsize); <br/> memset (buffer, 0, dwsize); <br/> wsprintf (szsubkey, "% u ", dwobjindex); <br/> // get object perf_data_block <B R/> while (bpass) <br/>{< br/> RT = regqueryvalueex (hkey, szsubkey, null, & dwtype, buffer, & dwsize ); <br/> pperf = (pperf_data_block) buffer; <br/> If (RT = error_success) & (dwsize> 0) & <br/> pperf-> signature [0] = (wchar) 'P' & <br/> pperf-> signature [1] = (wchar) 'E' & <br/> pperf-> signature [2] = (wchar) 'R' & <br/> pperf-> signature [3] = (wchar) 'F') <br/>{< br/> break; <br/>}</P> <p> If (RT = ER Ror_more_data) <br/>{< br/> dwsize + = extend_size; <br/> buffer = (lpbyte) realloc (buffer, dwsize); <br/> memset (buffer, 0, dwsize); <br/>}< br/> else <br/>{< br/> bpass = false; <br/>}</P> <p> If (bpass) <br/> {<br/> // get counters <br/> pobj = (pperf_object_type) (DWORD) pperf + pperf-> headerlength ); <br/> pcounterdef = (pperf_counter_definition) (DWORD) pobj + pobj-> headerlength); <br/> pclistctr Linstances-> insertcolumn (0, (lpctstr) (mperfcountersindex [dwobjindex]), lvcfmt_left, 120); <br/> for (DWORD I = 0; I <(DWORD) pobj-> numcounters; I ++) <br/> {<br/> moffsets [pcounterdef-> counternametitleindex] = pcounterdef-> counteroffset; <br/> mindexs [pcounterdef-> counternametitleindex] = I + 1; <br/> pclistboxcounters-> insertstring (I, (lpctstr) (mperfcountersindex [pcounterdef-> counternametitleindex]); <Br/> pclistctrlinstances-> insertcolumn (I + 1, (lpctstr) (mperfcountersindex [pcounterdef-> counternametitleindex]), lvcfmt_left, 120); <br/> pcounterdef ++; <br/>}</P> <p> // get instances <br/> If (pobj-> numinstances = 0 | perf_no_instances = pobj-> numinstances) <br/>{< br/> // no instances <br/> pcounter = (pperf_counter_block) (DWORD) pobj + pobj-> definitionlength ); <br/> pclistctrlinstances-> insertit EM (0, "NONE"); <br/> for (cit p = moffsets. Begin (); P! = Moffsets. end (); ++ p) <br/>{< br/> DWORD counterval = * (lpdword) (DWORD) pcounter + P-> second )); <br/> char info [256] = {0}; <br/> wsprintf (Info, "% u", counterval ); <br/> pclistctrlinstances-> setitemtext (0, mindexs [p-> first], Info ); <br/>}< br/> else <br/>{< br/> // muIti-instances case <br/> tchar szinstancename [max_path]; <br/> pinst = (pperf_instance_definition) (DWORD) pobj + pobj-> definitionl Ength); <br/> for (I = 0; I <(DWORD) pobj-> numinstances; I ++) <br/>{< br/> P = (lpstr) (DWORD) pinst + pinst-> nameoffset); <br/> RT = widechartomultibyte (cp_acp, 0, (lpcwstr) P,-1, szinstancename, sizeof (szinstancename), null, null); <br/> pclistctrlinstances-> insertitem (I, szinstancename ); </P> <p> for (cit p = moffsets. begin (); P! = Moffsets. end (); ++ p) <br/>{< br/> pcounter = (pperf_counter_block) (DWORD) pinst + pinst-> bytelength ); <br/> DWORD counterval = * (lpdword) (DWORD) pcounter + P-> second )); </P> <p> char info [256] = {0}; <br/> wsprintf (Info, "% u", counterval ); <br/> pclistctrlinstances-> setitemtext (I, mindexs [p-> first], Info ); <br/>}< br/> // point to the next process <br/> pinst = (pperf_instance_definition) (DWORD) pcounter + pcounter-> bytelength ); <br/>}< br/>}// end if (bpass) </P> <p> If (buffer) <br/>{< br/> free (buffer); <br/> buffer = NULL; <br/>}< br/> return bpass; <br/>}
V. References
[1] in-depth analysis of Windows operating system (version 4), Mark E. russinovich & David A. Solomon.
[2] using performance counters, msdn. http://msdn.microsoft.com/en-us/library/aa373209 (vs.85). aspx.
[3] process enumeration, Lu Qiming. http://jasonye.bokee.com/432054.html.
[4] how to program to obtain Windows NT Performance Data, Zhou Jingsheng. http://www.comprg.com.cn/detail.asp? Hw_id = 2643.
(Aiguille Liu/Liu aigui/Aigui.liu@gmail.com)