2015-06-06 25 views
0

我最近開始使用C++中的OpenCL,並試圖完全理解如何使用2D和3D NDRange。我目前在OpenCL中實現反距離加權,但是我的問題是一般的。使用OpenCL在2D中進行嵌套循環求和

下面是計算權重的串行函數,它由一個嵌套循環組成。

void computeWeights(int nGrids, int nPoints, double *distances, double *weightSum, const double p) { 

    for (int i = 0; i < nGrids; ++i) { 
     double sum = 0; 
     for (int j = 0; j < nPoints; ++j) { 
      double weight = 1/pow(distances[i * nPoints + j], p); 
      distances[i * nPoints + j] = weight; 
      sum += weight; 
     } 
     weightSum[i] = sum; 
    } 
} 

我想是落實使用2D NDRange,第一個是在nGrids和第二過nPoints上述功能。然而,我不明白的是如何處理weightSum [i]的權重總和。我明白,我可能不得不使用並行總和減少,不知何故。

回答

1

當使用2D全局工作空間調度內核時,OpenCL會創建一個工作項目網格。每個工作項目都會執行內核,並在這兩個維度中獲取唯一的ID。

(x,y)|________________________ 
    | (0,0) (0,1) (0,2) ... 
    | (1,0) (1,1) (1,2) 
    | (2,0) (2,1) (2,2) 
    | ... 

工作項目也被分成組,並在這些工作組中獲得唯一的ID。例如。對於規模工作組(2,2):

(x,y)|________________________ 
    | (0,0) (0,1) (0,0) ... 
    | (1,0) (1,1) (1,0) 
    | (0,0) (0,1) (0,0) 
    | ... 

您可以安排工作組,使他們中的每一個執行縮小。

您的SDK可能有樣本,並行減少將是其中之一。

爲了讓您入門,下面是解決您的問題的內核。它是最簡單的形式,適用於每行一個工作組。

// cl::NDRange global(nPoints, nGrids); 
// cl::NDRange local(nPoints, 1); 
// cl::Local data(nPoints * sizeof (double)); 
kernel 
void computeWeights(global double *distances, global double *weightSum, local double *data, double p) 
{ 
    uint nPoints = get_global_size(0); 

    uint j = get_global_id(0); 
    uint i = get_global_id(1); 
    uint lX = get_local_id(0); 

    double weight = 1.0/pow(distances[i * nPoints + j], p); 

    distances[i * nPoints + j] = weight; 

    data[lX] = weight; 

    for (uint d = get_local_size(0) >> 1; d > 0; d >>= 1) 
    { 
     barrier(CLK_LOCAL_MEM_FENCE); 
     if (lX < d) 
      data[lX] += data[lX + d]; 
    } 

    if (lX == 0) 
     weightSum[i] = data[0]; 
} 

的工作項(即,每個工作組)中的每一行計算的權重(以及它們的總和)爲grid i。每個工作項目計算一個重量,將其存儲回distances,並將其加載到本地內存中。然後,每個工作組都會減少本地內存,最終將結果存儲在weightSum中。

+0

非常感謝您的幫助!減少行數有助於我理解實際情況。 我正在努力擴展它,因爲太大的nPoints是不可能創建。每行有多個工作組是一個選項,但是之後我需要將寫入同步到weightSum [i],並且我對使用atomic_add的特殊實現進行雙重操作猶豫不決。 – leadhoarse

+0

同步僅存在於工作組中。原子也只適用於整數類型(至少用於添加)。 解決這個問題的方法如下:對於初學者,每個工作項加載2個距離(雙打),或者更好的加載每個工作項2個double2或double4,以便每個工作項計算4個(或8個)權重。然後,如果'nPoints'仍然過大,則可以減少塊的權重。您將來自每個工作組的總和存儲在全局內存中,而在第二個內核中,您可以像往常一樣減少這些總和。 – pAIgn10