Я написал ядро dotproduct для opencl на C ++, и оно работает для длины вектора 4096 (также пробовал 12k элементов и работает без нареканий), но когда я увеличиваю длину вектора до 16k элементов, результат становится бесконечным пока он не должен выходить за пределы небольшого числа с плавающей точкой. Ясно, что есть утечка или что-то подобное, но это нормально работает<16к элементов. 16 КБ элементов и 4 байта каждый составляют 64 КБ, три буфера суммируются до 192 КБ, и это даже не 1/1000 памяти gpu. Сравненный результат с тем же алгоритмом сокращения для кода хоста (C #) и результата хоста мал, как и ожидалось. Также нет погрешностей точности для построения бесконечности (она может даже ограничиваться определенным конечным значением).
Вот ядро (Ln = локальный размер работы, n = глобальный размер работы) из C #, переданное в C ++ через DLL-вызов:
"__kernel void SkalarCarpim(__global float * v1, __global float * v2, __global float * v3)" +
"{" +
" int i = get_global_id(0);" +
" int j = get_local_id(0);" +
" __local float biriktirici [" + Ln.ToString() + "];" +
" barrier(CLK_LOCAL_MEM_FENCE);" +
" biriktirici[j]=v1[i]*v2[i];" +
" barrier(CLK_LOCAL_MEM_FENCE);" +
" barrier(CLK_GLOBAL_MEM_FENCE);" +
" float toplam=0.0f;" +
" if(j==0)" +
" {" +
" for(int k=0;k<"+Ln.ToString()+";k++)"+ // reduction
" {"+
" toplam+=biriktirici[k];"+
" }"+
" }" +
" barrier(CLK_GLOBAL_MEM_FENCE);" +
" v3[i]=toplam;" +
" barrier(CLK_GLOBAL_MEM_FENCE);" +
" toplam=0.0f;" +
" for(int k=0;k<"+(n/Ln).ToString()+";k++)" +
" {" +
" toplam+=v3[k*"+Ln.ToString()+"]; " + // sum of temporary sums
" }" +
" v3[i]=toplam;"+
"}";
Вот буферы C ++ Opencl:
buf1=cl::Buffer(altYapi,CL_MEM_READ_WRITE,sizeof(cl_float) * N);
buf2=cl::Buffer(altYapi,CL_MEM_READ_WRITE,sizeof(cl_float) * N);
buf3=cl::Buffer(altYapi,CL_MEM_READ_WRITE,sizeof(cl_float) * N);
//CL_MEM_READ_ONLY makes same error, tried some other too, no solution :(
Вот как отправляются буферы:
komutSirasi.enqueueWriteBuffer(buf1,CL_TRUE,0,sizeof(cl_float)*N,v1);
komutSirasi.enqueueWriteBuffer(buf2,CL_TRUE,0,sizeof(cl_float)*N,v2);
//CL_TRUE makes a blocking action so waits until finished
Исполнение:
komutSirasi.enqueueNDRangeKernel(kernel,0,Global,Local);
//I got this from an example and I dont know if it is blocking or not.
Вот как берется буфер результатов (все элементы являются результатом, я знаю, что он незакончен):
komutSirasi.enqueueReadBuffer(buf3,CL_TRUE,0,sizeof(cl_float) * N,v3);
//CL_TRUE makes a blocking action so waits until finished
Вопрос: Есть ли необходимость в настройке, прежде чем погрузиться в C ++ Opencl? Это не было проблемой в Java / Aparapi / Jocl.
Для этого используйте заголовки Opencl 1.2 с сайта Khronos и AMD Opencl.lib + Opencl.dll (целевое устройство HD7870).
Ваше второе сокращение, сумма v3 [k * N], предполагает, что все значения в v3 уже вычислены. Это потребует синхронизации между различными рабочими группами, что невозможно в общем случае. Это может случайно произойти, когда есть одна рабочая группа.
После первого сокращения вы должны сохранить toplam в v3 [get_group_id (0)], а затем запустить второе ядро для второго сокращения.
Других решений пока нет …