0

我在 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)。

4

1 回答 1

3

您的第二次减少,即 v3[k*N] 的总和,假设 v3 中的所有值都已计算。这将需要不同工作组之间的同步,这在一般情况下是不可能的。当只有一个工作组时,它可能会意外发生。

第一次缩减后,您应该将 toplam 存储在 v3[get_group_id(0)] 中,然后运行第二个内核进行第二次缩减。

于 2013-07-31T21:52:56.780 回答