【问题标题】:OpenCL kernel math outputs incorrect resultsOpenCL 内核数学输出不正确的结果
【发布时间】:2018-01-16 06:06:38
【问题描述】:

我目前正在尝试实现 OpenCL 内核。内核应该输出先前计算的元素数除以重新映射为 0 到 255 值的元素总数。

内核在具有 256 个工作项的单个工作组中运行,其中 LX 是本地 ID:

#define LX get_local_id(0)

kernel void reduceStatistic(global int *inout, int nr_workgroups, int nr_pixels)
{
    int i = 1;
    for (; i < nr_workgroups; i++)
    {
        inout[LX] += inout[LX + i * 256];
    }

    inout[LX] = (int)floor(((float)inout[LX] / (float)nr_pixels) * 256.0f);
}

重映射操作之前的计算是为了在同一个缓冲区上一次计算之后进行清理。

清除后的 inout[LX] 的第一项是 17176,nr_pixels 是 160000,因此使用上面的计算结果应该是 27。然而,代码返回 6。

相关主机端代码如下:

// nr_workgroups is of type int
cl_mem outputBuffer = clCreateBuffer(mgr->context, CL_MEM_READ_WRITE, nr_workgroups * 256 * sizeof(cl_int), NULL, NULL);

// another kernel writes into outputBuffer

// set kernel arguments
clSetKernelArg(mgr->reduceStatisticKernel, 0, sizeof(outputBuffer), &outputBuffer);
clSetKernelArg(mgr->reduceStatisticKernel, 1, sizeof(cl_int), &nr_workgroups);
clSetKernelArg(mgr->reduceStatisticKernel, 2, sizeof(cl_int), &imgSeqSize);

size_t global_work_size_statistics[1] = { 256 };
size_t local_work_size_statistics[1] = { 256 };

// run the kernel
clEnqueueNDRangeKernel(mgr->commandQueue, mgr->reduceStatisticKernel, 1, NULL, global_work_size_statistics, local_work_size_statistics, 0, NULL, NULL);

// read result
cl_int *reducedResult = new cl_int[256];
clEnqueueReadBuffer(mgr->commandQueue, outputBuffer, CL_TRUE, 0, 256 * sizeof(cl_int), reducedResult, 0, NULL, NULL);

帮助非常感谢! (:

【问题讨论】:

  • 你确定你的意思是i &lt;= nr_workgroups,不应该是i &lt; nr_workgroups吗? inout[LX + i * 265]; 中的步幅不应该是 256,而不是 265?
  • 265 有错,
  • 您能否检查一下您是否不小心创建了一个乱序队列?只需确保填充缓冲区的内核实际上首先完成。此外,如果您运行 2WG,您将覆盖内存。您可能打算使用 get_global_id()
  • commandQueue = clCreateCommandQueue(context, devices[deviceNo], CL_QUEUE_PROFILING_ENABLE, &status);

标签: opencl


【解决方案1】:

我们在 cmets 中建立了全局缓冲区索引计算错误:

    inout[LX] += inout[LX + i * 265];
                      ----------^^^
                      Should be 256

缓冲区超出范围会导致未定义的行为,因此这始终是要寻找的罪魁祸首之一。

【讨论】:

  • 感谢您的回答(:不幸的是,这并不能解决问题。我还注释掉了整个上半部分,但数学仍然是错误的。
  • @vakyas 如果您仍然需要这方面的帮助,请编辑问题以反映最新的代码(最好也包含 LX 宏的定义),并且还请提供相关的主机端代码( OpenCL API 调用、数据准备/读出)。目前的信息不足以让我们调试问题。
  • @vakyas 我目前看不到发布的代码有任何明显错误。需要检查的几件事:(1.) 您的命令队列是有序的,对吗?如果它是使用CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE 选项创建的,那么您的代码未充分同步。 (2.) 通过在reduce 内核运行之前插入一个额外的clEnqueueReadBuffer 并转储数据来验证您的输入数据确实符合您的预期。 (当然仅用于诊断目的)(3.)我对您的累积代码有一种不好的感觉,因为它混合了全局读取和写入。
  • 扩展项目 (3.) - 工作项目的全局内存访问似乎都不会直接重叠,但除了糟糕的内存访问效率之外,我可能不会混合像这样的全局读写。经过非常快速的搜索支持我的直觉,我在 OpenCL 规范中找不到任何地方,但我会使用私有变量 int sum = 0 然后将循环写为 for (int i = 0; i &lt; nr_workgroups; i++) sum += inout[LX + i * 256]; 然后,执行全局内存屏障,并且每个工作项只写一次inout[LX] 以获得最终结果。正如我所提到的,对此不确定。
  • 命令队列是有序的。如果我在运行内核之前输出缓冲区,结果与预期的完全一样。总而言之,感谢您的建议!这确实是有道理的,这不是一个很好的风格。
猜你喜欢
  • 2011-12-14
  • 1970-01-01
  • 2016-12-25
  • 1970-01-01
  • 2021-12-23
  • 2019-04-23
  • 2015-07-06
  • 2013-06-12
  • 1970-01-01
相关资源
最近更新 更多