Back to Blog

How to Troubleshoot Windows Performance Issues with ETW

Christopher 8 min read
etwtroubleshootingwindowsperformancekernel-memory

This post describes Event Tracing for Windows (ETW), the providers commonly used for performance troubleshooting, the standard ETW capture workflow, and patterns observed in trace analysis.

What ETW is

ETW is a kernel-level tracing framework included in every version of Windows since XP. ETW captures real-time events from the kernel, drivers, and applications at microsecond granularity. Process file opens, memory allocations, network packet transmissions, and exception records are all emitted by ETW providers.

The Windows kernel exposes hundreds of event providers covering disk I/O, context switches, page faults, and other subsystems. ETW is the data source used by Windows Performance Analyzer (WPA), ProcMon, and xperf.

A busy server can emit millions of ETW events per minute. The volume makes unfiltered manual analysis impractical.

Standard capture workflow

The standard ETW troubleshooting workflow uses logman, xperf, or wpr to start a trace session, reproduce the condition, stop the trace, and analyze the resulting .etl file in WPA.

Example using logman:

# Start kernel trace sessions for process and disk events
logman create trace "PerfTrace" -p "Microsoft-Windows-Kernel-Process" -o C:\Traces\perf.etl
logman create trace "DiskTrace" -p "Microsoft-Windows-Kernel-Disk" -o C:\Traces\disk.etl
logman start "PerfTrace"
logman start "DiskTrace"

Reproduce the condition while the trace is running, then stop the trace:

logman stop "PerfTrace"
logman stop "DiskTrace"
# Open .etl files in WPA for analysis

Analysis requires correlating events across providers in WPA.

Providers used for performance troubleshooting

Microsoft-Windows-Kernel-Process. Process creation, termination, thread activity, and CPU consumption.

Microsoft-Windows-Kernel-Disk. Disk read and write records including byte offsets, file paths, and per-I/O latency.

Microsoft-Windows-Kernel-Network. TCP/UDP connections, DNS lookups, and packet transmission.

Microsoft-Windows-Kernel-Memory. Page faults, working set changes, and memory allocation records.

Microsoft-Windows-Kernel-Registry. Registry reads and writes.

Microsoft-Windows-TCPIP. Lower-level network diagnostics including retransmissions, connection resets, and MTU records.

Deep dive into the Microsoft-Windows-Kernel-Memory provider

When the symptom is memory pressure specifically, microsoft-windows-kernel-memory is the provider that exposes the memory manager's accounting. It is a manifest-based provider, not part of the legacy NT Kernel Logger, so it can be enabled into an ordinary real-time session alongside your other providers.

Provider GUID

The provider GUID is {D1D93EF7-E1F2-4F45-9943-03D245FE6C00}. Confirm it on any Windows host with:

logman query providers | findstr kernel-memory
# Microsoft-Windows-Kernel-Memory          {D1D93EF7-E1F2-4F45-9943-03D245FE6C00}

What it exposes

The provider emits periodic accounting snapshots and state-transition events rather than a record for every heap allocation. Keywords select which families you receive, and the set has grown across Windows releases:

KeywordMaskWhat you get
KERNEL_MEM_KEYWORD_MEMINFO0x20System-wide snapshot: zeroed, free, modified, and standby page-list counts, paged and nonpaged pool page counts, and total commit charge (CommitPageCount).
KERNEL_MEM_KEYWORD_MEMINFO_EX0x40Per-process and per-session working-set and commit detail.
KERNEL_MEM_KEYWORD_WS_SWAP0x80Working-set swap start and stop as the memory manager writes a process working set out to, or reads it back from, the swapfile, with the process ID and pages processed.
KERNEL_MEM_KEYWORD_ACG0x100Arbitrary Code Guard mitigation events.
KERNEL_MEM_KEYWORD_PHYSICAL_ALLOC0x200Physical page allocation events.
KERNEL_MEM_KEYWORD_MEMINFO_NODE0x400Per-NUMA-node memory snapshot, the node-resolved companion to MEMINFO.

That covers pool growth (paged and nonpaged pool page counts), commit-charge trends, working-set and swap pressure, and on current builds physical page allocations and per-NUMA-node snapshots. The two keywords above the original four (0x200 and 0x400) exist only on newer Windows releases; the 2018 (1803) manifest stopped at 0x100, and the provider also carries an Analytic group keyword (0x8000000000000000). What it still does not give you is a per-heap-allocation stream or a record for every page fault. Per-fault records come from the kernel system-trace provider (the hard-fault and memory kernel flags), not this manifest provider. Use Kernel-Memory for accounting and trends; reach for the kernel logger when you need per-fault granularity.

Enabling it

With logman, pass the combined keyword mask (here 0xe0 = MEMINFO | MEMINFO_EX | WS_SWAP):

logman create trace "MemTrace" -p "Microsoft-Windows-Kernel-Memory" 0xe0 -o C:\Traces\mem.etl
logman start "MemTrace"
# reproduce the memory pressure, then:
logman stop "MemTrace"

From C# with the TraceEvent library, enable the provider by GUID and decode events live. Run elevated:

using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Session;

// Manifest provider, so an ordinary real-time session works.
using var session = new TraceEventSession("ETDuckyKernelMemory");

// MEMINFO (0x20) | MEMINFO_EX (0x40) | WS_SWAP (0x80)
session.EnableProvider(
    new Guid("d1d93ef7-e1f2-4f45-9943-03d245fe6c00"),
    TraceEventLevel.Informational,
    0x20 | 0x40 | 0x80);

session.Source.Dynamic.All += e =>
{
    if (e.ProviderName != "Microsoft-Windows-Kernel-Memory") return;
    Console.WriteLine(e.TimeStamp.ToString("HH:mm:ss.fff") + "  " +
        e.EventName + "  commit=" + e.PayloadByName("CommitPageCount"));
};

session.Source.Process(); // blocks until the session is stopped

Known limitations and gotchas

It is a snapshot, not a stream. The MEMINFO event fires on an interval, so a short trace can miss a fast spike. Keep the session running across the full reproduction.

WS_SWAP only fires when the system actually swaps. Working-set swap targets the swapfile used by modern (UWP) app suspension. On servers where that swapfile is disabled, those events never appear, which is expected rather than a capture failure.

The real limit is the session ceiling, not a provider conflict. Kernel-Memory is a manifest provider, so it starts in its own ordinary session and coexists with a live kernel session that is already carrying Kernel-Network and the WFP provider. We verified this on a running host. A Kernel-Memory trace started cleanly while a WFP and Kernel-Network capture was active, with no error. What you actually hit is Windows' bounded number of concurrent ETW sessions. On a test host already running about 44 trace sessions (many of them always-on networking, Wi-Fi, antivirus, and diagnostic autologgers), a loop that kept opening new Kernel-Memory sessions failed on the 17th with Insufficient system resources exist to complete the requested service. If EnableProvider or logman start fails that way, stop an unused session or attach to an existing autologger rather than creating another; it is slot and buffer exhaustion, not a clash between the memory and WFP providers.

When to use it versus adjacent kernel providers

ProviderReach for it when you need
Microsoft-Windows-Kernel-MemoryMemory accounting over time: commit charge climbing, pool growth, working-set and swap pressure.
Microsoft-Windows-Kernel-ProcessAttribution to a process or thread: create and exit, CPU time, image loads. Pair it with Kernel-Memory to tie a commit climb to a specific PID.
Microsoft-Windows-Kernel-NetworkA network-bound cause: TCP and UDP connections, sends and receives, DNS. Use it when memory looks healthy but latency or throughput is the symptom.

A leak investigation usually enables all three at once. Kernel-Memory watches the commit and working-set climb, Kernel-Process attributes it to a PID, and Kernel-Network rules out a backlog of unclosed sockets pinning nonpaged pool.

Common patterns in trace data

High context switch rate with low CPU. Indicates thread contention. Threads spend more time waiting for locks than executing. The Kernel-Process provider includes thread wait-chain records.

Disk I/O spikes correlating with memory pressure. Indicates paging. When physical memory is exhausted, Windows pages memory to disk, producing disk I/O. The Kernel-Memory provider records the working-set transitions.

Periodic CPU spikes every 15 to 30 minutes. Typical of scheduled tasks, antivirus scans, or Windows Update checks. The Kernel-Process provider records the process and exec time.

Gradual working-set growth over days. Consistent with a memory leak. Working-set growth is captured by the Kernel-Memory provider.

Network timeouts without packet loss. Consistent with DNS resolution delays or certificate revocation checks. The TCPIP and DNS providers record the timing.

Scaling ETW capture

Per-host ETW capture requires interactive access to each machine, manual trace start and stop, and per-machine analysis. Across a fleet of endpoints, that workflow does not aggregate.

An alternative model uses an agent that runs ETW capture continuously, applies correlation rules on the host, and emits summarized records. Correlation reduces the per-host data volume from megabytes per second of raw events to kilobytes per minute of summary records while preserving the records used in root-cause analysis.

Linux parity

The Linux equivalent is eBPF. eBPF programs attached to scheduler and syscall tracepoints emit process, file, and network events at kernel speed. The on-host correlation model applies the same way.

Frequently asked questions

What is the Microsoft-Windows-Kernel-Memory provider GUID?

It is {D1D93EF7-E1F2-4F45-9943-03D245FE6C00}. You can confirm it on any host with logman query providers | findstr kernel-memory.

What events does the Microsoft-Windows-Kernel-Memory provider expose?

Periodic system-wide memory snapshots (free, modified, and standby page lists, paged and nonpaged pool page counts, and commit charge), per-process working-set and commit detail, working-set swap start and stop, and Arbitrary Code Guard events. Current Windows builds add physical page allocations (0x200) and per-NUMA-node snapshots (0x400). It is an accounting and state-transition provider, not a per-heap-allocation or per-page-fault tracer.

How do I enable the Microsoft-Windows-Kernel-Memory provider?

From an elevated prompt, start a trace with logman or the TraceEvent library and select the keyword mask you need. Use 0x20 for system memory info, 0x40 for per-process detail, and 0x80 for working-set swap events. See the enabling examples above.

When should I use Kernel-Memory instead of Kernel-Process?

Use Kernel-Memory for memory accounting (commit charge, pool, working set, swap) and Kernel-Process to attribute that activity to a process or thread. Memory-leak and paging investigations typically enable both together.

For more on how ET Ducky puts ETW to work in production, see AI-driven dynamic ETW diagnostics, Kernel-Network vs TcpIp for network telemetry, diagnosing app failures with environmental diffs, and what standard RMM agents miss that ETW can see.

ET Ducky

Documentation and pricing are available on this site.

View Pricing