Microsoft KB Archive/174631

{|
 * width="100%"|

HOWTO: Access the Performance Registry Under Windows 95

 * }

Q174631

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), included with:
 * Microsoft Windows 95

-

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:


 * 1) Determine which performance objects are currently active in the system.
 * 2) Determine the characteristics of each performance object.
 * 3) Determine which performance counters are currently active for each performance object.
 * 4) Determine the characteristics of each performance counter.
 * 5) Enable the collection of performance data.
 * 6) Retrieve performance data for an object\counter pair.
 * 7) 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    #include 

#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 </li> Perform the steps as described above.</li></ol>