2013-12-08 29 views
4

我有以下功能:對齊在一個週期內存訪問

void ikj(float (*a)[N], float (*b)[N], float (*c)[N], int n) { 

    int i, j, k; 
    float r; 

    papi_start(); 

    for (i = 0; i < n; i++) { 
     for (k = 0; k < n; k++) { 

      r = a[i][k]; 

      for (j = 0; j < n; j++) 
       c[i][j] += r * b[k][j]; 

     } 
    } 

    papi_stop(); 

} 

而且我使用PAPI數我有多少負載和存儲有papi_start()papi_stop()結果我已經有以下之間:

載荷(使用PAPI_LD_INS):

32 26781 
64 205053 
128 1606077 
256 12714815 
512 101189551 
1024 807406950 
2048 6450848188 

商店(使用PAPI_SR_INS):

32 8290 
64 65698 
128 524578 
256 4194850 
512 33555490 
1024 268437701 
2048 2147487778 

其中第一個值是N的大小,第二個值是指令的數目。我正在編譯與O3和我的緩存大小L1 = 32KB×2(指令和數據,8路)和L2 = 1024KB(4路)(共享2個核心)..我的CPU是英特爾T3200和SSE3 ..

我知道,O3優化代碼,所以它會使用預取之間的其他功能,因爲我加載連續的地址和我的緩存有一個64字節的行大小我加載16立即浮動,但我的計算沒有達到這個值,所以任何人都可以向我解釋這一點?

編輯:這是我的彙編文件,遺憾的只是把他們在這裏,但我從來沒有與裝配工作,我不能真正理解它的任何:

http://dl.dropboxusercontent.com/u/878621/mmc.s http://dl.dropboxusercontent.com/u/878621/mmc_asm.s

謝謝!

+0

當我們沒有告訴我們你的'n'是什麼(等等)時,我們很難猜測。 –

+1

你看過編譯器輸出以查看編譯器已分配給寄存器的內容嗎?寄存器訪問不計入內存訪問。另外,編譯器可能已經對代碼進行了向量化,因此它使用單個加載或存儲執行多個操作。 –

+0

是的,我做了,它的輸出值的第一列,它從32到2048 .. @JerryCoffin –

回答

3

看着商店,你得到的數字非常接近N**3/4。我們期望它顯然是O(N ** 3)。

這表明4個浮點寫入被合併到PAPI_SR_INS正在測量的任何一箇中。看着它,或者你正在計算16字節寫入的數量。

類似地,負載的數量大致爲3/4 N**3。占主導地位的術語應該是來自最內層循環內的b和c的負載,這將是每次迭代2次讀取。說實話,我無法理解這一點。

如果您不確切地知道您要測量的是什麼,並且您沒有將其與生成的代碼關聯起來,則很難預測測量結果。

編輯:數字似乎與執行的加載和存儲指令相關,但與L1,L2等事務或未命中的數量無關 - 因此不太可能與實際性能相關。是不是需要更好的數字擔心的時間?鑑於現代CPU架構的複雜性,我相信任何一天的測量都超過預測。

+2

快速瀏覽彙編文件表明循環得到了矢量化,一次處理四個元素。我猜Jose需要學習一點x86程序集。 –

+0

@JoeZ:是的,這解釋了商店。負載計數並不合理(我也希望它是1/2 * N^3)。 –

+0

那麼,有'a [i] [k]'的外部循環負載會發生N^2次,並且根據哪個循環矢量化,它可能需要4個負載。 4 * N^2 + N^3/2開始接近。我承認我沒有仔細閱讀過大會。 –