我有一個算法,用C編寫,它處理一對二維數組(例如,大小爲Y x X)以產生另一個相同大小的二維數組。所有三個數組都包含32位浮點數並且具有相同的大小Y x X,其中Y可能是幾十,但X是一百萬左右。如何緩解轉置陣列訪問順序對性能的影響?
不幸的是:
- 所有陣列必須是row-major order(掃描通過X訪問連續的存儲器),
- 算法需要最內層循環掃描整個Y維度。
也許不出所料,以非連續方式訪問數據相對較慢。所以...
我能做些什麼來緩解非連續內存訪問對性能的影響?
(特別注意這是一個long shot,但我試過的預取指令的各種圖案在即將到來的欄目帶來,但都無濟於事)
以下(更新)代碼演示此問題:
#include <stdio.h>
#include <stdlib.h>
#define NX 1000000
#define NY 30
int main() {
float *a = malloc(sizeof(float) * NY * NX);
float *b = malloc(sizeof(float) * NY * NX);
float *c = malloc(sizeof(float) * NY * NX);
size_t y, x, offset;
float v;
for(x=0; x<NX; x++) {
v = 1;
for(y=0; y<NY; y++) {
offset = x + NX * y;
if(a[offset] < 0) {
v = 2;
}
c[offset] = v * b[offset];
}
}
free(a);
free(b);
free(c);
}
在配備E5520 CPU @ 2.27 GHz的測試機器上,即使只讀取〜220 MB並寫入〜110 MB,執行時間也需要1秒。
如果你可以將你的數據分解成尺寸合理的chuncks/blocks,使它可以共存於緩存中的雙重循環中,這可以提供幫助。這當然取決於你的算法(和問題)如何合併結果塊。在上面的添加這樣簡單的事情中,這不需要進一步的工作。 –
取決於你的循環體是什麼,迭代之間有什麼依賴關係。切換循環順序將是最佳選擇,但可能需要一些輔助存儲。阻塞/平鋪算法也是一個不錯的選擇,但是在給定機器的特定參數的情況下,您必須小心瓷磚尺寸(例如,在3MB緩存中效果良好的瓷磚尺寸可能無法很好地發揮作用在具有512K緩存的系統上運行)。我想我們需要更多關於你的實際算法的信息,而不是上面的玩具測試用例... – twalberg
我已經更新了示例代碼,試圖說明處理的列順序性質。 –