Performance Engineering

cycles, instructions and IPC

/ IPC: eye-pee-SEE /

A CPU runs to the beat of a clock, and each tick is a cycle — a 3 GHz chip ticks three billion times a second. Two natural questions about a piece of code are: how many of those ticks did it take (cycles), and how many machine instructions did it complete (instructions)? Divide one by the other and you get a single, deeply informative number: instructions per cycle, or IPC.

IPC is just retired instructions divided by elapsed cycles, both read straight from the PMU. 'Retired' means instructions that actually completed and counted, not speculative ones that got thrown away. Modern CPUs are superscalar, meaning they can complete more than one instruction per cycle, so IPC of 2, 3, or even 4 is achievable on good code; an IPC well below 1 means the CPU spent most cycles STALLED — waiting on memory, on a branch it mispredicted, or on a dependency chain — rather than doing work. The reciprocal, cycles per instruction (CPI), says the same thing inverted. The crucial insight is that total time = instructions x CPI / frequency, which splits performance into three independent levers: do fewer instructions (better algorithm or less work), lower the CPI (remove stalls so each instruction costs fewer cycles), or raise the frequency (mostly the hardware's job). Two programs can run the same number of instructions yet differ 5x in time purely because one stalls and the other does not.

It matters because IPC tells you WHICH lever to pull. High IPC and still too slow? You are simply doing too much work — reach for a better algorithm, because the hardware is already busy every cycle. Low IPC? The CPU is starved — chase the stalls, usually cache misses or branch mispredictions. The honest caveat: IPC is not a goal in itself. Replacing four cheap instructions with one expensive division can RAISE IPC while making the code slower, and a tighter algorithm that does far less work can show a lower IPC yet finish sooner. Optimize for total time; use IPC to understand WHY the time is what it is.

Loop A: 1.0e9 instructions, 0.5e9 cycles -> IPC 2.0 (busy, compute-bound) Loop B: 1.0e9 instructions, 4.0e9 cycles -> IPC 0.25 (stalled ~mostly on cache misses) Same instruction count, B is 8x slower.

Identical instruction counts, wildly different time: IPC reveals that loop B spends its cycles stalled, not computing.

Higher IPC is not automatically better: a fused or vector instruction does more per slot, and trading several cheap ops for one slow one can raise IPC while slowing the program. Always judge by total time; let IPC explain it.

Also called
instructions per cycleCPI (cycles per instruction)每週期指令數每指令週期數