# PerfMon for a Windows web server: the counters that explain a slow site

> Use Performance Monitor and data collector sets to watch CPU, memory, disk, IIS app pools and connections, and read the result without superstition.

**Tested on**

- Build: 26100.33650
- Edition: Standard / Datacenter
- Architecture: x64
- Evidence: E1
- Verified: 2026-10-29

## The short answer

Four resources decide most web-server performance:

1. **CPU** — steal vs. your app.
2. **Memory** — working set, paging, app-pool private bytes.
3. **Disk** — queue length and latency on the data/log volume.
4. **Network/connections** — current connections, requests/sec, queue.

Watch the app pool and the whole host; a healthy host can still have one bad pool.

## Counters

```text
Processor(_Total)\% Processor Time
Memory\Available MBytes
Memory\Pages/sec
PhysicalDisk(_Total)\Avg. Disk sec/Read
PhysicalDisk(_Total)\Avg. Disk sec/Write
PhysicalDisk(_Total)\Current Disk Queue Length
Web Service(_Total)\Current Connections
Web Service(_Total)\Get Requests/sec
APP_POOL_WAS(*)\Current Application Pool State
Process(*)\Private Bytes
Process(*)\% Processor Time
```

Add `HTTP Service Request Queues(*)\CurrentQueueSize` when requests queue before the app.

## Collect

Interactive: `perfmon` → Performance Monitor → add counters.

Data collector set (better for incidents): create a User Defined set, log to a file, run for 24h, restart on schedule. Keep the `.blg` off the system drive.

PowerShell snapshot:

```powershell
Get-Counter -Counter '\Processor(_Total)\% Processor Time','\Memory\Available MBytes' -SampleInterval 2 -MaxSamples 5
Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
  Sort-Object PercentProcessorTime -Descending | Select-Object -First 10 Name,PercentProcessorTime,WorkingSetPrivate
```

## Read it correctly

- **CPU 100%** — is it `w3wp`, `php-cgi`, `node`, or antivirus? Look at the process, not just the total.
- **Available MBytes low + Pages/sec high** — real memory pressure; find the leaking pool.
- **Disk queue > 2 × spindles (or high latency)** — storage bottleneck; check logging/AV scans on the data volume.
- **Current Connections high + low CPU** — slow clients or keep-alive exhaustion; check timeouts.
- **Queue growing** — app can’t keep up; scale/optimize or the pool is recycling.

> **Caution: One sample is not a measurement**
>
> A single spike is noise. Collect at least a full business cycle, correlate with deploys/traffic, and keep the counter log with the incident.

## Baseline

Record a normal-week baseline: CPU/memory/disk/connections per site. Without a baseline, “high CPU” is an opinion.

## Lab boundary

E1. The lab served IIS/Nginx but did not run a PerfMon collector or load test. Counters and the reading guide are the production method for Server 2025.

## Sources

- [Microsoft Learn — Performance Monitor](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/perfmon)
- [Microsoft Learn — IIS performance counters](https://learn.microsoft.com/en-us/iis/troubleshoot/performance-issues/)
- [Microsoft Learn — Get-Counter](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.diagnostics/get-counter)

---

Source: https://windows.homes/en/server/ops/perfmon/
