假設高速緩存行的寬度爲64字節,並且我有兩個數組a
和b
,它們填充高速緩存行並且也與高速緩存行對齊。我們還假設這兩個數組都在L1緩存中,所以當我從他們那裏讀取時,我沒有發現緩存未命中。最後使用的高速緩存行與不同的高速緩存行
float a[16]; //64 byte aligned e.g. with __attribute__((aligned (64)))
float b[16]; //64 byte aligned
我讀a[0]
。我的問題是現在閱讀a[1]
比閱讀b[0]
更快? 換句話說,從上次使用的緩存行讀取速度更快嗎?
設置是否重要?現在假設我有一個32位的L1數據緩存,它是4路的。因此,如果a
和b
相距8192個字節,它們最終會在同一組中。這會改變我的問題的答案嗎?
另一種問我問題的方法是(我真正關心的)是閱讀一個矩陣。
換句話說,假設矩陣M
適合L1高速緩存並且64字節對齊並且已經在L1高速緩存中,這兩個代碼選項中的哪一個將更有效。
float M[16][16]; //64 byte aligned
版本1:
for(int i=0; i<16; i++) {
for(int j=0; j<16; j++) {
x += M[i][j];
}
}
版本2:
for(int i=0; i<16; i++) {
for(int j=0; j<16; j++) {
x += M[j][i];
}
}
編輯:爲了更清楚些,由於SSE/AVX讓我們假設我從a
讀前八個值與AVX一起(例如與_mm256_load_ps()
)。從a
讀取下8個值會比從b
讀取前8個值快(回想a和b已經在緩存中,所以不會有cahce miss)?
編輯::自Intel Core 2和Nehalem以來,我主要對所有處理器感興趣,但我目前正在使用Ivy Bridge處理器並計劃儘快使用Haswell。
這是一個很好的答案。我意識到關鍵步驟的問題。對我來說唯一的一件事(我應該在我的問題中更清楚)是L2中的效果。我使用的瓷磚尺寸形成了適合於L2而不是L1的GEMM代碼(我可以將它們製作成任何尺寸,但是我發現使它們適合L2可以獲得最佳效果)。所以我想我仍然對當矩陣適合L2而不是L1時會發生什麼感到困惑。多級緩存很複雜。 –
大多數現代CPU也有內存消歧,所以即使存在部分匹配,完整的存儲/加載別名也不會造成瓶頸,您可以推測重新安排它是安全的。 – Leeor