The Cache Prefetcher's Pollution Problem: Why Aggressive Prefetching Can Make Your Code Slower

2026-06-17

A prefetcher's job is to pull data into cache before you ask for it. Done right, it hides DRAM latency. Done wrong, it evicts data you were about to use to make room for data you'll never touch. That's cache pollution, and it's the dark side of every aggressive prefetcher shipped in the last 20 years.

The mechanism is brutal in its simplicity. Your L2 cache has, say, 1 MB of capacity. A prefetcher detects a stride and starts hauling in lines ahead of the access stream. Each prefetched line takes a slot. If the prefetcher's guess is wrong — or if it runs past the end of the array into unrelated memory — those lines displace useful lines that the program was about to revisit. The next demand load misses, goes to DRAM, and you've paid 200+ cycles for a miss that wouldn't have happened without the prefetcher trying to help.

Concrete example: Consider a hash table lookup inside a loop that streams through a large array. The array access triggers the stride prefetcher to aggressively pull in array lines. Meanwhile, the hash table buckets — small, scattered, hot — get evicted from L2 because the prefetched array lines crowd them out. Profilers show this as a paradox: turning off the hardware prefetcher (via MSR 0x1A4 on Intel) sometimes speeds up code by 10-20% on workloads that mix streaming and random access. Linus famously complained about this on kernel mailing lists when prefetchers polluted the L1 during page zeroing.

How CPUs fight back:

Rule of thumb: A prefetcher pays off when (prefetch_accuracy × DRAM_latency_saved) > (pollution_rate × extra_miss_cost). If accuracy drops below ~50% on a workload with a tight working set, the prefetcher is net-negative. On Skylake, useful prefetch rates below 60% trigger automatic throttling within a few thousand cycles.

This is why benchmark scores on synthetic streaming tests look great but real applications — with their messy mix of random pointer chasing and array walks — see modest gains. The prefetcher is optimizing for the workload it can see, not the one you're actually running.

Key Takeaway: A prefetcher that's wrong half the time isn't neutral — it's actively evicting your hot data, and the cure can be worse than the disease.

All newsletters