循環優化與多面體模型

循環通常是數據並行應用的最密集計算段,因此循環優化直接影響性能。當面對嵌套循環時,分配給線程的計算粒度將直接影響性能。循環轉換如Fission(循環裂變)與Fusion(循環融合)的嵌套式循環可促使並行化,並提高工作效率。

本文就幾種循環優化的方法與多面體模型的調度進行簡要闡述(因爲LZ已經被這些循環優化搞得痛不欲生了)。


Loop fusion

顧名思義,該變換令循環進行了融合。如圖所示,原始代碼是兩個for循環,變化之後,對兩個循環中 i、j 相同的範圍進行了融合。
在這裏插入圖片描述
我們爲了把該變換映射或者說調度到多面體模型中去,需要產生調度樹。

舉例如下:
在這裏插入圖片描述
有這樣一段用TC寫的代碼,語句S、T分別爲循環語句。其融合操作表述如下:
在這裏插入圖片描述
Band 操作將S、T所對應的迭代向量進行了融合。


Loop tiling

Loop tiling/blocking 的意思是分塊,可以將循環的迭代空間劃分爲更小的塊,以幫助確保循環中使用的數據在重用之前一直保存在緩存中。循環迭代空間的劃分導致將大數組劃分爲更小的塊,從而將被訪問的數組元素匹配到緩存大小中,增強緩存重用,消除緩存大小需求。

平常的循環:

for(i=0; i<N; ++i){
  ...
}

變換後的循環,擁有一個全新的 block 大小B:

for(j=0; j<N; j+=B){
  for(i=j; i<min(N, j+B); ++i){
    ....
  }
}

更具體的例子:
在這裏插入圖片描述
下面是一個矩陣向量乘法的例子。有三個數組,每個數組有100個元素。代碼沒有將數組劃分爲更小的大小。

  int i, j, a[100][100], b[100], c[100];
  int n = 100;
  for (i = 0; i < n; i++) {
    c[i] = 0;
    for (j = 0; j < n; j++) {
      c[i] = c[i] + a[i][j] * b[j];
    }
  }

當我們應用循環分塊,使用2 * 2塊,代碼變爲:

  int i, j, x, y, a[100][100], b[100], c[100];
  int n = 100;
  for (i = 0; i < n; i += 2) {
    c[i] = 0;
    c[i + 1] = 0;
    for (j = 0; j < n; j += 2) {
      for (x = i; x < min(i + 2, n); x++) {
        for (y = j; y < min(j + 2, n); y++) {
          c[x] = c[x] + a[x][y] * b[y];
        }
      }
    }
  }

原來的循環迭代空間n×n。數組的訪問塊(i, j)也是n×n。當n過大和機器的緩存容量太小,訪問數組元素的循環迭代(例如,i = 1, j = 1到n)可能交叉的高速緩存線路,導致緩存丟失。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章