为啥这个 opencl 代码是不确定的?

Posted

技术标签:

【中文标题】为啥这个 opencl 代码是不确定的?【英文标题】:Why is this opencl code non-deterministic?为什么这个 opencl 代码是不确定的? 【发布时间】:2013-04-11 19:42:29 【问题描述】:

以下 python 代码使用 PyOpenCL 用数组 b 中元素的总和填充数组 a_plus_b(这不是我的实际目标,但它是我能找到的最简单的代码,它仍然显示问题)。

import pyopencl as cl
import numpy as np
import numpy.linalg as la

height = 50
width = 32

b = np.arange(width,dtype=np.int32)

ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

mf = cl.mem_flags
b_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=b)
dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, height*4)

prg = cl.Program(ctx, """
    __kernel void sum(__global const int *b, __global int *c)
    
      int x = get_global_id(1);
      int y;
      c[x] = 0;
      for(y=0;y<get_global_size(0);y++) 
          c[x] += b[y];
      
    
    """).build()

prg.sum(queue, (width,height), None, b_buf, dest_buf)

a_plus_b = np.empty(height,dtype=np.int32)
cl.enqueue_copy(queue, a_plus_b, dest_buf)

print(np.sum(b))
print(a_plus_b)
print(np.sum(a_plus_b-np.sum(b)))

给出输出:

496
[496 496 496 496 496 496 496 496 496 496 496 496 496 496 496 496 496 496
 496 496 496 496 496 496 496 496 496 496 496 496 496 496 496 496 496 496
 496 496 496 496 496 496 496 496 496 496 496 496 496 496]
0

但是,如果我将 width 从 32 更改为 33,则数组不再是同一个元素。

528
[555 557 555 559 560 528 560 560 528 528 528 528 528 528 528 528 528 528
 528 528 528 531 540 569 581 528 705 591 560 560 545 560 560 528 560 528
 528 528 528 528 528 528 528 528 528 528 528 532 533 535]
752

实际上,每次运行代码,都会产生不同的结果。

528
[560 560 559 560 560 560 560 528 528 528 528 528 528 528 528 528 528 528
 528 528 528 560 528 514 565 553 621 650 560 560 560 560 560 528 528 528
 528 528 528 528 528 528 528 528 549 528 528 544 528 537]
724

造成这种差异的原因是什么?什么不是

【问题讨论】:

【参考方案1】:

您正在运行 WIDTH x HEIGHT 工作项。对于内核中的每个 X 值,都会有 WIDTH 工作项并行执行完全相同的操作:将 C[X] 设置为 0,然后在 Y 循环中更新它。所有这些 WIDTH 工作项将读取 C[X],然后或多或少地同时更新它。这种“或多或少”是您观察到的变化的原因。

您的算法是一维的,您只需要运行 HEIGHT 工作项,并将 WIDTH 作为内核参数传递。将 C[X] 替换为寄存器“SUM”,并在最后执行单个 C[X]=SUM。

【讨论】:

解决了这个问题。我想这就是我因为懒惰而不将数组的长度作为实际参数传递而得到的。

以上是关于为啥这个 opencl 代码是不确定的?的主要内容,如果未能解决你的问题,请参考以下文章

为啥相同的 OpenCL 代码从 Intel Xeon CPU 和 NVIDIA GTX 1080 Ti GPU 具有不同的输出?

linux 下OpenCL代码中已经写了 include <CL/cl.h> 为啥clGetPlatformIDs之类的函数仍不能编译通过

为啥以下 Haskell 代码是不确定的?

Apple 是不是提供了一种方法来确定为啥不推荐使用特定代码?

MSSQL 为啥这个函数是不确定的

如何查看android 是不是支持opencl