The EVENT_TRACE_PROFILE_COUNTER_INFORMATION structure is one of many that the ZwSetSystemInformation and NtSetSystemInformation functions expect as input when given the information class SystemPerformanceTraceInformation (0x1F). This particular structure is selected when the first dword in the information buffer is EventTraceProfileConfigInformation (0x0C) or EventTraceProfileCounterListInformation (0x0F).

Documentation Status

The EVENT_TRACE_PROFILE_COUNTER_INFORMATION structure is not documented. Its only known public existence in anything like plain text is a C-language definition in a header file named NTETW.H from the Enterprise edition of the Windows Driver Kit (WDK) for Windows 10 version 1511.


At least in user mode, the EVENT_TRACE_PROFILE_COUNTER_INFORMATION structure arguably exists only to support the documented ADVAPI32 (or SECHOST) function TraceSetInformation for its information classes TraceProfileSourceConfigInfo (0x06) and TracePmcCounterListInfo (0x09). Well-behaved user-mode software executing above ADVAPI32 does not call NtSetSystemInformation but prefers TraceSetInformation and therefore has no need of this structure.

Or so might go the theory or principle. Against it is that Microsoft’s documentation of TraceSetInformation, as perused online today (30th November 2016), does not tell programmers what information to provide in what form. For instance, of TracePmcCounterListInfo it says only “Query the list of performance monitoring counters to collect.”


The EVENT_TRACE_PROFILE_COUNTER_INFORMATION is 0x18 bytes in both 32-bit and 64-bit Windows.

Offset Definition

Though the elements of the ProfileSource array are defined as ULONG, they take values from the KPROFILE_SOURCE enumeration. This is defined in WDM.H and lists the types of profiling data that the HAL may keep about processor performance. It is presumably also defined in headers that Microsoft does not publish but makes available to its own user-mode programmers: how else does type information for it appear in symbol files for such high-level modules as the URLMON.DLL from Internet Explorer?

Though the one EVENT_TRACE_PROFILE_COUNTER_INFORMATION structure serves both information classes EventTraceProfileConfigInformation and EventTraceProfileCounterListInformation, NTETW.H helpfully defines the alias EVENT_TRACE_PROFILE_CONFIG_INFORMATION for the structure’s use with the first of them.


The EVENT_TRACE_PROFILE_COUNTER_INFORMATION structure is meaningful only as input to the ZwSetSystemInformation function in two cases. Their behaviour is as well picked up here. This review takes as understood all the general points and shorthands that are noted in the separate attempt at documenting the function, and takes as granted that the information class is SystemPerformanceTraceInformation and that the information buffer is at least large enough for an EVENT_TRACE_PROFILE_COUNTER_INFORMATION structure up to but not including the ProfileSource array and in which the EventTraceInformationClass is either EventTraceProfileConfigInformation or EventTraceProfileCounterListInformation.




The point to the ProfileSource array is that although it is defined formally as having only one element, it is meant to continue for the remainder of the information buffer. If the information buffer is not exactly right for zero or more whole array elements, the function returns STATUS_INVALID_PARAMETER.

The TraceHandle selects an event logger. Specifically, the low 16 bits are the logger ID or are 0xFFFF to select the NT Kernel Logger. This interpretation of 0xFFFF is formalised by the definition of a macro KERNEL_LOGGER_ID in the NTWMI_X.H header in the Windows Driver Kit (WDK) for Windows 10. If the logger ID does not select an active logger to which the function can arrange exclusive access, the function returns STATUS_WMI_INSTANCE_NOT_FOUND. If the caller does not have the TRACELOG_GUID_ENABLE permission for the logger, the function fails, typically returning STATUS_ACCESS_DENIED.

The function is to configure the logger for receiving the processor performance monitoring counters that are represented by the given profile sources. The implementation can support at most four profile sources per logger. If the information buffer supplies either none or more than four, the function returns STATUS_INVALID_PARAMETER. If the logger is set to use paged memory, as from having EVENT_TRACE_USE_PAGED_MEMORY in its logger mode, then the function returns STATUS_INVALID_PARAMETER.

To profile counters, the logger must have an ETW_PMC_SUPPORT structure. If it does not already have one but the function cannot create one, the function returns STATUS_NO_MEMORY.

Each logger can have profile counters set for it just the once. Whatever sources are set remain set until the logger is stopped. If the logger already has a source set, the function returns STATUS_WMI_ALREADY_ENABLED.

The profiling is actually done by the HAL. For each currently active processor, the given profile sources are passed to the HAL via the HalAllocatePmcCounterSets pointer in the kernel’s HAL_PRIVATE_DISPATCH_TABLE. Failure for any processor is failure for the function.