HOWTO: Access the Performance Registry Under Windows 95
ID: Q174631
|
The information in this article applies to:
-
Microsoft Win32 Application Programming Interface (API), included with:
SUMMARY
Windows 95 comes with an application called System Monitor (Sysmon.exe)
that provides users with a method to monitor system resources or
performance data. Note that Sysmon.exe is not installed by default under
Windows 95, but users can install it via the Control Panel applet named
Add/Remove Programs, clicking the Windows Setup tab, and then selecting the
System Monitor check box. System resources exist as a collection of objects
where an object is a grouping of resources. Each resource within an object
can be monitored and is known as a counter. Each object and counter form a
unique pair from which performance data is collected. All the information
required to perform System Monitor functionality is located in the Windows
95 registry.
The process for writing a Performance Monitor involves the following steps:
- Determine which performance objects are currently active in the system.
- Determine the characteristics of each performance object.
- Determine which performance counters are currently active for each
performance object.
- Determine the characteristics of each performance counter.
- Enable the collection of performance data.
- Retrieve performance data for an object\counter pair.
- Disable the collection of performance data.
In addition to monitoring a local Windows 95 machine, the above procedure
of querying the registry to obtain system-monitoring data, can also be
performed on a remote machine running Windows 95.
MORE INFORMATION
Step 1: Determine What Performance
Objects Are Currently Active in the System
To determine which objects are active in the system, start by enumerating
the following registry key:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\PerfStats\Enum
Each registry key that is listed under this location is called an Object
(for example, VFAT, KERNEL, etc.). The availability of objects is dynamic.
Therefore, this location must be checked first before proceeding to collect
performance data. The following sample code illustrates this concept:
Sample Code
#include <windows.h>
#include <stdio.h>
#define DIFFFLAGLEN 6
#define PERFENUMKEY
"System\\CurrentControlSet\\Control\\PerfStats\\Enum"
char szCounter[MAX_PATH];
char szObject[MAX_PATH];
char szName[MAX_PATH];
LPSTR lpszDescBuff = NULL;
char szDiffFlag[DIFFFLAGLEN]; // can contain either "TRUE" or "FALSE"
void main(void)
{
DWORD rc;
DWORD dwIndex1, dwIndex2;
DWORD dwType;
DWORD dwBufSize;
HKEY hKey;
HKEY hObject;
HKEY hCounter;
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
PERFENUMKEY, 0, KEY_READ, &hKey);
if (rc == ERROR_SUCCESS)
{
dwBufSize = MAX_PATH;
dwIndex1 = 0;
// enumerate objects
while ( RegEnumKeyEx(hKey, dwIndex1++, szObject,
&dwBufSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS )
{
if ( (rc=RegOpenKeyEx(hKey, szObject, 0, KEY_READ, &hObject))
== ERROR_SUCCESS)
{
// process information on the open key using hObject
}
RegCloseKey(hObject);
dwBufSize = MAX_PATH;
}
RegCloseKey(hKey);
}
else
printf("Error %d opening %s\n", rc, PERFENUMKEY);
} // end main
Step 2: Determine the Characteristics of Each Performance Object
Each performance object key is characterized by one registry value. This
registry value is of type REG_SZ and is called "Name." The "Name" registry
key identifies the commonly used name of the object (for example, VFAT is
know as "File System"). It is this "Name" that would be shown to an end
user that is using the system monitor application. Use RegQueryValueEx() to
obtain this registry value as shown in the following sample code:
Sample Code
if ((rc=RegQueryValueEx(hObject, "Name", NULL, &dwType,
szObject, &dwBufSize)) == ERROR_SUCCESS)
{
}
Step 3: Determine what Performance Counters Are Active for Each perf Object
Associated with each performance object key identified above with hObject,
there is one or more performance counters. Each performance counter exists
as a subkey of a performance object key. The following sample code
enumerates all these performance counters for a given performance object
(hObject):
Sample Code
// enumerate counters
dwIndex2 = 0;
dwBufSize = MAX_PATH;
while(RegEnumKeyEx(hObject, dwIndex2++, szCounter, &dwBufSize,
NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
if ( (rc=RegOpenKeyEx(hObject, szCounter, 0, KEY_READ, &hCounter))
== ERROR_SUCCESS)
{
// do processing on open counter key using hCounter
}
else
printf("Error %d opening counter %s\n", rc, szCounter);
RegCloseKey(hCounter);
dwBufSize = MAX_PATH;
}
Step 4: Determine the Characteristics of Each Performance Counter
Similar to a performance object, each performance counter is characterized
by three registry values. Each of these registry values is identified by
"Name" and is of type REG_SZ. This "Name" value identifies the commonly
used name of the counter (for example, CPUUsage is know as "Processor Usage
(%)") and would be displayed to a user. A second REG_SZ value called
"Description" describes the counter in more detail. You can use this
description to provide more detail to the user. And finally, there is a
third REG_SZ value called "Differentiate" that is either "TRUE" or "FALSE."
If "Differentiate" is set to "FALSE" then the data retrieved is used in its
raw form. If "Differentiate" is "TRUE" the data retrieved for this counter
must be differentiated over time as follows:
Counter_Value2 - Counter_Value1
-----------------------------------------
Time_Taken2 - Time_Taken1
The following code illustrates this procedure:
Sample Code
// First, get the Name of the performance counter
dwBufSize = MAX_PATH;
rc = RegQueryValueEx(hObject, "Name", NULL, &dwType, szName,
&dwBufSize);
// Second, get the Description
dwBufSize = 0;
RegQueryValueEx(hCounter, "Description", NULL, &dwType, NULL,
&dwBufSize);
lpszDescBuff = LocalAlloc(LPTR, dwBufSize + 1);
rc = RegQueryValueEx(hCounter, "Description", NULL, &dwType,
lpszDescBuff, &dwBufSize);
if (ERROR_SUCCESS == rc)
{
printf("%s: %s\n", szCounter, lpszDescBuff);
LocalFree(lpszDescBuff);
}
// get the Differentiate value
dwBufSize = DIFFFLAGLEN;
rc = RegQueryValueEx(hCounter, "Differentiate", NULL, &dwType,
szDiffFlag, &dwBufSize);
if (ERROR_SUCCESS == rc)
{
printf("Differentiating Counter: %s\n\n", szDiffFlag);
}
Step 5: Enable the Collection of Performance Data
Together, the performance object key name and counter subkey name pair is
used to initialize performance data collection. To request the beginning of
a performance data collection for any performance object\counter pair, use
the object\counter pair to query the registry value located at
HKEY_DYN_DATA\PerfStats\StartStat using RegQueryValueEx. For example, to
start performance data collection on KERNEL\CPUUsage, a registry query on
KERNEL\CPUUsage at location HKEY_DYN_DATA\PerfStats\StartStat is performed.
If no requests to start data collection are issued, the performance data
retrieved for KERNEL\CPUUsage is always 100%. Once a request to start
performance data collection is issued, the data retrieved reflects the
actual CPU utilization.
Sample Code
BOOL EnableDataCollection(char *szObjName, char *szCounterName)
{
HKEY hOpen;
DWORD cbData;
DWORD dwType;
LPBYTE pByte;
DWORD rc;
char *szCounterData;
BOOL bSuccess = TRUE;
if ( (rc = RegOpenKeyEx(HKEY_DYN_DATA,"PerfStats\\StartStat", 0,
KEY_READ, &hOpen)) == ERROR_SUCCESS)
{
// concatenate the object and couter key names
szCounterData = LocalAlloc(LPTR,
lstrlen(szObjName) + lstrlen(szCounterName) + 2);
wsprintf(szCounterData, "%s\\%s", szObjName, szCounterName);
// query to get data size
if ( (rc = RegQueryValueEx(hOpen,szCounterData,NULL,&dwType,
NULL, &cbData )) == ERROR_SUCCESS )
{
pByte = LocalAlloc(LPTR, cbData);
// query the performance start key to initialize performance data
// query the start key to initialize performance data
rc = RegQueryValueEx(hOpen,szCounterData,NULL,&dwType, pByte,
&cbData );
// at this point we don't do anything with the data
// free up resources
LocalFree(pByte);
}
else
bSuccess = FALSE;
RegCloseKey(hOpen);
LocalFree(szCounterData);
}
else
bSuccess = FALSE;
return bSuccess;
}
Step 6: Retrieve Performance Data for an object\counter Pair
Once performance data collection is initialized, each performance object
key and counter subkey pair is again used to retrieve performance data from
the registry key HKEY_DYN_DATA\PerfStats\StartData using RegQueryValueEx
(for example, KERNEL\CPUUsage, KERNEL\Threads, etc.). The performance data
retrieved using RegQueryValueEx is always of type DWORD (for example, 4
bytes).
Sample Code
BOOL CollectPerfData(char *szObjName, char *szCounterName,
DWORD *pdwData)
{
HKEY hOpen;
DWORD dwType;
DWORD cbData;
char *szCounterData;
DWORD rc;
BOOL bSuccess = TRUE;
// concatenate the object and counter keys
szCounterData = LocalAlloc(LPTR,
lstrlen(szObjName) + lstrlen(szCounterName) + 2);
wsprintf(szCounterData, "%s\\%s", szObjName, szCounterName);
// open performance data key
if ( (rc = RegOpenKeyEx(HKEY_DYN_DATA,"PerfStats\\StatData", 0,
KEY_READ, &hOpen)) == ERROR_SUCCESS)
{
cbData = sizeof(DWORD);
// retrieve performance data which is of size of DWORD
rc=RegQueryValueEx(hOpen,szCounterData,0,&dwType,
(LPBYTE)pdwData,&cbData );
// let the caller know if it worked or not
bSuccess = rc == ERROR_SUCCESS;
RegCloseKey(hOpen);
}
else
bSuccess = FALSE;
// free the resources
LocalFree(szCounterData);
return bSuccess;
}
Step 7: Disable the Collection of Performance Data
After performance data retrieval is completed, performance data collection
must be de-initialized or turned off to allow system resources to be
released. To request the end of performance data collection for any
object\counter pair, the object\counter pair is used to query the registry
value located at HKEY_DYN_DATA\PerfStats\StopStat using RegQueryValueEx().
For example, to request performance data collection end for
KERNEL\CPUUsage, RegQueryValueEx() is used to query the registry value
KERNEL\CPUUsage at location HKEY_DYN_DATA\PerfStats\StopStat.
Sample Code
BOOL DisableDataCollection(char *szObjName, char *szCounterName)
{
HKEY hOpen;
LPBYTE pByte;
DWORD cbData;
DWORD dwType;
DWORD rc;
char *szCounterData;
BOOL bSuccess = TRUE;
if ( (rc = RegOpenKeyEx(HKEY_DYN_DATA,"PerfStats\\StopStat", 0,
KEY_READ, &hOpen)) == ERROR_SUCCESS)
{
// concatenate the object and couter key names
szCounterData = LocalAlloc(LPTR,
lstrlen(szObjName) + lstrlen(szCounterName) + 2);
wsprintf(szCounterData, "%s\\%s", szObjName, szCounterName);
// query to get data size
if ( (rc = RegQueryValueEx(hOpen,szCounterData,NULL,&dwType,
NULL, &cbData )) == ERROR_SUCCESS )
{
pByte = LocalAlloc(LPTR, cbData);
// query the performance start key to initialize performance data
// query the start key to initialize performance data
rc = RegQueryValueEx(hOpen,szCounterData,NULL,&dwType, pByte,
&cbData );
// at this point we don't do anything with the data
// free up resources
LocalFree(pByte);
}
else
bSuccess = FALSE;
RegCloseKey(hopen);
LocalFree(szCounterData);
}
else
bSuccess = FALSE;
return bSuccess;
}
Step 8: Remote System Monitoring
Since performance data is part of the registry and since
RegConnectRegistry() enables one Windows 95 machine to read and write to a
remote registry, system monitoring can be performed on a remote Windows 95
machine. Follow these steps to enable this functionality:
- Install the "Remote Registry Service" on all Windows 95 machines.
- Use RegConnectRegistry to retrieve handles to HKEY_LOCAL_MACHINE and
HKEY_DYN_DATA from the remote Windows 95 target, as shown below:
RegConnectRegistry(szComputerName, // name of remote computer
HKEY_LOCAL_MACHINE, // predefined registry handle
&hkRemoteMachine); // buffer for remote registry handle
- Use the handle returned by RegConnectRegistry as replacements for
HKEY_LOCAL_MACHINE and HKEY_DYN_DATA, as shown below:
RegConnectRegistry(szComputerName, // name of remote computer
HKEY_DYN_DATA, // predefined registry handle
&hkDynaData); // buffer for remote registry handle
- Perform the steps as described above.
REFERENCES
Since performance monitoring is such a valuable tool, Windows 95 has
provided a method by which additional performance objects can be added to
the registry. In Windows 95, performance data is provided by a collection
of VxDs. It is the job of these VxDs to provide the performance data upon
request as the registry is queried. To get more information on how to
providing performance objects, consult the Device Driver Kit (DDK)
documentation.
Additional query words:
Keywords : kbKernBase kbPerfMon kbRegistry kbGrpKernBase
Version : winnt:
Platform : winnt
Issue type : kbhowto