2016-08-04 65 views
0

我想實現與APARAPI並行的Entropy函數。 在那個函數中,我需要計算向量中的不同鍵,但它無法正確執行。用Aparapi對向量中的不同值進行計數

假設我們只有3個不同的值。 這裏是我的代碼:

final int[] V = new int[1024]; 
// Initialization for V values 
final int[] count = new int[3]; 
Kernel kernel = new Kernel(){ 
    @Override 
    public void run(){ 
     int gid = getGlobalId(); 
     count[V[gid]]++; 
    } 
}; 
kernel.execute(Range.create(V.length)); 
kernel.dispose(); 

運行該代碼段後,當我打印計數[]值它給了我1,1,1。 看來count[V[gid]]++對於每個V [gid]只執行一次。

謝謝。

+0

寫作競賽條件。你需要原子增量函數。 –

回答

0

所以這裏是問題所在。 ++運算符實際上是三個操作之一:讀取當前值,增加它,寫入新值。在Aparapi中,您可能會同時運行1024個GPU線程。這意味着它們將讀取值,可能在所有值爲0的同時讀取值,然後將其增加到1,然後所有1024個線程將寫入1.因此,它按預期行事。

你要做的就是稱爲Map-reduce功能。你只是跳過很多步驟。你需要記住Aparapi是一個沒有線程安全的系統,所以你必須編寫你的算法來適應它。這就是Map-Reduce進來的地方,這裏是如何做到的。我只是寫了它,並將其添加到它的新家Aparapi存儲庫,詳細信息如下。

int size = 1024; 
final int count = 3; 
final int[] V = new int[size]; 

//lets fill in V randomly... 
for (int i = 0; i < size; i++) { 
    //random number either 0, 1, or 2 
    V[i] = (int) (Math.random() * 3); 
} 

//this will hold our values between the phases. 
int[][] totals = new int[count][size]; 

/////////////// 
// MAP PHASE // 
/////////////// 
final int[][] kernelTotals = totals; 
Kernel mapKernel = new Kernel() { 
    @Override 
    public void run() { 
     int gid = getGlobalId(); 
     int value = V[gid]; 
     for(int index = 0; index < count; index++) { 
      if (value == index) 
       kernelTotals[index][gid] = 1; 
     } 
    } 
}; 
mapKernel.execute(Range.create(size)); 
mapKernel.dispose(); 
totals = kernelTotals; 

////////////////// 
// REDUCE PHASE // 
////////////////// 
while (size > 1) { 
    int nextSize = size/2; 
    final int[][] currentTotals = totals; 
    final int[][] nextTotals = new int[count][nextSize]; 
    Kernel reduceKernel = new Kernel() { 
     @Override 
     public void run() { 
      int gid = getGlobalId(); 
      for(int index = 0; index < count; index++) { 
       nextTotals[index][gid] = currentTotals[index][gid * 2] + currentTotals[index][gid * 2 + 1]; 
      } 
     } 
    }; 
    reduceKernel.execute(Range.create(nextSize)); 
    reduceKernel.dispose(); 

    totals = nextTotals; 
    size = nextSize; 
} 
assert size == 1; 

///////////////////////////// 
// Done, just print it out // 
///////////////////////////// 
int[] results = new int[3]; 
results[0] = totals[0][0]; 
results[1] = totals[1][0]; 
results[2] = totals[2][0]; 

System.out.println(Arrays.toString(results)); 

請記住,雖然它可能看起來效率低下,它實際上在很大數量上工作得很好。這個算法很好用

size = 1048576. 

在新的尺寸下,我的系統在大約一秒鐘內計算出以下結果。

[349602, 349698, 349276] 

最後要注意,你可能要考慮在aparapi.com移動到更多的活動項目。它包含多個修補程序以及上面鏈接的較舊庫的許多額外功能和性能增強功能。它也在maven中心,有大約十幾個版本。所以它更容易使用。我只是在這個答案中寫了代碼,但決定在新的Aparapi存儲庫的示例部分中使用它,您可以在the following link in the new Aparapi repository處找到它。

相關問題