Windows 11 Performance Counters Cheat Sheet

Sidebar

Operating Systems · Windows 11 Performance Counters Cheat Sheet

The counter path syntax, the counters worth watching for CPU, disk, network, processes and GPU, and the tools that read and log them (Performance Monitor, Resource Monitor, Get-Counter, typeperf). Every counter path below returned values on the PC this was written on (Windows 11 Pro, build 26300), as a normal user, and Get-Counter, Export-Counter and typeperf -o were run. The thresholds are common rules of thumb, not Microsoft limits, and are marked as such. Memory counters are on the Memory Troubleshooting sheet.

Counter Paths

\Object(instance)\CounterThe syntax: \Processor(_Total)\% Processor Time. (*) means every instance
\\PCNAME\Object\CounterAdd a computer name to read another PC (needs remote access rights)
_TotalThe all-instances sum for objects that have one (Processor, Process, PhysicalDisk)
Get-Counter -ListSet *Every counter set (234 here); -ListSet Memory | % Counter lists one set's counters
(Get-Counter -ListSet Process).PathsWithInstancesEvery concrete path, with instances
Localised namesOn a non-English Windows the object and counter names are translated

Reading Them

perfmonPerformance Monitor: add counters (green +), choose graph, histogram or report view
resmonResource Monitor: CPU, Memory, Disk, Network tabs with per-process detail
perfmon /relReliability Monitor (a different tool: stability history)
Task Manager > PerformanceThe summary graphs (see the Task Manager sheet)
Get-CounterOne sample now; -Continuous until Ctrl+C; -SampleInterval 5 -MaxSamples 12 for one minute
typeperfCommand Prompt equivalent: typeperf "\Memory\Available MBytes" -sc 5

CPU

\Processor(_Total)\% Processor TimeBusy share of all logical processors (the classic figure)
\Processor Information(_Total)\% Processor UtilityBusy share scaled by current frequency; Task Manager's CPU graph matches this more closely (my understanding)
\System\Processor Queue LengthThreads waiting for a processor. Sustained values above about 2 per logical processor mean CPU contention (rule of thumb)
\System\Context Switches/secThread switches. Only meaningful compared with a baseline
\Process(name)\% Processor TimeOne process; can exceed 100% on many cores (it sums the cores)
\Processor(_Total)\% Interrupt TimeTime spent on hardware interrupts; persistently high points at a driver or device
\Processor(_Total)\% DPC TimeDeferred procedure calls: also drivers. Same reading

Disk

\PhysicalDisk(_Total)\% Disk TimeHow busy; can pass 100% on fast or parallel devices, so not a measure of saturation
\PhysicalDisk(*)\Avg. Disk sec/ReadAverage read latency in seconds. Sustained above roughly 0.020 (20 ms) feels slow on a spinning disk (rule of thumb); SSDs should be far lower
\PhysicalDisk(*)\Avg. Disk sec/WriteWrite latency, same reading
\PhysicalDisk(*)\Current Disk Queue LengthRequests waiting right now; sustained growth means the disk cannot keep up
\PhysicalDisk(*)\Disk Bytes/secThroughput, read + write
\LogicalDisk(C:)\% Free SpaceSpace left on the volume
(*) instances0 C: style names; map them to drives with Get-Disk, Get-Volume

On this PC the disk counters are worth reading per disk: two USB drives log thousands of device errors (see the Event Viewer sheet), and their latencies are the first thing to check.

Network

\Network Interface(*)\Bytes Total/secThroughput per adapter (three instances active here)
\Network Interface(*)\Output Queue LengthPackets waiting to send; sustained above 2 suggests a bottleneck (rule of thumb)
\Network Interface(*)\Packets Received ErrorsReceive errors; non-zero and rising is a cable, driver or hardware lead
\Network Interface(*)\Current BandwidthThe link speed in bits per second
Instance namesAdapter names have special characters replaced; list with (Get-Counter -ListSet 'Network Interface').PathsWithInstances

Processes, Handles and System

\Process(_Total)\Handle CountSystem-wide open handles (192,314 here)
\Process(_Total)\Thread CountSystem-wide threads
\System\ProcessesNumber of processes
\System\System Up TimeSeconds since boot (counts a fast restart's clock differently)
\Process(name)\Working Set - PrivateOne program's private working set (firefox returned one instance here although it has many processes: the instance names are firefox, firefox#1, …)
\Process(name)\Private BytesOne program's commit
\Paging File(_Total)\% UsagePage file use (see Memory Troubleshooting)

GPU

\GPU Engine(*)\Utilization PercentagePer-engine, per-process use (510 instances here). Sum by process or engine to match Task Manager
\GPU Process Memory(*)\Dedicated UsageDedicated video memory per process (counter exists on current Windows; not checked here)
\GPU Adapter Memory(*)\Dedicated UsagePer adapter (not checked here)
Task Manager > Performance > GPUThe easier view for most checks

Logging to a File

Get-Counter '\Memory\Available MBytes' -SampleInterval 5 -MaxSamples 720 | Export-Counter -Path C:\log\mem.csv -FileFormat csvOne hour at 5-second spacing to CSV (a small version was run here)
typeperf "\Memory\Available MBytes" "\Processor(_Total)\% Processor Time" -si 5 -o C:\log\p.csv -ySeveral counters to CSV; -y overwrites without asking (run here with one counter)
-f BIN / .blgExport-Counter -FileFormat blg writes a binary log Performance Monitor can open
logman create counterA background data collector set; creating one usually needs admin and the Performance Log Users rights (not tested here)
relogConvert or trim a .blg log

For a leak, log every 30–60 seconds for many hours, and note what you were doing (the Memory Troubleshooting sheet explains why short samples mislead).

A baseline beats a threshold
Rules of thumb like 20 ms or queue of 2 are starting points. A number means something only compared with the same PC when it was working: log a quiet hour now, and keep the file.
Rates need two samples
Counters such as % Processor Time, Bytes/sec and Pages/sec are computed between samples; the first sample of a rate counter is zero or meaningless. Get-Counter takes a pair of samples for you.