WPR/WPA in Practice — An Introduction to System-Wide Performance Investigation for "the Whole PC Is Slow"

· · Windows, Performance, WPR, WPA, ETW, Performance Investigation, Troubleshooting, Windows Development

“They said the whole PC got slow after they installed a new app. But when I look at Task Manager, both CPU and memory have headroom.” “There is one PC that takes 3 minutes to start. I have no idea what is wrong.” — Performance consultations really do come in this shape a lot. What they have in common is that looking at a specific process does not give you an answer.

Process-level tools are in place. File and registry access can be seen with Process Monitor, and a .NET app’s CPU and GC can be followed with PerfView. But a symptom such as “the whole PC is slow” or “CPU is idle and it is still slow” starts from not even knowing which process is the culprit. App A may be slow because of an antivirus scan, or because another service is writing heavily to disk, or because of a lock chain that spans several processes. What you need is data that recorded not the inside of a process but the OS as a whole on a single timeline.

The tools for capturing and reading that are Windows Performance Recorder (WPR) and Windows Performance Analyzer (WPA). WPR records OS-wide activity on an ETW (Event Tracing for Windows) base, and WPA analyzes that recording in graphs and tables. Who used CPU on which stack, who a thread was waiting for, which process issued disk I/O to which file — facts a step or two below Task Manager all remain, with timestamps.

Aimed at IT staff in small and medium businesses and at Windows app developers, this article organizes the practice of capturing with WPR and how to read WPA — especially the difference between investigating “when CPU is high” and “when CPU is low and it is still slow” — grounded in primary sources as of August 2026.

1. The Bottom Line First

  • The first choice for a “the whole PC is slow” investigation is WPR/WPA, which captures and reads an OS-wide ETW trace. Problems that process-level tools (Task Manager, Procmon, PerfView) cannot pin down can be followed if you look at every process and the kernel on a single timeline.12
  • The capture tool wpr.exe ships with Windows 8.1 and later. You can use it with no extra install. The GUI edition (WPRUI) and the analysis tool WPA are included in the Windows ADK.12
  • The basic procedure is three lines. As administrator, wpr -start GeneralProfile -filemode → reproduce the issue → wpr -stop C:\temp\trace.etl. Remember just that and you can start capturing.3
  • The field baseline is a split of “in the customer environment, only capture with wpr.exe; reading is WPA on your own machine”. You can capture even on a server where you cannot install software. It is the same idea as packet capture’s “capture with a standard tool, read in Wireshark”.1
  • Reading WPA starts by classifying “CPU, wait, or I/O”. If CPU is burning, CPU Usage (Sampled); if CPU is idle and it is still slow, wait analysis in CPU Usage (Precise); if disk is suspected, Disk Usage — the path splits at the start.45
  • CPU Usage (Sampled) shows “which function used CPU” from sampling about every 1 millisecond. You can walk the breakdown of Task Manager’s “50%” from process → thread → stack → function.6
  • CPU Usage (Precise) is a complete record of context switches, and tells you “who a thread was waiting for”. Walking Waits (wait time), ReadyingProcess (who woke it), and ReadyThreadStack (the waker’s stack) is the technique this article most wants to convey.47
  • Reading a stack requires symbol configuration. WPA refers to Microsoft’s public symbol server by default. To see function names in your own app, add the path to your own PDBs.8
  • An ETL file contains internal system information such as process names and file paths. Keep the capture to the minimum needed, and decide how it will be handled if it leaves the company before you capture.

2. Where the Tools Sit — WPR Captures, WPA Reads

Windows Performance Toolkit (WPT) is the performance-investigation toolset included in the Windows ADK (Windows Assessment and Deployment Kit); the center is the pair of WPR and WPA.2 The roles are clearly split.

  • WPR (Windows Performance Recorder) = capture. It bundles groups of ETW providers into a unit called a “profile”, starts and stops recording, and produces an ETL file. The command-line edition, wpr.exe, ships with Windows 8.1 and later, with no extra install. The GUI edition (WPRUI.exe) is included in the ADK.1
  • WPA (Windows Performance Analyzer) = analysis. It opens an ETL file and analyzes it in graphs and tables. An ADK install is required.2

In other words, there is nothing you need to place in the customer environment. Capture with the OS-standard wpr.exe, take the ETL file home, and read it in WPA on your own PC — the same split as packet capture’s “capture with pktmon, read in Wireshark” holds.

The split of capturing with WPR and reading with WPAIn the customer environment, record with the OS-standard wpr.exe and produce an ETL file; take it home and analyze it in WPA installed via the ADK on your own PCYour PC (WPA via ADK)Customer PC (no extra install)Take homeAnalyze graphs and tablesETL filewpr start → reproduce → stop

How it differs from similar tools is also worth organizing first.

  Process Monitor PerfView WPR + WPA
The question it answers Which process did what to which path, and what happened How is a .NET app’s CPU, GC, and allocation looking Across the OS, where did time disappear
Scope Operation log of file, registry, and process start Managed code first System-wide CPU, waits, disk, file I/O, power, and the like
Suited symptoms A setting is not being read, ACCESS DENIED Slowness or memory of your own .NET app alone The whole PC is slow, CPU is idle and it is still slow, culprit process unknown
Article A Practical Guide to Procmon A Practical Introduction to PerfView This article

If Procmon is an operation log of “what it did” and PerfView is “what happened inside .NET”, WPA is a tool that audits “where time disappeared” across every process. The mechanics of ETW itself, and how to instrument your own app with ETW, are covered in “An Introduction to Windows Event Log and ETW”. If your own app emits ETW events, your app’s checkpoints are recorded in the same trace and lining them up becomes much easier. WPR, however, records only events from providers enabled by the recording profile you chose. GeneralProfile does not include your own providers, so if you want them mixed in, prepare a custom recording profile (.wprp) that enables your providers and combine it as wpr -start GeneralProfile -start MyApp.wprp!MyAppProfile, specifying the profile name inside the .wprp file with !3.

3. Capture in Practice (WPR) — start, Reproduce, stop

The basic procedure in an administrator terminal.

:: List of built-in profiles you can use
wpr -profiles

:: 1. Start capture (general-purpose profile, file mode)
wpr -start GeneralProfile -filemode

:: 2. Reproduce the issue (check capture status with wpr -status)

:: 3. Stop and save (you can attach a description of the problem).
::    Create the destination folder in advance (without it, -stop fails to save)
mkdir C:\temp 2>nul
wpr -stop C:\temp\slow-pc.etl "Reproduced the issue where the whole PC becomes slow while starting App X"

:: To abandon without saving
wpr -cancel

What you pass to -start is a profile, a bundle of the ETW providers that investigation needs.3 Remembering only the ones you use often is enough.9

Profile What it records When to use it
GeneralProfile A general-purpose set including CPU samples, context switches, and disk I/O Start here. The first move when you do not know what is wrong
CPU Detailed CPU usage When you already know CPU is burning
DiskIO Disk I/O activity When disk is suspected
FileIO File I/O activity When you want to follow which file is being accessed

You can specify several profiles at once by lining up -start (for example wpr -start GeneralProfile -start FileIO -filemode).3

WPR capture flow and how to choose a modeAn issue you can reproduce on the spot is captured short and reliably in file mode; an issue whose timing you do not know is waited out in the default memory-mode ring buffer. An issue during boot or logon uses a boot trace. In every case the start / reproduce / stop procedure is the sameOn the spotTiming unknownBoot or logonWhen does it occur?File mode: short captureMemory mode: wait (3.1)Boot trace (Ch. 8)start → reproduce → stop

3.1. Memory mode and File mode — can you reproduce, or do you wait

WPR has two recording-destination modes; the default is Memory mode (an in-memory circular buffer). It is a ring buffer that overwrites from the oldest events, so it is suited to leaving capture running while you wait for an issue whose timing you do not know, and stopping when it happens. Adding -filemode switches to File mode, and everything is recorded to a continuous file. This is not overwritten away; the only ceiling is free disk space, and the file grows without bound.10

How Memory mode and File mode recordMemory mode records to an in-memory circular buffer; older events are overwritten and only the most recent remain, so it is suited to waiting. File mode keeps everything in a file, but the only ceiling is free disk space, so it is suited to a short, reliable reproductionETW eventsMemory mode: ring bufferFile mode: grow a fileWait for unknown timingShort, reliable reproduce

A rule of thumb for choosing is as follows.

  • Reproducible on the spot → File mode. Start just before reproduction, stop just after, and keep the capture within a few minutes
  • Timing unknown → Wait in Memory mode (the default). As soon as it occurs, wpr -stop
  • Even a few minutes of GeneralProfile can produce an ETL in the hundreds of MB to GB class. A file that is too large can become unanalyzable in WPA, so “the longer you capture, the better” is counterproductive1011

To capture from the GUI, start WPRUI, pick a profile and Logging mode, and Start/Save. The official How-to summarizes the procedure.11 If you ask a customer-site contact to capture, the three commands above can go into a procedure as-is.

4. The Basics of Reading WPA — Graphs, the Golden Rule of Tables, and Narrowing Time

When you open a captured ETL in WPA, the left-hand Graph Explorer lists graph thumbnails in categories such as System Activity, Computation, Storage, and Memory.12 Drag a graph you want to see onto the Analysis tab on the right, and a graph appears above and a table below. The first three things to take on board are these.

  1. The golden rule of tables — column order decides grouping. A WPA table has two vertical bars, gold and blue, and columns to the left of the gold bar hierarchize (group) the data in that order, and columns to the right of the blue bar are aggregates.13 Arrange them Process → Stack and you get a per-process stack aggregation; Stack → Process and you get an aggregation of every process that uses the same stack — dragging columns to reorder them is itself an analysis operation. Understand this one point and every WPA table is read the same way.
The golden rule of tables — the two bars and the role of columnsColumns to the left of the gold bar hierarchize the data in that order; columns between the gold and blue bars are display columns; columns to the right of the blue bar are aggregates. Dragging columns to reorder them is itself an analysis operationLeft of gold: groupingGold barBetween bars: displayBlue barRight of blue: aggregatesDrag columns to analyze
  1. Narrow the time range. Drag on the graph to select a range, then right-click and “Zoom”, and the aggregation switches to that interval only. Performance investigation is always, in principle, looking only at “the interval when the issue was happening” (Chapter 9).
  2. Configure symbols. To read a stack by function name, run Trace > Load Symbols from the menu.14 By default it refers to Microsoft’s public symbol server (msdl.microsoft.com), so Windows’s own stacks can be resolved if you have an Internet connection. To see function names in your own app, add the folder of your app’s PDBs in Trace > Configure Symbol Paths.8 What a PDB is, and why you should always keep it even for a Release build, is summarized in “What Is a PDB (Program Database)?”. For .NET Framework NGen native images, WPR generates NGen PDBs (.ngenpdb) at capture time and places them in a folder next to the trace, and WPA refers to them automatically.8 This is a mechanism for NGen images only, and ordinary JIT .NET app code of your own is out of scope. The mapping from a JIT-code address to a function name is resolved from JIT events the CLR emits, so when you investigate a .NET app, prepare a recording profile (.wprp) that enables the CLR providers (Microsoft-Windows-DotNETRuntime and the matching Rundown) and combine it the same way as your own providers in Chapter 3, wpr -start GeneralProfile -start MyDotNet.wprp!profile-name, so that CLR events are included in the trace (you can check which built-in profiles your local WPR offers with wpr -profiles). On top of that, keep the PDBs generated by the build for mapping to source lines, and add them to the symbol path above.
Symbol resolution for reading a stack by function nameRunning Trace Load Symbols resolves Windows itself from Microsoft's public symbol server, and your own app from build PDBs added to the symbol path. NGen images use NGen PDBs that WPR generates; JIT .NET code is resolved from CLR JIT events in the trace plus build PDBsTrace > Load SymbolsWindows: public symbolsOwn app: build PDBsNGen: WPR .ngenpdbJIT: CLR events + PDBs

Once you are prepared, you enter from the next branch. In that interval, was CPU high, or low? If high, Chapter 5 (Sampled); if low and still slow, Chapter 6 (Precise).

Branch for choosing a WPA graph from the symptomZoom to the issue interval; if CPU is high go to CPU Usage Sampled; if low and still slow, check for a single-core / single-thread pin and then wait analysis in CPU Usage Precise; if disk is suspected, Disk Usage and File IOHighLow, still slowYesNoDisk suspectedZoom to the issue intervalCPU in that interval?Ch. 5: Sampled1-core / 1-thread pin?Ch. 6: PreciseCh. 7: Disk / File I/O

5. When CPU Is High — “Who Is Burning Which Function” with CPU Usage (Sampled)

If CPU is pinned, what you look at is CPU Usage (Sampled). This is sampling data that recorded, about every 1 millisecond on every CPU, “which process’s which stack is running now”, and the ratio of sample counts is the breakdown of CPU time as-is.6

How CPU Usage Sampled worksAbout every 1 millisecond, the stack running on every CPU is recorded, and the aggregated sample ratio is the breakdown of CPU time. Read from process to thread, stack, and function. Short activity that finishes between samples does not appearInterrupt about every 1 msRecord the running stackSample ratio = CPU breakdownProcess → Thread → StackActivity between samples is missed
  1. From Graph Explorer’s Computation, place CPU Usage (Sampled) on the Analysis tab and pick the Utilization by Process, Stack preset.5
  2. Look at processes in descending order of Weight (or Count). The identity of what was “50%” in Task Manager becomes clear first at the process level.
  3. Expand the culprit process’s Stack column. Stacks are aggregated as a tree, and walking the path where the number does not drop much at a branch lands you on the function that is burning CPU. If symbols are resolved, it is a straight line to which function in your own code.
  4. If expanding the tree is tedious, switch the graph display to Flame. It is drawn with width = share of CPU time, so which call path dominates is obvious at a glance. CPU Usage (Sampled) also has a Flame by Process, Stack preset.13

There is one caveat. Because it is sampling, short activity that finishes between samples does not appear.6 Remember it as a tool for seeing “where CPU was used in aggregate”, not a tool for measuring exact per-invocation duration.

6. When CPU Is Low and It Is Still Slow — CPU Usage (Precise) and Wait Analysis

This is the core of the article. Before you proceed to wait analysis, though, there is one thing to confirm. “Overall CPU usage is low” does not mean “CPU is not the bottleneck”. On a 16-core PC, serial work pinned to one core (a single UI thread running flat out) only looks like about 6% overall. First check in Chapter 5’s Sampled (or CPU Usage (Precise)’s Utilization by CPU) that there is no pin on a specific core or thread, and if there is not, come to this chapter — the work is not unable to run, it is waiting. What tells you what it is waiting for is CPU Usage (Precise).

Where Sampled is sampling, Precise is a complete record of context switches (thread switches). A thread enters a wait, is woken by someone (Ready), and lands on a CPU — that round trip remains one row at a time, and you can read the following columns.74

Column Meaning
NewThreadStack On which stack that thread entered the wait (= what it was doing when it stopped)
Waits (us) How long it waited
Ready (us) How long it was made to wait from being woken until it landed on a CPU (CPU contention)
ReadyingProcess / ReadyingThreadId The process and thread that woke that thread (released the wait)
ReadyThreadStack On which stack the waker woke it
One wait round trip and how the columns correspondA thread enters a wait on the stack that remains in NewThreadStack, and waits for the Waits time. When someone wakes it, that party remains in ReadyingProcess and ReadyThreadStack; it waits the Ready time for CPU contention and then runs againEnter waitSomeone wakes itLands on a CPURunningWait (Waits us)Ready (CPU contention)Running againNewThreadStack / ReadyingProcess

The reading pattern is as follows.4

  1. Apply the Utilization by Process, Thread preset and add NewThreadStack and ReadyThreadStack to the columns.
  2. First identify the thread that was executing the delayed operation (the UI thread, the thread handling the request in question). Looking only in descending order of total Waits is confusing, because threads that are “intentionally waiting the whole time”, such as a message pump or a timer, occupy the top. Once you have found the target thread, if its CPU Usage (ms) is large it is a Chapter 5 CPU problem; if Waits dominate it is a wait problem.
  3. Expand NewThreadStack and see what it was doing when it stopped. WaitForSingleObject or EnterCriticalSection is a lock wait; inside synchronous I/O such as ReadFile it is an I/O wait; inside a socket receive it is waiting for the peer to respond.
  4. Next see who released the wait. Expand ReadyThreadStack and check ReadyingProcess / ReadyingThreadId. If it was woken from the kernel’s KiTimerExpiration it was a timer (= it slept until a timeout); if it was woken from I/O completion handling, that confirms it was an I/O wait.4
  5. If the party that woke it is another thread or another process, investigate that thread with the same procedure. “A was waiting for B to release a lock, B was waiting for C’s RPC response, C was waiting for disk I/O” — what you have when you have walked this chain to the root is the delay’s critical path.7
The critical-path chain you walk in wait analysisSee in delayed thread A's NewThreadStack what it was doing when it stopped, identify the waker B from ReadyThreadStack and ReadyingProcess, and investigate B with the same procedure down to the root disk I/OLock waitRPC waitSync I/O waitCompletion wakes CResponse wakes BLock release wakes AThread A (delayed work)Thread B (holds lock)Process CDisk I/O (root)

In a case such as “we multithreaded it and it did not get faster”, this procedure shows every worker lined up on a single lock as-is. Avoiding lock contention by design is covered in “Practical Multithreading Best Practices: .NET Edition”, and the Windows mechanism that runs on a completion notification instead of waiting in synchronous I/O is covered in “I/O Completion Ports (IOCP) and the .NET Thread Pool”. Pinning down “who it was waiting for” in WPA and fixing it with those design arguments is one continuous flow.

7. Disk and File I/O — Identifying “Someone Is Scanning the Disk”

A classic culprit of “the whole PC is slow” is not CPU but disk. You investigate with Disk Usage and File I/O in the Storage category.15

Disk Usage is a record of disk I/O, and two columns matter. Disk Service Time is the time the disk device actually spent processing that I/O; IO Time is the time from the I/O entering the OS queue until it completed. IO Time is always at least Service Time by the amount of queueing, so if IO Time is much longer than Service Time, that I/O was “waiting in the queue”.6 That alone, however, does not decide whether the culprit that made the queue is another process, or only that process’s own heavy I/O lined up on a slow device. Do not draw the conclusion here; settle it with Service Time (the device’s own response) and the next breakdown by process, path, and stack.

Then, with the Utilization by Process, Path Name, Stack preset, look at which process issued I/O to which file from which stack, in descending order of IO Time or Size.15 The answers that come up often in the field are these two.

  • Antivirus was scanning every file. In the window when the app was slow to start, the antivirus process is seen issuing a large volume of reads. Process name, path, and volume are evidence as-is for a discussion of exclusions.
  • Another process was writing heavily. Backup, the indexer, logs written too much, and the like. When a write reaches the disk involves the cache manager, so the fact that “the moment you wrote” and “the moment the disk is busy” can diverge is also covered in “Cache Manager — When Does Your WriteFile Actually Reach the Disk?”.

File I/O is one layer up, a record of file operations the app issued (Create/Read/Write and the like), and presets such as Duration by Process, Thread, Type can aggregate time per file name and per operation.15 A case that spends time in the file system or a filter driver before reaching the disk does not appear in Disk Usage, so the mismatch itself — “Disk Usage is peaceful but File I/O is slow” — is a clue. If you want to start from the mechanics of synchronous and asynchronous I/O, see “Synchronous and Asynchronous I/O — What OVERLAPPED Really Means”.

The different layers File IO and Disk Usage seeAn app's file operation travels through the file system and filter drivers from the OS I/O queue to the disk device. File IO records operations at the upper layer; Disk Usage records I/O that reached the disk; the difference between IO Time and Disk Service Time is queue timeApp: ReadFile / WriteFileFS and filters (File I/O)OS I/O queueDisk device (Disk Usage)Missed by Disk UsageIO Time − Service TimeService Time = device

The line of thought “maybe it is short of memory and swapping” can be given a first isolation in Task Manager and Resource Monitor before you go to WPA. Do not, however, dismiss it from committed memory alone — even with commit headroom, a situation where physical-memory pressure trims the working set and hard faults continue is possible. Also check available physical memory and Resource Monitor’s “Hard Faults/sec”. How to read them is in “What Does Windows’ "Memory Usage" Actually Mean?”.

8. Slow Boot and Logon — The Entrance to a Boot Trace

A “it takes 3 minutes to start” type finishes before you can hand-run wpr -start. WPR has a boot trace, and you can arrange for the OS to start recording automatically on the next boot.3

:: 1. Arrange automatic recording on the next boot
wpr -boottrace -addboot GeneralProfile -filemode

:: 2. Restart (reproduce the slow boot)

:: 3. After boot, stop recording and save (the arrangement is also cleared)
mkdir C:\temp 2>nul
wpr -boottrace -stopboot C:\temp\boot.etl "Issue where boot takes 3 minutes"
Boot-trace flowAfter you arrange automatic recording on the next boot with addboot and restart, the OS starts recording automatically at boot. Saving with stopboot after logon also clears the arrangement. To abandon, clear it with cancelbootwpr -boottrace -addbootRestart (slow boot)OS records at bootAfter logon: -stopbootAbandon: -cancelboot

The boot and shutdown measurement that xbootmgr used to own can also be run in current WPR with options such as -onoffscenario Boot.3 A captured trace is read with the same toolkit as the previous chapters. Look at which process was born when on a timeline in the Processes graph, zoom to the window where boot is stuck, and classify CPU, wait, or disk — a startup app waiting for something in series, a service start stuck on a specific I/O, and the like become visible. Boot analysis is a deep specialty in its own right, so this article only goes as far as the entrance: “an issue you cannot catch by hand can still be captured with WPR”. Start by grasping the overall picture with a GeneralProfile boot trace.

9. A Working Pattern — Classify → Zoom → Stack, Repeated

Now that the tools are clear, here is the pattern for the investigation as a whole.

  1. Pin down the time of the phenomenon. Not “it was slow”, but “10:23:40–10:24:10 was slow”. App logs, the event log, a note from the person who operated it — anything will do. If your own app writes checkpoints to ETW or the event log, events inside the trace become time stakes as-is.
  2. Zoom to that interval only. An aggregation of the whole trace is averaged out, and the anomaly that matters is diluted. WPA analysis is always a comparison of “the interval that was abnormal” versus “the interval that was normal”.
  3. Classify “CPU, wait, or I/O” first. Look at CPU Usage (Sampled); if it is burning, Chapter 5. If it is not burning, Waits in CPU Usage (Precise) (Chapter 6). If Disk Usage IO Time is inflated, Chapter 7. Taking this three-way fork first keeps you from getting lost.
  4. Repeat hypothesis → zoom → stack. If you think “antivirus?”, narrow to that process and back it with the stack. If it does not hold, the next hypothesis. Not drawing a conclusion before you have walked to the stack and backed it is the discipline of this kind of investigation.
The iterative loop of a performance investigationPin down the time of the phenomenon, zoom to the interval, classify CPU / wait / I/O, form a hypothesis and narrow, and back it with the stack. If it holds, the cause is confirmed; if it does not, repeat with the next hypothesisHoldsDoes notPin down the timeZoom to that intervalClassify CPU / wait / I/OHypothesis and narrowBack it with the stackCause confirmed

Finally, handling of the capture file. An ETL file widely reflects the inside of the system: the names of every process, paths of files that were opened, modules that were loaded, and (depending on the profile) registry key names. A standard GeneralProfile capture does not include data bodies such as communication contents, but if you enabled a custom provider, that event’s payload (strings the app recorded, and the like) goes in as-is. After confirming what the providers you enabled emit, treat it as a file confidential enough to leave the company. As with packet capture, fold the minimum needed capture, agreement with the party you hand it to, and a retention period and deletion into the procedure.

What an ETL file reflects, and how to handle itAn ETL reflects every process name, paths of files that were opened, modules, and depending on the profile registry key names; enabling a custom provider also includes its payload. Treat it as confidential: the minimum needed capture, agreement with the other party, and a retention period and deletionETL fileNames, paths, modulesRegistry keys (some)Custom payloadTreat as confidential

10. Summary

  • A “the whole PC is slow” that Task Manager cannot explain is investigated with an OS-wide ETW trace — capture with WPR, read with WPA. wpr.exe ships with Windows 8.1 and later, so a split of capturing in the customer environment, taking the ETL home, and reading it in WPA on your own machine holds.
  • Capture is the three steps wpr -start GeneralProfile -filemode → reproduce → wpr -stop trace.etl. If you can reproduce, File mode within a few minutes; if you wait, Memory mode (ring buffer). Longer is not better.
  • WPA can be started once you have taken on board three points: the golden rule of tables (left of the gold bar = grouping), zooming the time range, and symbol configuration (your own app needs PDBs).
  • If CPU is high, walk process → stack → function in CPU Usage (Sampled). If CPU is low and it is still slow, walk the chain NewThreadStack (what it was doing when it stopped) → Waits (how long it waited) → ReadyingProcess and ReadyThreadStack (who woke it) to the root in CPU Usage (Precise).
  • For disk, see “time spent in the queue” from the difference between Disk Usage IO Time and Service Time, and identify the cause (whether the device itself is slow, or who made the queue) from Service Time and the breakdown by process, path, and stack. Slow boot can be captured with wpr -boottrace.
  • The working pattern is (1) pin down the time (2) zoom to the interval (3) classify CPU, wait, or I/O (4) repeat hypothesis → zoom → stack. Treat an ETL as confidential because it contains internal information.

WPA’s screen is intimidating, and everyone gets lost in the first hour. Once the two backbones — “left of the gold bar is grouping” and “Sampled is where it burned, Precise is who it waited for” — are in, though, the rest is the same operation repeated. The next time a consultation comes in that “CPU has headroom and it is still slow”, close Task Manager and capture a trace.

KomuraSoft LLC handles investigation of system-wide performance problems such as “the whole PC got slow and I don’t know why”, “CPU has headroom and the app is still slow”, and “only a specific environment is extremely slow to start”. We handle as one continuous engagement the capture design with WPR/WPA (in which environment, which profile, how much to capture), trace analysis, and the resulting fix on the app side and the settings side.

References

  1. Microsoft Learn, Introduction to WPR. That WPR is an ETW-based performance recording tool; that the command-line edition WPR.exe ships with Windows 8.1 and later with no extra install; its relationship to the GUI edition WPRUI.exe; and the idea of a recording profile.  2 3 4

  2. Microsoft Learn, Windows Performance Analyzer. That WPA is included in the Windows ADK, is an analysis tool that builds graphs and data tables from ETW events recorded by WPR, Xperf, and the like, and can open and analyze any ETL file.  2 3 4

  3. Microsoft Learn, WPR Command-Line Options. The syntax of wpr -start/-stop/-cancel/-status/-profiles; -filemode (the default is memory mode); specifying several profiles at once; boot traces with -boottrace (addboot/stopboot/cancelboot); and recording On/Off transitions such as Boot with -onoffscenario.  2 3 4 5 6

  4. Microsoft Learn, CPU Analysis. Definitions of the CPU Usage (Precise) graph columns (NewThreadStack, ReadyThreadStack, ReadyingProcess, Waits, and the like); the procedure of expanding ReadyThreadStack and walking ReadyingProcess/ReadyingThread to the root cause of a wait; and how to tell a wake from KiTimerExpiration (a timer wait) or from I/O completion.  2 3 4 5

  5. Microsoft Learn, Troubleshoot processes and threads by using WPR and WPA. Configurations such as reading CPU Usage (Sampled) as Process→Stack on high CPU usage, and using CPU Usage (Precise) Readying Process, Readying Thread, Readying Stack, and the Wait column in wait analysis; and a correspondence table of profiles and graphs by symptom.  2

  6. Microsoft Learn, Exercise 2 - Evaluate Fast Startup Using Windows Performance Toolkit. That CPU Usage (Sampled) is sampling at about a 1-millisecond interval and short activity between samples is not recorded; the procedure of walking process → thread → stack to identify the breakdown of CPU consumption; and the meaning of Disk Usage IO Time (including queue time) and Disk Service Time (disk processing time).  2 3 4

  7. Microsoft Learn, Exercise 3 - Understand Critical Path and Wait Analysis. The idea of critical-path analysis (the Running / Ready / Waiting classification); the meaning of the CPU Usage (Precise) table columns NewThreadStack, ReadyThreadStack, ReadyingProcess, Waits, Ready, and the like; and the procedure of walking the waker thread in turn to unravel a delay chain.  2 3

  8. Microsoft Learn, Loading Symbols. That when _NT_SYMBOL_PATH is unset WPA refers to Microsoft’s public symbol server (msdl.microsoft.com) by default; adding a PDB path for your own components; and that WPR generates PDBs for .NET managed symbols in a .ngenpdb folder next to the trace and WPA refers to them automatically.  2 3

  9. Microsoft Learn, Built-in Recording Profiles. The list of recording profiles built into WPR (CPU usage, Disk I/O activity, File I/O activity, Registry I/O activity, Networking I/O activity, and others) and what each profile records. 

  10. Microsoft Learn, Logging Mode. That recording modes are File (a continuous file) and Memory (an in-memory circular buffer) and the default is Memory; that Memory is suited to an issue whose timing you do not know and older events are overwritten; and that File’s only ceiling is free disk space and a file that is too large can become unanalyzable in WPA.  2

  11. Microsoft Learn, WPR How-to Topics. The procedure for starting and stopping a recording in WPRUI; choosing a profile, detail level, and Logging mode; and the caution that a long recording can make the file huge and unanalyzable in WPA, so Memory mode should be chosen.  2

  12. Microsoft Learn, Graph Explorer. That the Graph Explorer window lists graph thumbnails in categories such as System Activity, Computation, Storage, and Memory; and that you drag a graph onto the Analysis tab to display it together with a table. 

  13. Microsoft Learn, Graphs (WPA Features). WPA’s Flame graph display; the table structure in which columns to the left of the gold bar are grouping and columns to the right of the blue bar are aggregates; and the CPU Usage (Sampled) Flame by Process, Stack preset.  2

  14. Microsoft Learn, Load Symbols or Configure Symbol Paths. Loading symbols with Load Symbols from WPA’s Trace menu; and the procedure for setting and changing the symbol path in the Configure Symbol Paths dialog. 

  15. Microsoft Learn, List of WPA Graphs. The list of graphs available in WPA. Disk Usage presets such as IO Time by Process, IO Type; Service Time by Process, Path Name, Stack; Utilization by Process, Path Name, Stack; and File I/O presets such as Duration by Process, Thread, Type.  2 3

Recent articles sharing the same tags. Deepen your understanding with closely related topics.

These topic pages place the article in a broader service and decision context.

This article connects naturally to the following service pages.

Frequently Asked Questions

Common questions about the topic of this article.

Where do I get WPR and WPA? Can I use them in a customer environment where I cannot install software?
The capture tool wpr.exe (the command-line edition) ships with Windows 8.1 and later, so you can use it with no extra install. The GUI edition, WPRUI, and the analysis tool WPA (Windows Performance Analyzer) are included in the Windows ADK (Windows Assessment and Deployment Kit) and do require a separate install. In practice, if you split the work as "in the customer environment capture an ETL file with the OS-standard wpr.exe only, take it home, and analyze it in WPA on your own machine", you can investigate system-wide performance even at a site where you cannot add software.
Why is it slow when Task Manager shows CPU to spare? What can I see in WPA?
When CPU usage is low and it is still slow, the work is not unable to use the CPU — it is stopped "waiting for something". Lock contention, waiting for synchronous I/O to complete, and waiting for another process to respond are typical. Task Manager only shows the result, usage; WPA's CPU Usage (Precise) shows, from a per-context-switch record, where the thread started waiting (NewThreadStack), how long it waited (Waits), and who woke it (ReadyingProcess, ReadyThreadStack). By walking the party that made it wait, you can identify "the culprit of the slowness" down to the function.
How long should I capture a trace? Won't the file become huge?
If you can reproduce the issue, the baseline is to start just before reproduction, stop just after, and keep it within a few minutes. WPR's default is Memory mode, which records to an in-memory circular buffer; older events are overwritten, so it is suited to waiting for an issue whose timing you do not know. File mode, with -filemode, keeps everything in a continuous file, but the only ceiling is free disk space, and a file that is too large can become unanalyzable in WPA. Use Memory mode for a long wait, File mode for a short, reliable reproduction.
How should I choose between PerfView and WPA?
Both tools handle ETW traces, but their strengths differ. PerfView has a deep understanding of the .NET runtime and is strong at managed-app-specific investigation such as GC, allocation, and JIT. WPA is suited to reading OS-wide CPU, disk, file I/O, power, and the like across graphs and tables, and is the first choice when "it is not a specific app but the whole PC that is slow", "multiple processes are involved", or "something outside the app (antivirus, a driver, another process) is suspected". A rule of thumb is PerfView for slowness of your own .NET app alone, WPR/WPA for slowness of the whole system.
Is it all right to run WPR in a customer's production environment?
A short capture is common in practice, but it is not unconditionally safe. ETW is lightweight, but recording a large volume of events with stacks does consume a certain amount of CPU and memory. Fold considerations such as starting just before the reproduction step and stopping just after, keeping the capture within a few minutes, and running it at a time with little business impact into the same approval process as any ordinary change. Also, an ETL file contains internal system information such as process names, file paths, and executable information, so you should decide in advance how it will be handled if it leaves the company (minimization, retention period, deletion).

Author Profile

Profile page for the article author.

Go Komura

Representative of KomuraSoft LLC

Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.

Back to the Blog