Geoff Chappell - Software Analyst
The HAL handles the processor-specific work of using hardware performance counters to support the profiling of execution. What the HAL can do about profiling the processors depends, unsurprisingly, on what types of processor are present. Perhaps less unsurprisingly, it is assessed from the boot processor only. The HAL in the original release of Windows 10 distinguishes three profile interfaces:
Names are surmised from symbol files for the HAL. The name Emon appears to come from Intel’s manuals, apparently standing for Event Monitoring.
For anything more sophisticated than the Default interface, the HAL must identify the boot processor as suitable. It doesn’t even try unless a rough inspection of processor features done earlier has shown that performance monitoring is at least a possibility.
Much of the broad picture simply uses CPU identification that has already been made by the kernel and left in the KPRCB. Presumably as a remnant of age-old code, the HAL still checks that the cpuid instruction is available (as recorded in the CpuID). For the 64-bit HAL, this is enough. The 32-bit HAL, however, recognises the support as possible for only two vendors (as identified by the CpuVendor). If the vendor is Intel, then it is enough that the family (from the CpuType) is either 6 or 15. If the vendor is AMD, then cpuid leaf 0x80000000 must indicate support for cpuid leaf 0x80000001, which must in turn set the 0x20000000 bit in edx. (Intel’s manual would have it that this bit means “Intel® 64 Architecture available if 1.”)
The first part to selecting the profile interface is to know the vendor string from cpuid leaf 0. If this is AuthenticAMD, then Amd64 profiling is tentatively indicated, save only for what a hypervisor may have to say. Processors whose vendor string is GenuineIntel are tentatively recognised as having Emon profiling if the highest cpuid leaf, as returned in eax for cpuid leaf 0, is at least 10 and the result of executing cpuid leaf 10 satisfies all the following:
Neither of these identifications, for the Amd64 or Emon profiling interface, means anything if a Microsoft-compatible hypervisor is present and execution of cpuid leaf 0x40000003 produces a clear PerformanceMonitorsAvailable bit (2) in edx. This is taken to mean that whatever the underlying features of the processor, they are masked by the hypervisor. Profiling is then defaulted just as if the processor had been unrecognised. (The test for Microsoft-compatibility is the same as the kernel has for its exported HviIsHypervisorMicrosoftCompatible function. For the hypervisor features that are the output of cpuid leaf 0x40000003, see the HV_HYPERVISOR_FEATURES structure.)
The three profile interfaces provide independently of one another for their own initialisation and subsequent use. However, many points to this are done in very much the same way so that much can usefully be said in general.
For the purpose of interaction with the kernel, and indeed all the way to user mode through such functions as NtCreateProfile and NtCreateProfileEx, whatever it is that a hardware performance counter might count is abstracted as a profile source, represented numerically by a KPROFILE_SOURCE enumeration. This is defined in NTDDK.H in the Device Driver Kit (DDK) from as far back as Windows NT 3.51, moving to WDM.H in later kits, but without ever changing. The point to reproducing such a well-known enumeration here is to show which profile sources are supported by which profile interfaces:
Value | Symbol | Profile Interface |
---|---|---|
0x00 | ProfileTime | Default Emon Amd64 |
0x01 | ProfileAlignmentFixup | |
0x02 | ProfileTotalIssues | Emon Amd64 |
0x03 | ProfilePipelineDry | |
0x04 | ProfileLoadInstructions | |
0x05 | ProfilePipelineFrozen | |
0x06 | ProfileBranchInstructions | Emon Amd64 |
0x07 | ProfileTotalNonissues | |
0x08 | ProfileDcacheMisses | Amd64 |
0x09 | ProfileIcacheMisses | Amd64 |
0x0A | ProfileCacheMisses | Emon |
0x0B | ProfileBranchMispredictions | Emon Amd64 |
0x0C | ProfileStoreInstructions | |
0x0D | ProfileFpInstructions | Amd64 |
0x0E | ProfileIntegerInstructions | |
0x0F | Profile2Issue | |
0x10 | Profile3Issue | |
0x11 | Profile4Issue | |
0x12 | ProfileSpecialInstructions | |
0x13 | ProfileTotalCycles | Emon |
0x14 | ProfileIcacheIssues | Amd64 |
0x15 | ProfileDcacheAccesses | Amd64 |
0x16 | ProfileMemoryBarrierCycles | |
0x17 | ProfileLoadLinkedIssues | |
0x18 | ProfileMaximum | |
higher | processor-specific profile sources | Emon Amd64 |