Из following post, я пытаюсь осуществить сокращение суммы массива с этим ядром кода:OpenCL - метод для выполнения СОКРАЩЕНИЯ
#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
__kernel void sumGPU (__global const long *input,
__global long *finalSum
)
{
uint local_id = get_local_id(0);
uint group_size = get_local_size(0);
// Temporary local value
local long tempInput;
tempInput = input[local_id];
// Variable for final sum
local long totalSumIntegerPart[1];
// Initialize sums
if (local_id==0)
totalSumIntegerPart[0] = 0;
// Compute atom_add into each workGroup
barrier(CLK_LOCAL_MEM_FENCE);
atom_add(&totalSumIntegerPart[0], tempInput);
barrier(CLK_LOCAL_MEM_FENCE);
// Perform sum of each workGroup sum
if (local_id==(get_local_size(0)-1))
atom_add(finalSum, totalSumIntegerPart[0]);
}
Но значение finalSum
не ожидаемое значение (я имею сначала установите input
массив:
for (i=0; i<nWorkItems; i++)
input[i] = i+1;
Итак, я ожидаю с nWorkItems = 1024
: finalSum = nWorkItems*(nWorkItems+1)/2=524800
И на самом деле, я получаю finalSum = 16384
.
Получаю этот результат, принимая sizeWorkGroup = 16
и nWorkItems = 1024
.
Как ни странно, с sizeWorkGroup = 32
и nWorkItems = 1024
, я получаю еще одно значение: finalSum = 32768
Я не понимаю последнюю команду (которая, как предполагается, чтобы вычислить сумму каждой частичной суммы, то есть для каждой рабочей группы):
// Perform sum of each workGroup sum
if (local_id==(get_local_size(0)-1))
atom_add(finalSum, totalSumIntegerPart[0]);
Действительно, я бы подумал, что инструкция atom_add(finalSum, totalSumIntegerPart[0]);
не зависит от local_id
if condition
.
Важнейшей является эта инструкция, которая должна быть выполнена «number of workGroups
» раз (предполагается, что finalSum является общим значением между всеми рабочими группами, не так ли?).
Так я думал, что я мог бы заменить:
// Perform sum of each workGroup sum
if (local_id==(get_local_size(0)-1))
atom_add(finalSum, totalSumIntegerPart[0]);
по
// Perform sum of each workGroup sum
if (local_id==0)
atom_add(finalSum, totalSumIntegerPart[0]);
Любой может помочь найти правильное значение с моими параметрами (sizeWorkGroup = 16
и nWorkItems = 1024
), т.е. finalSum
, равных 524800
?
или exlain мне, почему эта окончательная сумма не очень хорошо выполнена?
UPDATE:
Вот код ядра на following link (она немного отличается от моего, потому что atom_add
здесь только шаг 1 для каждого WorkItem):
kernel void AtomicSum(global int* sum)
{
local int tmpSum[1];
if(get_local_id(0)==0){
tmpSum[0]=0;}
barrier(CLK_LOCAL_MEM_FENCE);
atomic_add(&tmpSum[0],1);
barrier(CLK_LOCAL_MEM_FENCE);
if(get_local_id(0)==(get_local_size(0)-1)){
atomic_add(sum,tmpSum[0]);
}
}
Является ли это правильный код ядра , Я имею в виду, что дает хорошие результаты?
Может быть, решение могло бы положить на начало моего кода ядра:
unsigned int tid = get_local_id(0);
unsigned int gid = get_global_id(0);
unsigned int localSize = get_local_size(0);
// load one tile into local memory
int idx = i * localSize + tid;
localInput[tid] = input[idx];
Я собираюсь проверить его и держать вас в курсе.
Благодаря
спасибо, я понимаю мои странные результаты. Но из http://simpleopencl.blogspot.fr/2013/04/performance-of-atomics-atomics-in.html они советуют работать с локальной памятью, которая обеспечивает лучшие характеристики. Я добавил свое обновление выше кода ядра, который они используют. – youpilat13
Вы хотели сказать: "atom_add (& totalSumIntegerPart, input [get_global_id (0)]);", а не "atom_add (& totalSumIntegerPart, input [get_global_size (0)]);", не так ли? – youpilat13
Конечно! Моя ошибка .... Я сделал ошибку копирования ... Исправлено. – DarkZeros