OpenCL 内核的非确定性行为 我注意到调试的事实:问题:

问题描述

考虑以下 OpenCL 内核。这是一个从长期的简化过程中产生的 MWE。当然拥有这样的内核是没有意义的,但这不是重点。保证MAX_ORDER >= num_fields,特别是MAX_ORDER=15(它通过clBuildProgram作为编译时常量传递给-D)。

__kernel void MWE_kernel(__global const double* const x,__global const double* alpha,const int num_fields,__global double* const restrict result,__local double* const restrict result_local)
{
    const int id          = get_global_id(0);
    const int global_size = get_global_size(0);

    double sum[MAX_ORDER];
    for (unsigned int i = 0; i < num_fields; i++)
        sum[i] = 0.0;
    
    double sum_sc=0.0;

    for (unsigned int id_mem = id; id_mem < 128 * num_fields; id_mem += global_size) {
        const int alpha_idx = id_mem / 128;
        //sum[0] += 3.0;
        sum[alpha_idx] += 3.0;
        sum_sc += 3.0;
        /*
        if (id == 8){
            printf("sum[%d]=%f   sum_sc=%f\n",alpha_idx,sum[alpha_idx],sum_sc);
        }
        */
    }
    
    if(id == 8){
        result[0] = sum[0];
        result[1] = sum_sc;
    }
}

我用 Intel(R) Gen9 HD Graphics NEOlocal_size=64 以及 global_size=64 在 GPU 设备(设备名称:num_fields=1)上排队。

我遇到的奇怪行为(我无法解释)是,如果我尝试使用 sum 作为索引填充 alpha_idx 私有数组,那么这对某些线程不起作用,在sum 条目没有增加的感觉。显示这种行为的第一个线程是数字 8,最后一个 if-clause 设置 result[0] = 0result[1]=6,因为我可以在主机上检查。

我注意到调试的事实:

  • 设置 MAX_ODER=1(在本例中可能,因为 num_fields=1),使奇怪的行为消失(result[0] 变为 6)。但是,对于 1<MAX_ORDER<21 没有任何变化。令人惊讶的是,MAX_ORDER>=22 更改了内核行为,我得到了 result[0]=6
  • 改变 local_size 和/或 global_size 不会改变任何东西,除非 local_size 减少到 8 或更少(见下一个项目符号)。
  • 将用于将内核排入队列的 local_size 减少到 8 会使奇怪的行为消失(在上面的示例中很简单,因为不再有线程号 8,但是在更复杂的完整版本中,我得到了预期的结果)。
  • 使用 this one 等在线工具没有发现任何问题。

问题:

  1. 您有什么想法可以解释我正在经历的行为吗?你能重现这种行为吗?
  2. 私有内存使用安全吗?或者 sum 数组声明在某种程度上很重要?
  3. 如果我没有做错任何事,这种行为是否是 (GPU) 编译器错误!?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)