【问题标题】:Invalid results by summing an array, OpenCL, Interleaved Addressing对数组、OpenCL、交错寻址求和的结果无效
【发布时间】:2014-11-15 21:00:18
【问题描述】:

我开始学习 OpenCl,作为我必须编写的任务之一,我编写了一个对数组的所有元素求和的程序。

该程序应该很简单,我不知道我今天出了什么问题,但它不起作用。嗯,确实如此,但有时会显示错误的结果(有时不会)。

我们拥有的元素越多,得到错误结果的机会就越大(尤其是在 16536 之后) 元素的数量总是等于二的幂。

谁能告诉我,这里出了什么问题?

内核:

__kernel void Reduction_InterleavedAddressing(__global uint* array, uint stride)
{
    unsigned int i = get_global_id (0); 
    unsigned int size = get_global_size(0);

    if ((i % stride*2) == 0 && (i + stride)<size){
            array[i]  += array[i+stride];
    }
}

内核调用:

    unsigned int stride = 1;
    clErr = clSetKernelArg(m_InterleavedAddressingKernel, 0, sizeof(cl_mem), (void*)&m_dPingArray);

    for (; stride <= m_N / 2 ; stride*=2){
        clErr = clSetKernelArg(m_InterleavedAddressingKernel, 1, sizeof(cl_int), (void*)&stride);
        clErr = clEnqueueNDRangeKernel(CommandQueue, m_InterleavedAddressingKernel, 1, NULL, &globalWorkSize, LocalWorkSize, 0, NULL, NULL);
        V_RETURN_CL(clErr, "Error executing kernel");
    }

提前感谢您的提示

【问题讨论】:

  • 什么是 LocalWorkSize?尝试通过 NULL 代替。在 OpenCL 1.x 中,如果您传递本地工作大小,则全局工作大小必须是它的倍数。此外,这个内核可能有利于学习,但它不是一种有效的归约操作(随着步幅的增加,实际上做任何事情的工作项越来越少)。要调试您的算法,您可以在每次迭代后回读缓冲区,以查看结果是否符合您的预期。
  • 您正在使用该代码在悬崖上行走,如果工作项在单个内核调用中读取和写入相同的内存,那么结果肯定是错误的。在我看来,错误在于全局大小,每次迭代时大小应该减小,并且请将本地大小保留为 NULL,因为该代码无关紧要。
  • 您好,谢谢您的回答。我又写了一遍,globalWorkSize = 元素的数量,我每次都将它除以 2,localSize = NULL 并且在内核中我在每一步之后重新排列元素(放在开头)它效果更好,但仍然有错误:(跨度>
  • 更新:我将屏障(CLK_GLOBAL_MEM_FENCE)更改为屏障(CLK_LOCAL_MEM_FENCE),看起来它可以工作

标签: c++ opencl gpu reduction


【解决方案1】:

我测试它。您必须将stride * 2 设置为(stride * 2)!对于我的解决方案,它运行良好。

if ((i % (stride*2)) == 0 && (i + stride) < size) {
    array[i]  += array[i+stride];
}

【讨论】:

    猜你喜欢
    • 2012-07-15
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 1970-01-01
    相关资源
    最近更新 更多