beginner
The List That Got Slower Than Its Complexity
Read the counters before the options. Nothing here is labelled with the answer.
The report
We swapped a vector for a linked list so insertions in the middle would be cheap. Insertions did get cheaper. But the nightly aggregation pass, which just walks the whole thing and sums a field, went from about 40 ms to nearly 400 ms on the same data. Nobody changed the loop.
The aggregation pass, unchanged across both versions
// before: contiguous storage
total = 0
for i in 0 .. n-1:
total += items[i].value
// after: node-per-element, allocated as records arrived
total = 0
node = head
while node != null:
total += node.value
node = node.nextCountersSIMULATED
| instructions | ≈ 1.02× the vector version | Almost exactly the same number of instructions is retired in both versions. |
| cycles | ≈ 9.4× the vector version | The same instruction count takes roughly nine times as many cycles. |
| IPC | 0.11 (vector version: 1.02) | Very few instructions retire per cycle compared with the vector version. |
| L1-dcache-load-misses | 31.8% of loads (vector: 2.1%) | Roughly one load in three misses the first-level cache. |
| LLC-load-misses | 24.6% of loads (vector: 0.4%) | Most of the L1 misses go all the way to memory. |
| branch-misses | 0.4% of branches | Branch prediction is essentially perfect in both versions. |
What is the hardware doing?