操作指南#

如何在PyOpenCL中使用结构类型#

我们照常导入并初始化PyOpenCL:

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

>>> ctx = cl.create_some_context(interactive=False)
>>> queue = cl.CommandQueue(ctx)

然后,假设我们要声明一个由整数和浮点数组成的结构。我们先创建一个 numpy.dtype 沿着这些路线:

>>> my_struct = np.dtype([("field1", np.int32), ("field2", np.float32)])
>>> print(my_struct)
[('field1', '<i4'), ('field2', '<f4')]

备注

不是全部 numpy 还不支持数据类型。例如,不支持字符串(通常是有自己形状的东西)。

由于OpenCL C可能对 numpy 关于结构应该如何布局,例如,因为 alignment 。因此,作为第一步,我们将我们的dtype与CL的版本进行匹配:

>>> my_struct, my_struct_c_decl = cl.tools.match_dtype_to_c_struct(
...    ctx.devices[0], "my_struct", my_struct)
>>> print(my_struct_c_decl)
typedef struct {
  int field1;
  float field2;
} my_struct;

然后我们告诉PyOpenCL我们的新类型。

>>> my_struct = cl.tools.get_or_register_dtype("my_struct", my_struct)

接下来,我们可以在主机上创建一些该类型的数据并将其传输到设备:

>>> ary_host = np.empty(20, my_struct)
>>> ary_host["field1"].fill(217)
>>> ary_host["field2"].fill(1000)
>>> ary_host[13]["field2"] = 12
>>> print(ary_host) 
[(217,  1000.) (217,  1000.) (217,  1000.) (217,  1000.) (217,  1000.)
 (217,  1000.) (217,  1000.) (217,  1000.) (217,  1000.) (217,  1000.)
 (217,  1000.) (217,  1000.) (217,  1000.) (217,    12.) (217,  1000.)
 (217,  1000.) (217,  1000.) (217,  1000.) (217,  1000.) (217,  1000.)]

>>> ary = cl.array.to_device(queue, ary_host)

然后我们可以使用自己的内核对数组进行操作:

>>> prg = cl.Program(ctx, my_struct_c_decl + """
...     __kernel void set_to_1(__global my_struct *a)
...     {
...         a[get_global_id(0)].field1 = 1;
...     }
...     """).build()

>>> evt = prg.set_to_1(queue, ary.shape, None, ary.data)
>>> print(ary) 
[(1,  1000.) (1,  1000.) (1,  1000.) (1,  1000.) (1,  1000.) (1,  1000.)
 (1,  1000.) (1,  1000.) (1,  1000.) (1,  1000.) (1,  1000.) (1,  1000.)
 (1,  1000.) (1,    12.) (1,  1000.) (1,  1000.) (1,  1000.) (1,  1000.)
 (1,  1000.) (1,  1000.)]

以及PyOpenCL的内置操作:

>>> from pyopencl.elementwise import ElementwiseKernel
>>> elwise = ElementwiseKernel(ctx, "my_struct *a", "a[i].field1 = 2;",
...    preamble=my_struct_c_decl)
>>> evt = elwise(ary)
>>> print(ary) 
[(2,  1000.) (2,  1000.) (2,  1000.) (2,  1000.) (2,  1000.) (2,  1000.)
 (2,  1000.) (2,  1000.) (2,  1000.) (2,  1000.) (2,  1000.) (2,  1000.)
 (2,  1000.) (2,    12.) (2,  1000.) (2,  1000.) (2,  1000.) (2,  1000.)
 (2,  1000.) (2,  1000.)]