INFO: Retrieving Counter Data from the Registry
ID: Q107728
|
The information in this article applies to:
-
Microsoft Win32 Application Programming Interface (API), used with:
-
Microsoft Windows NT versions 3.1, 3.5, 3.51, 4.0
SUMMARY
The performance data begins with a structure of type PERF_DATA_BLOCK and is
followed by PERF_DATA_BLOCK.NumObjectTypes data blocks. Each data block
begins with a structure of type PERF_OBJECT_TYPE, followed by
PERF_OBJECT_TYPE.NumCounters structures of type PERF_COUNTER_DEFINITION.
Next, there are PERF_OBJECT_TYPE.NumInstances structures of type
PERF_INSTANCE DEFINITION, each directly followed by an instance name, a
structure of type PERF_COUNTER_BLOCK and PERF_OBJECT_TYPE.NumCounters
counters. All of these data types are described in WINPERF.H.
On Windows NT 4.0 and Win2000, a simpler way to access performance data is to use the PDH.DLL (Performance Data Helper Library). For more information see the Platform SDK document in Base Service, Performance Monitoring, Performance Data, The PDH Interface.
MORE INFORMATION
The following steps are used to retrieve all of the counter information
from the registry:
- Allocate a buffer to obtain the performance data. For single objects,
you may need at little as 1.5K. For global objects, you may need as
much as 50K. Call RegQueryValueEx() to obtain the data. If the call
returns ERROR_MORE_DATA, then the buffer size was not big enough.
Increase the size of the buffer and try again. Repeat until the call
is successful.
- Get the first object type in PerfObj.
- Get the first instance.
- Get the first counter and its data. At this point, if the object has no
instances, the next thing will be a pointer to a single
PERF_COUNTER_BLOCK; otherwise, the next thing will be a pointer to the
first PERF_INSTANCE_DEFINITION. Check PerfObj->NumInstances to find out
how many instances there are.
- Get the next counter and its data. Repeat for all PerfObj->NumCounters
counters.
- After all counters are retrieved for the instance, get the next
instance and all its counters. Repeat for all PerfObj->NumInstances
instances.
- After all instances of the object type are retrieved, move to the next
object type and repeat steps 3 - 7.
Sample Code
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#define TOTALBYTES 8192
#define BYTEINCREMENT 1024
void main()
{
PPERF_DATA_BLOCK PerfData = NULL;
PPERF_OBJECT_TYPE PerfObj;
PPERF_INSTANCE_DEFINITION PerfInst;
PPERF_COUNTER_DEFINITION PerfCntr, CurCntr;
PPERF_COUNTER_BLOCK PtrToCntr;
DWORD BufferSize = TOTALBYTES;
DWORD i, j, k;
// Allocate the buffer.
PerfData = (PPERF_DATA_BLOCK) malloc( BufferSize );
while( RegQueryValueEx( HKEY_PERFORMANCE_DATA,
"Global",
NULL,
NULL,
(LPBYTE) PerfData,
&BufferSize ) == ERROR_MORE_DATA )
{
// Get a buffer that is big enough.
BufferSize += BYTEINCREMENT;
PerfData = (PPERF_DATA_BLOCK) realloc( PerfData, BufferSize );
}
// Get the first object type.
PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfData +
PerfData->HeaderLength);
// Process all objects.
for( i=0; i < PerfData->NumObjectTypes; i++ )
{
printf( "\nObject: %ld\n", PerfObj->ObjectNameTitleIndex );
// Get the counter block.
PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +
PerfObj->HeaderLength);
if( PerfObj->NumInstances > 0 )
{
// Get the first instance.
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj +
PerfObj->DefinitionLength);
// Retrieve all instances.
for( k=0; k < PerfObj->NumInstances; k++ )
{
printf( "\n\tInstance: %S\n", (char *)((PBYTE)PerfInst +
PerfInst->NameOffset) );
CurCntr = PerfCntr;
// Get the first counter.
PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst +
PerfInst->ByteLength);
// Retrieve all counters.
for( j=0; j < PerfObj->NumCounters; j++ )
{
printf("\t\tCounter: %ld\n",CurCntr->CounterNameTitleIndex);
// Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);
// Get next counter.
CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr +
CurCntr->ByteLength);
}
// Get the next instance.
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr +
PtrToCntr->ByteLength);
}
}
else
{
// Get the first counter.
PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +
PerfObj->DefinitionLength );
// Retrieve all counters.
for( j=0; j < PerfObj->NumCounters; j++ )
{
printf( "\tCounter: %ld\n", PerfCntr->CounterNameTitleIndex );
// Data is (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr +
PerfCntr->ByteLength);
}
}
// Get the next object type.
PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
PerfObj->TotalByteLength);
}
}
Note that the instance names are retrieved in a fashion that is similar to
retrieving the data.
The steps above showed how to obtain all of the counters. You can retrieve
only the counters that pertain to a particular object by using the titles
database. The information is stored in the registry in the format index,
name, index, name, and so forth.
To retrieve the titles database and store it in TitlesDatabase:
- Open the key:
RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009",
0,
KEY_READ,
&Hkey);
Note that 009 is a language ID, so this value will be different on a
non-English version of the operating system.
- Query the information from the key:
RegQueryInfoKey(
Hkey,
(LPTSTR) Class,
&ClassSize,
NULL,
&Subkey,
MaxSubKey,
&MaxClass,
&Values,
&MaxName,
&MaxData,
&SecDesc,
&LastWriteTime );
- Allocate a buffer to store the information:
TitlesDataBase = (PSTR) malloc( (MaxData+1) * sizeof(TCHAR) )
- Retrieve the data:
RegQueryValueEx( Hkey,
(LPTSTR) "Counters",
NULL,
NULL,
(LPBYTE) TitlesDataBase,
&MaxData );
Once you have the database, it is possible to write code that will go
through all objects, searching by index (field ObjectNameTitleIndex) or by
type (field ObjectNameTitle - which is initially NULL).
Or, you could obtain only the performance data for specified objects by
changing the call to ReqQueryValueEx() in step 1 of the SUMMARY section
above to:
RegQueryValueEx( HKEY_PERFORMANCE_DATA,
Indices,
NULL,
NULL,
PerfData,
&BufferSize );
Note that the only difference here is that instead of specifying "Global"
as the second parameter, you specify a string that represents the decimal
value(s) for the object(s) of interest that are obtained from the titles
database.
REFERENCES
The PVIEWER and PERFMON samples in the MSTOOLS\SAMPLES\SDKTOOLS\WINNT
directory contain complete sample code that deals with performance data.
For more information, please see the "Performance Overview" in the Win32
SDK documentation and the volume titled "Optimizing Windows NT" in the
Windows NT Resource Kit. The PERFMON sample is now removed from the Platform SDK.
For more information see the Platform SDK documentation in Base Services, Performance Monitoring, Performance Data, The Registry Interface.
Additional query words:
3.10 3.50 Perfmon
Keywords : kbKernBase kbWinOS2000 kbPerfMon kbDSupport kbGrpKernBase
Version : winnt:3.1,3.5,3.51,4.0
Platform : winnt
Issue type : kbinfo
|