opencl 在结构操作期间跳过数据

opencl skipping data during operation on struct

我有一个自定义 struct,我想对其执行操作以减少我所有结构上的字段 scalar1。这是一个非常简单的操作。减法似乎正在发生,但 OpenCL 对错误的数据进行了操作。这是一个可能可以在您的计算机上执行的 MWE。

import pyopencl as cl
import pyopencl.tools
import numpy as np


kernelSource = """
__kernel void decreaseScalarFieldBy(__global myStruct *a, float delta)
{
    int gid = get_global_id(0);
        a[gid].scalar1 -= delta;
}
"""

context = cl.create_some_context()
queue = cl.CommandQueue(context)
device = context.devices[0]

myStruct = np.dtype(
    [("vector1", cl.cltypes.float4),
     ("scalar1", cl.cltypes.float)])
name = "myStruct"
_, c_decl = cl.tools.match_dtype_to_c_struct(device, name, myStruct)
myStruct_dtype = cl.tools.get_or_register_dtype(name, myStruct)

program = cl.Program(context, c_decl + kernelSource).build()

N = 10
HOST_struct = np.empty(N, dtype=myStruct_dtype)
HOST_struct["vector1"] = np.array([cl.cltypes.make_float4(1, 0, 0, 0)]*N, dtype=cl.cltypes.float4)
HOST_struct["scalar1"] = np.ones(N, dtype=cl.cltypes.float)
TARGET_struct = cl.Buffer(context, cl.mem_flags.READ_WRITE | cl.mem_flags.COPY_HOST_PTR, hostbuf=HOST_struct)
cl.enqueue_copy(queue, dest=TARGET_struct, src=HOST_struct)

program.decreaseScalarFieldBy(queue, (N,), None, TARGET_struct, np.float32(0.5))

cl.enqueue_copy(queue, dest=HOST_struct, src=TARGET_struct)
queue.finish()

print(HOST_struct)

这是输出,减法全部移位,最终在 vector1 字段内减去?

[((1. ,  0. ,  0. ,  0. ), 0.5) ((1. ,  0. ,  0. ,  0. ), 1. )
 ((1. ,  0. , -0.5,  0. ), 1. ) ((1. ,  0. ,  0. ,  0. ), 1. )
 ((0.5,  0. ,  0. ,  0. ), 1. ) ((1. ,  0. ,  0. , -0.5), 1. )
 ((1. ,  0. ,  0. ,  0. ), 1. ) ((1. , -0.5,  0. ,  0. ), 1. )
 ((1. ,  0. ,  0. ,  0. ), 0.5) ((1. ,  0. ,  0. ,  0. ), 1. )]

有人可以向我解释这段代码有什么问题吗? 我已经分别尝试使用 floatfloat4 并且它们在结构外部时都可以完美地工作。

我不知道内存对齐的概念。 从 OpenCL 1.2 specification 第 6.1 章,我们了解到类型必须在 2^X 上对齐。因此,我的结构未对齐,因为它的大小为 36 字节。 sizeOf(float4) = 16 Bytes, sizeOf(float) = 4 Bytes.

但是,numpy 默认对齐数组,但 NOT 与 OpenCL 的对齐方式相同。因此,struct 必须与 OpenCL 对齐匹配。这是

的工作
_, c_decl = cl.tools.match_dtype_to_c_struct(device, name, myStruct)

问题是在我的代码中,_ 省略了新的重新声明的结构。需要做的是采用新的重新声明的 struct 并覆盖我们旧的 numpy 声明。

myStruct = np.dtype(
    [("position", cl.cltypes.float4),
     ("direction", cl.cltypes.float4),
     ("weight", cl.cltypes.float)])
name = "photonStruct"
myStruct, c_decl = cl.tools.match_dtype_to_c_struct(device, name, myStruct)
myStruct_dtype = cl.tools.get_or_register_dtype(name, myStruct)

现在一切正常。