Collect Function

The system calls the Collect function for each application whenever a performance monitoring application calls the RegQueryValueEx function to collect performance data. The Collect function returns the performance data for the application.

The following code example shows the syntax for the Collect function.

DWORD WINAPI CollectPerformanceData(
LPWSTR lpwszValue, 
LPVOID *lppData, 
LPDWORD lpcbBytes, 
LPDWORD lpcObjectTypes 
);

CollectPerformanceData is a placeholder for a function name defined by the application.

lpwszValue is a pointer to a string specified by the performance monitoring application in a call to the RegQueryValueEx function.

lppData is a pointer to a pointer to the location where the data is to be placed. On successful exit, set lppData to the next byte in the buffer available for data. The data returned must be a multiple of a DWORD in length. It must conform to the PERF_OBJECT_TYPE structure. If the Collect function fails, do not change the value of lppData.

lpcbBytes is a pointer to a 32-bit value that specifies the size, in bytes, of the lppData buffer. On successful exit, set lpcbBytes to the size, in bytes, of the data written to the lppData buffer. This value must be a multiple of four. If the Collect function fails, set lpcbBytes to zero.

lpcObjectTypes is the number of object type definitions being returned. On successful exit, set lpcObjectTypes to the number of object type definitions being returned. If the Collect function fails, set lpcObjectTypes to zero.

If the requested data specified by lpwszValue does not correspond to any of the object indexes supported by your program, leave lppData unchanged, and set lpcbBytes and lpcObjectTypes both to zero. This action indicates that no data is returned. If your data collection is time-consuming, you should respond only to specific requests and costly requests. You should also lower the priority of the thread collecting the data, so that it does not adversely affect system performance.

The following table shows the values that the Collect function must return.

Return value Description
ERROR_MORE_DATA Indicates that the size of the lppData buffer as specified by lpcbBytes is not large enough to store the data to be returned. In this case, leave lppData unchanged, and set lpcbBytes and lpcObjectTypes to zero. No attempt is made to indicate the required buffer size, because this may change before the next call.
ERROR_SUCCESS Return this value in all other cases, even if no data is returned or an error occurs. To report errors other than insufficient buffer size, use the system event log, but do not flood the event log with errors on every data collection operation.

To provide more information to the user, the Collect function should write any error that prevents the function from completing successfully in the system event log.

Multiple threads may call the Collect function concurrently, so you should be careful how you initialize and use temporary data. Static variables should be used only if you intend to share the data across threads.

You can perform the following tasks with the Collect function:

  • Validate the shared memory pointer and check that the Open function has successfully completed. If the Open function fails, it should have already logged an event, so the Collect function does not need to report this error.
  • Determine the type of the data request. If the request is for a specific object or list of objects, search for its index in the list of object and counter indexes. If you do not find a match, the Collect function should return no data.
  • Request ownership of the mutex for the shared memory object. Wait to get access to the data in the shared memory block.
  • Estimate the size of the data to make sure there is enough room for the data in the buffer. If the estimated size of the data is larger than the available size, return a status of ERROR_MORE_DATA. The system passes this error to the thread that issued the call to RegQueryValueEx to request the data.
  • Copy the performance data from the shared memory to the performance data structure to be returned.

When all data has been transferred from the shared memory file to the performance data buffer, release the shared memory mutex and update the pointers and counter fields. Updating the pointers and counter fields is very important to prevent an access violation from the application, monitor, or system due to misleading buffer length information.

After the Collect function returns successfully, the system performs the following tests in an attempt to catch logic errors. The first test to fail generates an event log message and, in most cases, the data is discarded to prevent any further problems caused by invalid pointers. These tests are typically enabled. The following code example shows how to disable the tests by changing a registry value.

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Perflib
ExtCounterTestLevel = Test_Level

The Test_Level is a REG_DWORD that specifies the test level. Test level 1 requests all tests. Test level 2 requests basic tests. Test level 3 requests no tests. The default is test level 1.

The data buffer performs the following basic tests:

  • Checks whether the BytesLeft return value is consistent with the returned pointer. The returned value of the BytesLeft argument to the Collect function is compared to the returned buffer pointer. If all is consistent, the BytesLeft value added to the original buffer pointer passed in to the Collect function should be the same as the buffer pointer returned by the function. If they are not the same, a warning message is logged and the BytesLeft parameter is replaced by the value computed by finding the difference between the buffer pointer after the function call and the buffer pointer before the function call. This is somewhat risky because it assumes the BytesLeft value is incorrect, when it is possible that the buffer pointer is incorrect.
  • Checks whether the returned buffer pointer exceeds the allocated buffer extent. The actual buffer passed to the Collect function is allocated specifically for that function call by the performance library and contains a 1-kilobyte (KB) guard page above and below the size indicated by the remaining size of the buffer. A separate buffer is used to allow testing of the returned data for the extensible counter DLL without corrupting the caller's buffer. If the returned buffer pointer—the pointer to the next byte after this object's data—exceeds the size of this buffer—not including guard pages—then the buffer is assumed to be invalid and discarded because it is too large to be copied into the caller's buffer. This test consists of two parts. If the buffer pointer exceeds the end of the buffer, but not the end of the guard page, then a buffer overrun error is logged. If the buffer pointer is past the end of the guard page, then a heap error is logged because the heap that the buffer was allocated from could have been corrupted, causing other memory errors.
  • Checks whether the guard pages are corrupt. The 1-KB Guard Pages above and below the block of memory passed to the collect procedure are initialized with a data pattern before the Collect function is called. This data pattern is checked after the collect procedure returns. If any discrepancy is detected, a buffer overrun or other memory error is assumed and the buffer is discarded.

The data buffer performs the following tests only if you use test level 1:

  • Tests the field consistency of the object TotalByteLength. This test examines the objects returned by the extensible counter to see if the sum of the length of the objects returned is the same as the value of the size of the returned buffer. Because the Collect function generally returns one or more object structures—including the instance definitions, counter definitions, and data—the sum of the length of each object should be the same as the number of bytes returned. A failure here may indicate the object is not computing the value of the TotalByteLength field correctly. This can cause an application that is using the data to fail.
  • Tests the field consistency of the instance ByteLength. This test is similar to the test for TotalByteLength. This test examines the list of instances of each object that returns multiple instances and verifies whether the next object or the end of buffer follows the last instance. If an inconsistency is detected, the buffer is discarded to prevent the application from crashing because of a lost pointer.

 Last updated on Friday, October 08, 2004

© 1992-2003 Microsoft Corporation. All rights reserved.