2017-02-10 7 views
1

У меня есть набор операций, выполняющихся в цикле.Как накапливать векторы в OpenCL?

for(int i = 0; i < row; i++) 
{ 
    sum += arr1[0] - arr2[0] 
    sum += arr1[0] - arr2[0] 
    sum += arr1[0] - arr2[0] 
    sum += arr1[0] - arr2[0] 

    arr1 += offset1; 
    arr2 += offset2; 
} 

Теперь я пытаюсь векторизовать операции, как этот

for(int i = 0; i < row; i++) 
{ 
    convert_int4(vload4(0, arr1) - vload4(0, arr2)); 

    arr1 += offset1; 
    arr2 += offset2; 
} 

Но как я аккумулировать результирующий вектор в скаляр sum без использования цикла?

Я использую OpenCL 2.0.

ответ

1

Я нашел решение, которое, кажется, является самым близким путем, я мог бы ожидать решения моей проблемы.

uint sum = 0; 
uint4 S; 

for(int i = 0; i < row; i++) 
{ 
    S += convert_uint4(vload4(0, arr1) - vload4(0, arr2)); 

    arr1 += offset1; 
    arr2 += offset2; 
} 

S.s01 = S.s01 + S.s23; 
sum = S.s0 + S.s1; 

OpenCL 2.0 обеспечивает такую ​​функциональность с векторами, где элементы векторов последовательно могут быть заменены на операции сложения, как показано выше. Это может поддерживать до вектора размера 16. Большие операции можно разделить на факторы меньших операций. Например, для добавления абсолютных значений разностей между двумя векторами размером 32, мы можем сделать следующее:

uint sum = 0; 
uint16 S0, S1; 

for(int i = 0; i < row; i++) 
{ 
    S0 += convert_uint16(abs(vload16(0, arr1) - vload16(0, arr2))); 
    S1 += convert_uint16(abs(vload16(1, arr1) - vload16(1, arr2))); 

    arr1 += offset1; 
    arr2 += offset2; 
} 

S0 = S0 + S1; 
S0.s= S0.sS0.s89abcdef; 
S0.s= S0.sS0.s4567; 
S0.s01 = S0.s01 + S0.s23; 
sum = S0.s0 + S0.s1; 
+0

Тогда cpu должен быть быстрым с этим, и поскольку нет дополнительного умножения, как в dot product gpu тоже быстро –

1

Операция называется «сокращение», и, похоже, есть информация об этом here.

В функции OpenCL, как представляется, реализованы, один из которых work_group_reduce(), который может вам помочь: link.

И презентация, включая код: link.

+0

сокращений, насколько я могу понять, являются для элементов работы в рабочей группе. Принимая во внимание, что в моем коде это один рабочий элемент. –

+0

«Редукция» - это общая концепция, в которой несколько переменных «сводятся» к одному. Для этого вы можете использовать разные операции: add, multiply, min, max, XOR, AND, OR и т. Д. В ссылках вы показываете код о том, как писать эффективный параллельный код для реализации. Поскольку каждая ситуация другая, я не уверен, что есть простая операция, которая решает вашу проблему. – JHBonarius

1

Для float2, float4 и аналогичной, самой простой версией может быть точечный продукт. (Преобразование из междунар плавать может быть дорогим)

float4 v1=(float4)(1,2,3,4); 
float4 v2=(float4)(5,6,7,8); 

float sum=dot(v1-v2,(float4)(1,1,1,1)); 

это равно

(v1.x-v2.x)*1 + (v1.y-v2.y)*1+(v1.z-v2.z)*1+(v1.w-v2.w)*1 

и если есть аппаратная поддержка для нее, оставив ее на милость компилятора должно быть в порядке. Для больших векторов и особенно массивов ответ Дж. Б.Бонариуса - это путь. Как я знаю, только у процессора есть такие операции с вертикальной суммой, поскольку у GPU это не так, но ради мобильности, dot product и work_group_reduce - это самые простые способы достижения удобочитаемости и даже производительности.

У продукта Dot есть дополнительные умножения, поэтому это может быть не всегда хорошо.

+0

Почему эта операция не поддерживается для целых чисел? –

+0

Возможно, из-за программного обеспечения. Такие, как разработчики игр, пишущие собственные алгоритмы квадратного корня в течение длительного времени, вместо того, чтобы просить об этом поставщиков оборудования. Также вы можете преобразовать горизонтальное добавление в вертикальное добавление. Таким образом, вы можете добавить точно так же, как и векторы, но по крайней мере нужны 4 вектора вектора –