Microsoft KB Archive/262335

{|
 * width="100%"|

HOWTO: Align Performance Data of a Performance Extension DLL on an 8-Byte Boundary

 * }

Q262335

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * the operating system: Microsoft Windows 2000

-

SUMMARY
When the performance data buffer returned by a performance extension DLL is not aligned on an 8-byte boundary, the performance library (PERFLIB) part of ADVAPI32.dll will report a warning 1016 to the Application Log in Event Viewer. This article explains how the developer of a performance extension DLL can align the performance data on an 8-byte boundary.

MORE INFORMATION
On Windows 2000, the length of all data buffers returned by a performance extension DLL should be a multiple of 8 bytes. PERFLIB calls the CollectPerformanceData function in the performance extension DLL. On input, *lppData points to the location where the performance data is to be placed. On successful exit, *lppData should point to one byte past the last byte of performance data written. Similarly, *lpcbBytes on input specifies the size of the *lppData buffer. On successful exit, the performance extension DLL must set *lpcbBytes to the size in bytes of the performance data written to *lppData buffer, and the *lpcbBytes value should be a multiple of 8 bytes.

When PERFLIB encounters a buffer whose length (*lpcbBytes) is not a multiple of 8 bytes, it reports a warning with event ID 1016 to the Application Log in Event Viewer. The event description includes the name of the service associated with the performance counter and the path to the performance extension DLL that returned the invalid buffer. One misaligned buffer can cause multiple errors. For example, the *lppData on input for the next collect call from PerfLib will not be aligned on an 8-byte boundary. The first performance extension DLL should be fixed to return correctly sized buffers.

If the performance data structures of a performance extension DLL are designed to be a multiple of 8 bytes, then this 1016 warning will be eliminated. If the byte length of any data structure is not a multiple of 8 bytes, then you can add reserved members to increase the size to the next multiple of 8 bytes. You can also add bytes to the end of the buffer to make it a multiple of 8 bytes.

The structures in Winperf.h such as PERF_OBJECT_TYPE and PERF_COUNTER_DEFINITION are defined to be a multiple of 8-bytes long. If you make sure that the ByteLength member in the PERF_COUNTER_BLOCK as well as the PERF_INSTANCE_DEFINITION structure are designed to be a multiple of 8 bytes, then the length of all data buffers returned by a performance extension DLL will automatically be a multiple of 8 bytes.

The fixed length of the PERF_INSTANCE_DEFINITION structure is a multiple of 8 bytes. If the instance name immediately follows the PERF_INSTANCE_DEFINITION structure, then the ByteLength in PERF_INSTANCE_DEFINITION specifies the total bytes of the structure including the subsequent instance name. The instance name should be padded with extra NULL characters so that it is a multiple of 8 bytes. In this case the ByteLength member in PERF_INSTANCE_DEFINITION will automatically be a multiple of 8 bytes.

If the performance object contains instances, then the block of performance counter data immediately follows the PERF_INSTANCE_DEFINITION block. If there are no instances, then the performance counter data block follows the PERF_COUNTER_DEFINITION. The ByteLength in PERF_COUNTER_BLOCK specifies the bytes that follow the ByteLength member. This member is 4 bytes in length, so if this member is aligned on an 8-byte boundary, then the data that immediately follows it will not be aligned on an 8-byte boundary, so padding bytes will be needed following the ByteLength member and before the first counter value.

For example, if the data for each counter is a multiple of 8 bytes, then the entire block of counters plus the PERF_COUNTER_BLOCK->ByteLength member will not be a multiple of 8 bytes. It will be off by 4 bytes. In this case, 4 padding bytes can be added following the ByteLength member and before the first counter value starts, so that the total length of all bytes for the counter data will be a multiple of 8 bytes. Padding bytes can also follow the last counter data. If this is done for all performance objects being collected, then the overall buffer returned to PERFLIB is a multiple of 8 bytes, and each performance object within the buffer will also be aligned on an 8-byte boundary.

A hypothetical layout of the different structures and their alignment is shown below:

Contents of *lppData: Object type 1  (object 1 does not contain any instances) PERF_OBJECT_TYPE PERF_COUNTER_DEFINITION PERF_COUNTER_DEFINITION PERF_COUNTER_DEFINITION PERF_COUNTER_DEFINITION PERF_COUNTER_BLOCK (misalignment begins following this structure) Padding bytes (alignment corrected here) Counter Data Padding bytes (alignment corrected here, if required) Object type 2 Object type 3 (object 3 contains n instances) PERF_OBJECT_TYPE PERF_COUNTER_DEFINITION PERF_COUNTER_DEFINITION PERF_COUNTER_DEFINITION PERF_COUNTER_DEFINITION Instance definition 1 PERF_INSTANCE_DEFINITION Instance Name  (misalignment begins following the name) Padding bytes (alignment corrected here) PERF_COUNTER_BLOCK (misalignment begins following this structure) Padding bytes (alignment corrected here) Counter Data Padding bytes (alignment corrected here, if required) Instance definition 2 Instance definition n Object type n If each structure within the overall buffer is aligned to 8-byte boundaries, then the overall buffer itself must then be aligned on an 8-byte boundary.

There are members that must be updated to reflect the padding bytes added. These members are:


 * PERF_OBJECT_TYPE->TotalByteLength

This member must be set to the total length of all structures for the performance object, any instance data, and all counter data, including all padding bytes used in each component. This value includes the size of the PERF_OBJECT_TYPE structure, the PERF_COUNTER_DEFINITION structures, and the PERF_INSTANCE_DEFINITION and PERF_COUNTER_BLOCK structures for each instance.
 * PERF_INSTANCE_DEFINITION->NameLength

The PERF_INSTANCE_DEFINITION structure is used only when the performance object has instances. The NameLength should be set to the length of the instance name plus all padding bytes. The fixed portion of the PERF_INSTANCE_DEFINITION structure is aligned on an 8-byte boundary. If the instance name immediately follows this structure, then the member ByteLength must be set to the length of the fixed portion of the structure plus the NameLength (the NameLength member includes the padding bytes).
 * PERF_COUNTER_BLOCK->ByteLength

This member must be set to the size of the PERF_COUNTER_BLOCK structure, including the size of the data for all the counters that follow the PERF_COUNTER_BLOCK structure, plus any padding bytes. If there are no instances, then the performance object will have a single PERF_COUNTER_BLOCK of counter data. If there are instances, then there will be multiple PERF_COUNTER_BLOCKs of counter data, one for each instance.

If these guidelines are followed, then after all performance objects have been collected, the overall buffer returned to PERFLIB will be aligned on an 8-byte boundary.

The parameter *lpcbBytes to the CollectPerformanceData function must be set to the overall buffer size, including all padding bytes. This should be the summation of the PERF_OBJECT_TYPE->TotalByteLength member for all the performance objects.