Geoff Chappell, Software Analyst
This function sets the profile interval for a given profile source.
NTSTATUS NtSetIntervalProfile ( ULONG Interval, KPROFILE_SOURCE ProfileSource);
in version 3.51 and higher, but
NTSTATUS NtSetIntervalProfile (ULONG Interval);
in versions 3.10 and 3.50.
The Interval argument provides the new time or count that is to separate profile interrupts that have the given source. The unit of measurement depends on the source.
The ProfileSource argument selects a possible source of profile interrupts.
The function returns STATUS_SUCCESS if successful, else a negative error code.
The NtSetIntervalProfile function and its alias ZwSetIntervalProfile are exported by name from NTDLL in version 3.10 and higher. In kernel mode, where ZwSetIntervalProfile is a stub and NtSetIntervalProfile is the implementation, neither is exported until the 1607 release of Windows 10 exports the stub.
Neither NtSetIntervalProfile nor its alias is documented. As ZwSetIntervalProfile, it is declared in the ZWAPI.H file in the Windows Driver Kit (WDK) for Windows 10.
The semi-documented repackaging of NtSetIntervalProfile in a higher-level user-mode module (than NTDLL) is the TraceSampledProfileIntervalInfo (0x05) information class of the ADVAPI32 and SECHOST function TraceSetInformation. Not that the documentation spells it out, but the information buffer to provide for this information class is the TRACE_PROFILE_INTERVAL. Though the structure appears to be undocumented, a C-language definition is available in EVNTRACE.H. That structure’s non-zero Source on input is in fact a KPROFILE_SOURCE. It and the structure’s Interval becomes the two arguments to NtSetIntervalProfile.
The following implementation notes come mainly from inspection of the kernel from the original release of Windows 10. They may some day get revised to account for other versions. Where anything is written about earlier versions, take it not as an attempt at presenting a comprehensive history but as a bonus from my being unable to resist a quick trip down memory lane. I have no programme of revisiting this analysis for later releases. Updates mean just that I happen to have noticed something and to have found time to add it.
The function requires SeSystemProfilePrivilege. Without it, the function returns STATUS_PRIVILEGE_NOT_HELD. With it, the function necessarily succeeds, but the behaviour is not trivial. It may help to sketch the basic behaviour before getting to details.
All profile sources other than ProfileAlignmentFixup (0x01) are managed by the HAL. On each currently active processor, the kernel calls the HAL via the HalSetSystemInformation pointer in the kernel’s HAL_DISPATCH, specifically for the information class HalProfileSourceInterval (0x00), giving the Interval and ProfileSource as the information.
What, if anything, the HAL does with the Interval and ProfileSource is immaterial to the NtSetIntervalProfile function. Some points to watch for can be surmised as interface features. The profile source might not be supported. For each supported profile source, the HAL has a minimum and maximum interval which can be learnt in advance even from user mode through TraceQueryInformation with the information class TraceProfileSourceListInfo (0x07). How the HAL is required to respond to an attempt to set an interval that is too small or too large is unclear. Indeed, it’s not clear that the HAL is required to accept any interval exactly as given. If it matters, e.g., for calculations, to know what interval the HAL uses, it might be prudent to follow NtSetIntervalProfile with a call to NtQueryIntervalProfile.
Beware anyway that profile sources are global. An interval that one process sets for a profile source can be changed by any other sufficiently privileged process’s call to the same function for the same profile source.
If the tracing of profile events to NT Kernel Logger sessions is enabled when the function has set the interval, the function will trace an event to record what the interval changed from. If the tracing of profile events is already enabled before the function sets the interval, the function first queries for the current setting, as preparation.
The profile source ProfileTime (0) has special interest to the kernel for cache errata support. If the desired Interval is larger than the kernel needs for that support, the kernel’s interval is what gets set.
For ProfileAlignmentFixup, the kernel does not involve the HAL but simply remembers the given Interval. No x86 or x64 build of Windows in any version is known to make any other use of this interval except that it can be set and queried.
Once the interval has been set as described above, if tracing of profile events is enabled, the function queries for what actually did get set as the new interval and puts both the new and old settings in an event. If tracing was not enabled before the function set the interval, then zero is used as the old setting. The hook ID for the event that records the change of interval is PERFINFO_LOG_TYPE_SAMPLED_PROFILE_SET_INTERVAL (0x0F48).