SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION

An array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION structures, one per processor, is produced in the output buffer by a successful call to the following functions:

when given the information class SystemProcessorPerformanceInformation (0x08).

Documentation Status

The SYSTEM_PROCESSOR_PERFRMANCE_INFORMATION structure is defined in WINTERNL.H from the Software Development Kit (SDK). The definition there provides only some of the members: IdleTime, KernelTime and UserTime.

Microsoft does publish the practical equivalent of a C-language definition as type information in public symbol files, though not for the kernel, where the structure is prepared, nor even for low-level user-mode DLLs that interpret the structure, but for various higher-level user-mode DLLs such as URLMON.DLL and only then starting with version 6.2.

Two earlier disclosures of type information are known, though not in symbol files but in statically linked libraries: GDISRVL.LIB from the Device Driver Kit (DDK) for Windows NT 3.51; and SHELL32.LIB from the DDK for Windows NT 4.0.

Layout

The SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION is 0x30 bytes in both 32-bit and 64-bit Windows.

Offset Definition
0x00
LARGE_INTEGER IdleTime;
0x08
LARGE_INTEGER KernelTime;
0x10
LARGE_INTEGER UserTime;
0x18
LARGE_INTEGER DpcTime;
0x20
LARGE_INTEGER InterruptTime;
0x28
ULONG InterruptCount;

The counts for each processor are taken more or less directly from the similarly named members of the processor’s KPRCB. The IdleTime is the conceptual exception in that it is the accumulated KernelTime of the processor’s IdleThread. Indirectness of the others is more practical. Only version 3.10 accumulates 64-bit times in the usual 100ns units. Later versions multiply their 32-bit counts of an abstracted timer tick by whatever is currently the maximum time increment, i.e., the number of 100ns per tick. This increment can be queried from kernel mode through the exported (and documented) KeQueryTimeIncrement function, but up to and including version 6.2 it can also be set through the exported (but undocumented) KeSetTimeIncrement function. The latter was surely intended to have the HAL as its one and only caller. Still, the integrity of the times in this structure looks to have depended strongly on the time increment being set only during the kernel’s initialisation.