我在 C++ 中为 opencl 编写了一个点积内核,它适用于向量长度 4096(也尝试了 12k 个元素并且工作完美)但是当我将向量长度增加到 16k 个元素时,结果变为无穷大,而它不应该超过一个小浮点数数字。显然有泄漏或类似的东西,但它适用于 n<16k 元素。16k 个元素和 4 个字节每个构成 64kB,三个缓冲区总和为 192kB,这甚至不是 gpu 内存的 1/1000。将结果与主机代码(C#)的相同缩减算法进行比较,主机结果如预期的那样小。也没有建立无穷大的精度误差(它甚至可能被限制在某个有限值)。
这是通过 DLL 调用从 C# 传递给 C++ 的内核(Ln= 本地工作大小,n= 全局工作大小):
"__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 中不是问题。
如果有帮助,请使用来自 Khronos 网站的 Opencl 1.2 头文件和 AMD Opencl.lib + Opencl.dll (目标设备是 HD7870)。