A book snapshot holds 10 million entries, each a 48 byte struct of price, size, order id, timestamp and two flags. A pass sums the sizes only. Compare an array of structs layout with a struct of arrays layout, giving the bytes moved in each and the expected speed ratio.

A book snapshot holds 10 million entries, each a 48 byte struct of price, size, order id, timestamp and two flags. A pass sums the sizes only. Compare an array of structs layout with a struct of arrays layout, giving the bytes moved in each and the expected speed ratio.

Approach: Count how many bytes each layout brings into cache per element used, then compare that with the number of bytes the loop actually consumes.

The array of structs moves 480 MB because each 64 byte line delivers 48 bytes of which only the 8 byte size field is read, while the struct of arrays moves 80 MB and uses every byte fetched, so the ratio is about 6 times before vectorisation and more after it. In the array of structs the useful fraction is 8 over 48, so the loop is memory bandwidth bound on data it discards, and the stride defeats nothing in the prefetcher yet wastes most of what it fetches. In the struct of arrays the sizes are contiguous, the hardware prefetcher tracks the stride perfectly, and the compiler emits one wide instruction per four elements. The cost of the change is that a pass touching every field of one entry now takes six cache line misses instead of one, so the layout should follow the dominant access pattern, and grouping only the hot fields together is the usual compromise.

Follow-up: What does the same count give when the pass reads price and size together and those two fields are adjacent in the struct?

Key concepts: array of structs, struct of arrays, cache line, memory bandwidth, prefetcher.