2016-08-04 5 views
0

Я хочу реализовать функцию Entropy параллельно с APARAPI. в этой функции мне нужно подсчитать разные клавиши в векторе, но он не может выполнить правильно.подсчет различных значений в векторе с 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]]++ выполнить только 1 раз для каждого 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. Он включает в себя несколько исправлений ошибок и множество дополнительных функций и улучшений производительности над старой библиотекой, с которой вы связаны выше. Он также находится в центральной части с примерно дюжиной релизов. поэтому его легче использовать. Я просто написал код в этом ответе, но решил использовать его в новом разделе примера репозитория Aparapi, вы можете найти это на the following link in the new Aparapi repository.