The Uop Cache's Fetch-Address-Based Set Indexing: Why Two Loops at Different Addresses Never Conflict

2026-09-03

The uop cache (Intel calls it the DSB — Decoded Stream Buffer) is a set-associative structure, and like any cache it needs a way to map addresses to sets. The choice Intel made is subtle and has real performance consequences: the set index is derived from the fetch address of the 32-byte instruction window, not from the individual uop's logical address or its position within a basic block.

On Skylake through Alder Lake, the DSB has 32 sets, 8 ways per set, and holds up to 6 uops per line. The set index comes from bits [9:5] of the fetch address — meaning any two 32-byte code windows whose linear addresses differ by a multiple of 1024 bytes (32 sets × 32 bytes) will land in the same set and compete for the same 8 ways.

This produces a counterintuitive result: two hot loops at different addresses almost never conflict, because random code layout scatters them across the 32 sets. But aligned code layout — say, functions padded to 1KB boundaries, or a jump table where every entry sits at a 1024-byte offset — can pile every hot fetch window into a single set, exhausting the 8 ways and evicting uops that were about to be re-fetched.

Concrete example: A tight inner loop of 96 bytes (three 32-byte fetch windows) normally occupies 3 sets, 1 way each — trivial to fit. But if a linker aligns hot functions to 1024-byte boundaries, and the loop body sits alongside 7 other similarly-aligned hot code paths, all 8 ways in that set fill up. Adding a 9th hot path evicts one — and if that eviction hits your loop, you fall back to legacy decode at ~4 uops/cycle instead of DSB's 6 uops/cycle. On a workload where the front-end was already the bottleneck, this is a measurable 30%+ throughput loss.

Rule of thumb: If perf stat shows idq.dsb_uops dropping while idq.mite_uops rises during a specific phase, and your linker aggressively aligns functions to power-of-two boundaries ≥1KB, suspect DSB set conflicts. The fix is often as simple as passing -falign-functions=32 instead of -falign-functions=1024 to your compiler.

The deeper lesson: DSB capacity in uops (about 1536 on Skylake) tells you nothing about whether your code fits. Set conflicts can make a 96-byte loop uncacheable while a 4KB loop with scattered addresses fits comfortably. Effective DSB capacity is not a number — it's a distribution.

See it in action: Check out CompTIA A+ Core 1 (220-1201) Full Certification Course by PowerCert Animated Videos to see this theory applied.
Key Takeaway: The uop cache indexes by 32-byte fetch window address, so aligned code layouts concentrate hot paths into a few sets and cause conflict evictions long before total uop capacity is reached.

All newsletters