2016-08-04 58 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处找到它。

相关问题