關於 cache 衝突模式(cache conflict patterns),考慮下列 C 程式碼在一個具有 32 KB direct-mapped L1 data cache、64-byte cache lines、4-byte 整數的系統上執行:
int A[8192], B[8192]; // 陣列連續配置,且cache-line對齊
for (int i = 0; i < 8192; i++) {
A[i] = A[i] + B[i];
}
請選出正確的敘述。
參考答案與解析
答案 (A)(B)。快取規格:32KB、direct-mapped、64B/line,故有512個line(set);A、B兩陣列各32KB,B緊接在A之後,兩者位址恰好相差32KB(等於整個cache大小的整數倍),因此對任意i,A[i]與B[i]永遠映射到「完全相同」的cache line。(A)對:迴圈中每次迭代讀A[i]、讀B[i]、寫回A[i],三者都指向同一個line;讀A[i]載入A的區塊後,緊接著讀B[i]時該line已被A佔用,必定miss並把A逐出換成B,寫回A[i]時該line又被換回A,導致下一輪讀B[i+1]時line內仍是A的資料、再次miss——形成典型的conflict thrashing,B[i]的每一次存取都無法受益於空間局部性,全部miss。(B)對:改成2-way set-associative、總容量仍32KB時,set數變成256個,A[i]與B[i]仍映射到同一個set,但現在一個set有2個way,可以同時容納A的line與B的line而不必互相驅逐;由於整個迴圈只對i做一次循序掃描(不是重複掃描同一段資料),同一個set在陣列wraparound後才會被同一組(A,B)以外的資料重新使用,時間上與前一次使用完全錯開、不會產生額外衝突,因此除了一開始的compulsory miss外,2-way確實可以完全消除這裡的conflict miss。(C)錯:padding 8192個整數=32KB,讓A、B位址差變成64KB,仍是cache大小(32KB)的整數倍,映射到的line完全沒變,衝突沒有被解決(要消除衝突,padding的位移不能是cache大小的整數倍)。(D)錯:loop interchange是用來改善巢狀(2D以上)迴圈的存取順序,這裡只有單層1D迴圈,無法套用。(E)錯:prefetching無法消除程式一開始的compulsory miss,而且在direct-mapped、A/B仍互相衝突映射的前提下,預取進來的區塊一樣會被另一個陣列的存取立刻驅逐,無法消除全部cache miss。