2016-04-05 6 views
1

Я пытаюсь сделать кумулятивный расчет, подобный сокращению, в котором необходимо сохранить 4 разных значения в зависимости от определенных условий. Мое ядро ​​получает длинные массивы в качестве входных данных и должно хранить только 4 значения, которые являются «глобальными суммами», полученными из каждой точки данных на входе. Например, мне нужно сохранить сумму всех значений данных, удовлетворяющих определенному условию, и количество точек данных, удовлетворяющих указанному условию. Ядро ниже, чтобы сделать его более ясным:OpenCL: несколько рабочих элементов сохраняют результаты на один и тот же адрес глобальной памяти

__kernel void photometry(__global float* stamp, 
         __constant float* dark, 
         __global float* output) 
{ 
int x = get_global_id(0); 
int s = n * n; 

if(x < s){ 
    float2 curr_px = (float2)((x/n), (x % n)); 
    float2 center = (float2)(centerX, centerY); 
    int dist = (int)fast_distance(center, curr_px); 
    if(dist < aperture){ 
     output[0] += stamp[x]-dark[x]; 
     output[1]++; 
    }else if (dist > sky_inner && dist < sky_outer){ 
     output[2] += stamp[x]-dark[x]; 
     output[3]++; 
    } 
} 
} 

Все значения не объявленные в ядре предварительно определены с помощью макросов. s - длина входных массивов stamp и dark, которые составляют n x n матрицы, сплющенные до 1D.

Я получаю результаты, но они отличаются от моей версии процессора. Конечно, мне интересно: - это правильный способ сделать то, что я пытаюсь сделать? Могу ли я быть уверенным, что каждый пиксельный файл добавляется только один раз? Я не могу думать о другом способе сохранения совокупных значений результата.

+0

Несколько потоков, пытающихся изменить те же индексированные элементы. Вы нуждаетесь в доступе к атомам. Атомные инструкции добавления и атома. Таким образом, все потоки будут получать обновленные значения вместо неопределенных значений. https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/atomicFunctions.html –

+0

@huseyintugrulbuyukisik благодарит вас за ваше предложение. Однако это будет необходимо, даже если потоки не будут считываться из выходного буфера? Буферы, из которых прочитанные потоки не изменяются при вычислении – Francisca

ответ

3

Атомная операция необходима в вашем случае, в противном случае данные гонки приведут к непредсказуемым результатам.

Проблема здесь:

output[0] += stamp[x]-dark[x]; 
output[1]++; 

Вы можете себе представить, что нити в одной и той же волны все еще может следовать тем же шагом, поэтому, может быть хорошо для потоков внутри одной и той же волны. Поскольку они считывают одно и то же значение выходного [0], используя команду глобальной загрузки (широковещание). Затем, когда они закончат вычисление и попытаются сохранить данные в один и тот же адрес памяти (вывод [0]), операции записи будут сериализованы. К этому моменту вы все равно можете получить правильные результаты (для рабочих элементов внутри одной волны).

Однако, очень вероятно, что ваша программа запускает более одной волны (в большинстве случаев это так). Различные волны могут выполняться в неизвестном порядке; то, когда они обращаются к одному и тому же адресу памяти, поведение становится более сложным. Например, wave0 и wave1 могут получить выход [0] в начале до того, как произойдет любое другое вычисление, что означает, что они получают одно и то же значение с выхода [0]; то они начинают вычисление. После вычисления они сохраняют свои накопительные результаты в выходные данные [0]; по-видимому, результат одной из волн будет перезаписан другой, как будто только тот, кто пишет память позже, был исполнен. Представьте, что у вас гораздо больше волн в реальном приложении, поэтому не странно иметь неправильный результат.

 Смежные вопросы

  • Нет связанных вопросов^_^