2012-06-13 24 views
1

我一直在使用一段密集的內存綁定代碼。我試圖通過手動實現緩存阻塞,sw預取,循環展開等在單個內核中對其進行優化。儘管緩存阻塞可顯着提高性能。但是,當我介紹循環展開時,我得到了巨大的性能下降。循環展開對內存綁定數據的影響

我編譯與英特爾ICC與編譯器標誌-02和我所有的測試用例-ipo。

我的代碼是與此類似(3D 25點模版):

void stencil_baseline (double *V, double *U, int dx, int dy, int dz, double c0, double c1,  double c2, double c3, double c4) 
    { 
    int i, j, k; 

    for (k = 4; k < dz-4; k++) 
    { 
    for (j = 4; j < dy-4; j++) 
    { 
     //x-direction 
      for (i = 4; i < dx-4; i++) 
     { 
      U[k*dy*dx+j*dx+i] = (c0 * (V[k*dy*dx+j*dx+i]) //center 
       + c1 * (V[k*dy*dx+j*dx+(i-1)] + V[k*dy*dx+j*dx+(i+1)])     
       + c2 * (V[k*dy*dx+j*dx+(i-2)] + V[k*dy*dx+j*dx+(i+2)])  
       + c3 * (V[k*dy*dx+j*dx+(i-3)] + V[k*dy*dx+j*dx+(i+3)]) 
       + c4 * (V[k*dy*dx+j*dx+(i-4)] + V[k*dy*dx+j*dx+(i+4)])); 

     } 

     //y-direction 
     for (i = 4; i < dx-4; i++) 
     { 
      U[k*dy*dx+j*dx+i] += (c1 * (V[k*dy*dx+(j-1)*dx+i] + V[k*dy*dx+(j+1)*dx+i]) 
       + c2 * (V[k*dy*dx+(j-2)*dx+i] + V[k*dy*dx+(j+2)*dx+i]) 
       + c3 * (V[k*dy*dx+(j-3)*dx+i] + V[k*dy*dx+(j+3)*dx+i]) 
       + c4 * (V[k*dy*dx+(j-4)*dx+i] + V[k*dy*dx+(j+4)*dx+i])); 
     } 

     //z-direction 
     for (i = 4; i < dx-4; i++) 
     { 
      U[k*dy*dx+j*dx+i] += (c1 * (V[(k-1)*dy*dx+j*dx+i] + V[(k+1)*dy*dx+j*dx+i]) 
       + c2 * (V[(k-2)*dy*dx+j*dx+i] + V[(k+2)*dy*dx+j*dx+i]) 
       + c3 * (V[(k-3)*dy*dx+j*dx+i] + V[(k+3)*dy*dx+j*dx+i]) 
       + c4 * (V[(k-4)*dy*dx+j*dx+i] + V[(k+4)*dy*dx+j*dx+i])); 

     } 

    } 
    } 

} 

當我做循環展開上最內層循環(尺寸i)和在方向x,y展開,Z分別由UNROLL因子分別爲2,4,8,在所有9種情況下,我的性能都有所下降,即在方向x上展開2,在方向y上展開2,在方向z上展開2,在方向x上展開4 ...等。 但是當我在最外層循環(維k)上循環展開係數8(也是)時,我得到的性能改進甚至比緩存阻塞更好。

我甚至嘗試剖析我的代碼以英特爾VTune。這似乎是主要由於1.LLC Miss和2. LLC負載未命中由遠程DRAM服務的瓶頸。

我無法理解爲什麼在給性能下降而展開的最外層,最慢的維度獲取的性能提升展開的最裏面最快的循環。然而,在後一種情況下的這種改進是當我使用-O2和-ipo編譯icc時。

我不知道如何解釋這些統計數據。有人可以幫助闡明這一點。

+0

另一方面:大概編譯器正在優化k * dy * dx爲temp? –

+0

@Mitch小麥:我使用通用的子表達式消除,在我的原始代碼中考慮到k * dx * dy和j * dx。這是更多的示例代碼 – Anusuya

+0

你可以使用SSE指令來計算一些嗎?從快速瀏覽它看起來可以... – sarnold

回答

1

這有力地表明,你被展開,這是典型的導致指令高速緩存未命中。在現代硬件時代,展開不再自動意味着更快的代碼。如果每個內部循環都適合緩存行,那麼您將獲得更好的性能。

您可以手動展開以限制生成的代碼的大小,但這需要檢查生成的機器語言指令及其位置,以確保您的循環位於單個高速緩存行中。高速緩存行通常爲64個字節長,並在64字節邊界上對齊。

外環不具有相同的效果。無論展開級別如何,它們都可能位於指令高速緩存之外。以較少的分支展開這些結果,這就是爲什麼你獲得更好的表現。

「遠程DRAM服務加載未命中」意味着你分配一個NUMA節點上的內存,但現在你是在其他運行。基於NUMA設置進程或線程關聯是答案。

遠程DRAM花費差不多,只要對我已經使用了Intel機器讀取本地DRAM的兩倍。