# perf Metrics **Key performance metrics** derived from hardware counters reveal what the CPU is doing and where it's spending time. **Instructions per cycle (IPC)** is the most important metric—it tells you how efficiently the CPU is using its execution pipeline. Calculate it as `instructions / cycles`. ``` IPC = 2.5 → CPU is executing 2.5 instructions per cycle (good utilization) IPC = 1.0 → CPU is executing 1 instruction per cycle (moderate stall) IPC = 0.5 → CPU is executing 0.5 instructions per cycle (significant stall) ``` Modern superscalar CPUs can retire 3-4 instructions per cycle at theoretical peak (depends on architecture). An IPC above 2 is good; below 1 almost always indicates memory stalls (CPU is waiting for DRAM). **Cache miss rate** shows the fraction of cache accesses that missed and had to fetch from memory. Calculate as `cache-misses / cache-references`: ``` 1% miss rate → excellent (cache is working well) 5% miss rate → acceptable (some misses but mostly cache hits) 30% miss rate → poor (CPU is waiting for memory frequently) ``` High cache miss rates combined with low IPC confirms memory-bound execution. Typical optimizations: improve data locality, prefetch strategically, or increase compute per loaded cacheline. **Branch misprediction rate** is `branch-misses / branches`. Modern CPUs have sophisticated branch predictors but they can still miss: ``` 2% miss rate → typical for well-predicted code 10% miss rate → irregular branch patterns, consider restructuring ``` Data-dependent branches are hard to predict. Unpredictable branches cause pipeline flushes and stalls. Optimizations: branch on frequently-taken paths, use conditional moves, or restructure to avoid data-dependent branches. **Stalled cycles** (frontend vs backend) reveal where the CPU is waiting: ``` stalled-cycles-frontend CPU waiting for instruction fetch (rare) stalled-cycles-backend CPU waiting for execution (memory, data hazards) ``` High backend stalls with low IPC usually means memory waits. High frontend stalls indicate instruction fetch bottlenecks (usually from branch mispredictions or instruction cache misses). **Cycles per instruction (CPI)** is the inverse of IPC—sometimes more intuitive to reason about: ``` CPI = cycles / instructions = 1 / IPC ``` CPI of 2 means it takes 2 cycles per instruction on average (equivalent to IPC of 0.5). **System utilization** shows CPU efficiency. For a single-threaded program: ``` task-clock (ms) / wall-clock time (ms) = CPUs utilized ``` If your program runs for 4 seconds and task-clock is 4000ms, that's 1 CPU utilized (100%). If it's 1000ms, that's 0.25 CPUs (25%)—the program is not keeping the CPU busy (waiting on I/O or synchronization). **Quick profiling checklist:** 1. Is IPC low (< 1)? Memory bound—optimize memory access. 2. Is cache miss rate high (> 10%)? Memory access pattern issue—improve locality. 3. Is branch misprediction rate high (> 5%)? Branch prediction issue—restructure loops. 4. Is CPU utilization low (< 75%)? I/O bound or synchronization—check for waits.