Geoff Chappell, Software Analyst
This function starts the profiling that has been configured for a given profile object.
NTSTATUS NtStartProfile (HANDLE ProfileHandle);
The ProfileHandle argument is a handle to an executive profile object, such as created by NtCreateProfile or NtCreateProfileEx.
The function returns STATUS_SUCCESS if successful, else a negative error code.
The NtStartProfile function and its alias ZwStartProfile are exported by name from NTDLL in version 3.10 and higher. In kernel mode, where ZwStartProfile is a stub and NtStartProfile is the implementation, neither is exported.
Neither NtStartProfile nor its alias is documented. As ZwStartProfile, it is declared in the ZWAPI.H file in the Windows Driver Kit (WDK) for Windows 10.
Unusually for native API functions, no repackaging of NtStartProfile, documented or not, is known in any higher-level user-mode module that is distributed as standard with Windows.
The following implementation notes are from inspection of the kernel from the original release of Windows 10 only. They may some day get revised to account for earlier versions. Meanwhile, where anything is added about earlier versions, take it not as an attempt at comprehensiveness but as a bonus from my being unable to resist a trip down memory lane or at least a quick look into the history.
The function fails unless the given handle references an executive profile object (rather than any other type of object) and has whatever permission is represented by the access mask 0x00000001. Microsoft’s name for this one permission that is defined for profile objects is not known.
The profile object retains parameters that were supplied on some earlier call to NtCreateProfile or NtCreateProfileEx. Among these is the address of a buffer that is to receive the ULONG counters of times that execution is discovered in successive buckets that span a profiled region of address space. Because the counters will be incremented while handling a hardware interrupt this buffer—well, that part of it that will be needed for the counters—must be locked into physical memory and mapped into system address space at all times that profiling is started but not yet stopped. This mapped address for the buffer is also kept with the profile object. If it’s present, then profiling is deemed to have started already, and the function returns STATUS_PROFILING_NOT_STOPPED.
There is a system-wide limit to the number of profile objects that can at any one time be started but not yet stopped. If this limit is reached, the function returns STATUS_PROFILING_AT_LIMIT. Up to and including version 5.0, this limit seems intended to have been 8 but is ineffective since the started profiles are not counted. The limit was then dropped, but since its restoration for version 6.1 it is 8,192 times the number of processors (which seems implausibly large).
Given that the executive profile object is in order, the function links it to a kernel profile object. Microsoft’s name for this as a structure is not known, though there would be no surprise if it turned out to be KPROFILE. It is a kernel object in the sense of beginning with a type and size. The type, from the KOBJECTS enumeration, is specifically ProfileObject (0x17 in most versions). The structure itself is followed immediately by an MDL to describe the buffer that is to receive the execution counts. If the function cannot get memory for this profile object, it returns STATUS_INSUFFICIENT_RESOURCES.
The executions counts will be updated by the KeProfileInterruptWithSource function when it is called from the HAL once profiling is started. Because this will happen while handling hardware interrupts, paging I/O is not even close to being possible and the buffer must therefore be locked into physical memory. Failure at this is failure for the function. Moreover, the interruption can be of arbitrary threads, including for other processes and so the buffer must be mapped into system address space. If the function fails at this, it returns STATUS_INSUFFICIENT_RESOURCES.
From here, the function succeeds. Parameters are transferred to the kernel profile object. If a process was specified for the profiling, then the profile object is inserted into a list for that process, else into a global list. The function directs the HAL, via its exported HalStartProfileInterrupt function, to start a profile interrupt on each processor that was specified for the profiling. This continues until profiling is stopped by the NtStopProfile function or by deleting the executive profile object.