高效能與平行計算

資料局部性(data locality)

假設你照食譜做菜,整個烘焙過程都把麵粉、糖、蛋擺在台面上——你一次又一次伸手去拿,不必跑儲藏室。現在反過來,假設你每用完一樣就立刻收起來,下次再從儲藏室取回。同樣的食譜、同樣的食材,但第二種方式累死人。資料局部性就是一項計算的特質,它決定你的程式像哪一位廚師:它衡量你的程式在伸手去拿遠處之物前,重複使用了多少已在手邊的資料。

它有兩種味道。時間局部性指你在碰過某資料後不久又重用它——像因為每分鐘要打一顆蛋而把蛋留在台面。空間局部性指你碰一個項目後不久就碰它在記憶體中的鄰居——像因為要連著用而整盒蛋一起拿。快取對兩者都給獎賞:時間局部性把熱資料留在快層,空間局部性則兌現「一次快取失誤會一口氣拖上整條 64 位元組的線」這件事,使鄰近的值免費搭便車。局部性好的程式幾乎全從快取執行;局部性差的程式不斷掉回慢記憶體並卡住。

局部性是把「以浮點運算數論」的理論變成機器真實速度的槓桿。BLAS level-3 運算(矩陣對矩陣)每次浮點運算之所以遠比 level-1(向量)運算快,原因就是局部性:矩陣乘法把每個載入的值用上 O(n) 次,而向量加法每個值只用一次。幾乎每一項經典高效能技巧——迴圈重排、分塊與貼磚、依走訪順序儲存陣列、為 SIMD 採用結構陣列佈局——都是提升局部性的招式。你無法減少資料量;你只能安排在每一塊還熱的時候多次重用它。

兩向量相加 c = a + b 的「每浮點運算局部性」很糟:n 次浮點運算卻有 3n 次記憶體存取,每個值只用一次。兩個 n×n 矩陣相乘則把每個載入的值重用約 n 次:搬進快取的同一筆資料會與整列或整行相乘。這就是為何矩陣對矩陣乘法可逼近機器尖峰速度,而向量加法卡在記憶體頻寬速度。

每個載入值的重用次數就是關鍵:向量加法 O(1),矩陣乘法 O(n)。

局部性是存取模式的性質,不是資料本身的性質——同一個陣列,依走訪順序不同,局部性可以極好也可以極差。把矩陣以列優先儲存、卻先行迴圈,就把佈局原本給你的空間局部性全丟掉了。

又称
locality of referencereference locality局部性存取局部性