如何在pyOpenCL中传递一组向量

时间:2012-07-31 09:16:10

标签: opencl pyopencl

我正在将模拟移动到pyOpenCL中,无法使我的数据访问工作。我正在尝试提供一维矢量数组(好吧,实际上有几个,但我刚刚使用过的一个例子)。

目前,几个向量被复制得很好,但数据根本就不是我提供的。

我认为我之前没有在这里发布,所以如果任何格式/演示文稿错误,请道歉。另外,我刚刚删除了所有的模拟代码,所以我意识到这个代码目前实际上并没有做任何事情,我只想让缓冲区传递正确。

提前致谢。

内核(kertest.py):

step1 = """
#pragma OPENCL EXTENSION cl_amd_printf: enable
#define X xdim
#define Y ydim
__kernel void k1(__global float3 *spins,
                 __local float3 *tile)
{        
    ushort lid = 2 * get_local_id(0);
    ushort group = 2 * get_group_id(0);
    ushort num = get_num_groups(0);
    int lim = X*Y*3;

    for (ushort i = 0; i < lim; i++)
        {
            if (lid == 0 && group == 0)
            {
                printf("%f :: %d\\n", spins[i].x, i);
            }
         }
}"""

代码本身(gputest.py):

import kertest as k2D
import numpy as np
import pyopencl as cl

class GPU_MC2DSim():
    def __init__(self, x, y):
        self.x = x
        self.y = y

        if x >= y:
            self.xdim = int(self.x)
            self.ydim = int(self.y)
        else:
            self.xdim = int(self.y)
            self.ydim = int(self.x)

        if self.xdim % 2 != 0: self.xdim += 1

        if self.ydim % 2 != 0: self.ydim += 1

        self.M = np.ones((self.xdim*self.ydim, 3)).astype(np.float32)
        self.M[:, 1] += 1.0
        self.M[:, 2] += 2.0

        print self.M

    def simulate(self):
        ctx = cl.create_some_context()
        q = cl.CommandQueue(ctx)
        mf = cl.mem_flags

        #Pass buffer:
        M_buf = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf = self.M)

        #Insert kernel parameters:
        params = {"xdim" : "%d" % (self.xdim),
                  "ydim" : "%d" % (self.ydim),
                  }
        for name in params:
            k2D.step1 = k2D.step1.replace(name, params[name])

        #Compile kernel:
        step1 = cl.Program(ctx, k2D.step1).build()

        locmem = cl.LocalMemory(self.xdim*4*4)

        step1.k1(q, ((self.xdim*self.ydim)/4,), (self.xdim/2,), M_buf, locmem).wait()
        return None

xdim = 4
ydim = 4
sim = GPU_MC2DSim(xdim, ydim)
sim.simulate()

1 个答案:

答案 0 :(得分:3)

您将数据复制到设备的代码很好。但是,你的内核至少有两个问题:

    根据OpenCL 1.2 Spec,6.1.5,
  1. float3值预计为16字节对齐:

      

    对于3分量矢量数据类型,数据类型的大小为4 * sizeof(分量)。这意味着3分量矢量数据类型将与4 * sizeof(分量)边界对齐。 vload3 vstore3 内置函数可用于分别从打包标量数据类型数组中读取和写入3分量矢量数据类型。

    您上传到设备的值未正确对齐,内核无法直接读取float3值。

  2. 您的限额计算int lim = X*Y*3;略有偏差。您已尝试从float3数组中读取,因此*3是多余的。

  3. 这两个问题的解决方案很简单:如规范中所述,您应该使用 vload3 float的数组中加载:

    #pragma OPENCL EXTENSION cl_amd_printf: enable
    #define X xdim
    #define Y ydim
    __kernel void k1(__global float *spins,
                     __local float3 *tile)
    {
        ushort lid = 2 * get_local_id(0);
        ushort group = 2 * get_group_id(0);
        ushort num = get_num_groups(0);
        int lim = X*Y;
    
        for (ushort i = 0; i < lim; i++)
            {
                if (lid == 0 && group == 0)
                {
                    float3 vec = vload3(i, spins);
                    printf("(%f, %f, %f) :: %d\\n", vec.x, vec.y, vec.z, i);
                }
             }
    }