在opencl和pyopencl中的行和列主要

时间:2015-06-12 15:19:52

标签: python c opencl pyopencl

我是opencl的新手,也许我会问一个愚蠢的问题!

我在c/opencl中调整python/pyopencl程序时遇到了一些问题。特别是,我对使用 column-major row-major 订单感到有点困惑。

考虑M[i,j]维度的矩阵Ni*Nj,:

  • 专栏订单定义为:i + Ni*j

  • 行主订单定义为:j + Nj*i

将此内核用于(3,3)的本地大小:

__kernel void major(__global double local_i_i_major,
                    __global double local_j_i_major,
                    __global double local_i_j_major,
                    __global double local_j_j_major)
{
int i = get_global_id(0) ;
int j = get_global_id(1) ;

int Ni = get_num_groups(0) * get_local_size(0) ;
int Nj = get_num_groups(1) * get_local_size(1) ;

int main_i_major = j + i*Nj ;
int main_j_major = i + j*Ni ;

local_i_i_major(main_i_major) = get_local_id(0) ;
local_j_i_major(main_i_major) = get_local_id(1) ;

local_i_j_major(main_j_major) = get_local_id(0) ;
local_j_j_major(main_j_major) = get_local_id(1) ;
}

我们可以看看本地索引的分布。

使用Column-major时,我们获得:

|-------------------------- (i,j) ----------------------|
_________________________________________________________
| (0,0)  |  (1,0)  |  (2,0)  | (0,0)  |  (1,0)  |  (2,0) |
| (0,0)  |  (1,0)  |  (2,0)  | (0,0)  |  (1,0)  |  (2,0) |
| (0,0)  |  (1,0)  |  (2,0)  | (0,0)  |  (1,0)  |  (2,0) |
| (0,1)  |  (1,1)  |  (2,1)  | (0,1)  |  (1,1)  |   ...  |
| (0,1)  |  (1,1)  |  (2,1)  | (0,1)  |   ...   |   ...  |
| (0,1)  |  (1,1)  |  (2,1)  |   ...  |   ...   |   ...  |
_________________________________________________________

而且,当我们使用Row-major时,我们得到了:

|-------------------------- (i,j) ----------------------|
_________________________________________________________
| (0,0)  |  (0,1)  |  (0,2)  |  (0,0) |  (0,1)  |  ...  |
| (1,0)  |  (1,1)  |  (1,2)  |  (1,0) |   ...   |  ...  |
| (2,0)  |  (2,1)  |  (2,2)  |  (2,0) |   ...   |  ...  |
| (0,0)  |  (0,1)  |  (0,2)  |  (0,0) |  (0,1)  |  ...  |
| (1,0)  |  (1,1)  |  (1,2)  |  (1,0) |   ...   |  ...  |
| (2,0)  |  (2,1)  |  (2,2)  |  (2,0) |   ...   |  ...  |
_________________________________________________________

当然,这些分布是不同的。特别是,我不理解列主要顺序的本地索引分布。有些工作项似乎具有相同的ID?有可能吗?

当我阅读有关C/openCL的文章时,大部分时间都会使用列主要顺序。当我阅读Python/PyOpencl例子时,这是使用的 row-major 顺序。

考虑到Python和C都使用 raw-major 顺序,为什么存在这种差异?

另外,性能怎么样?使用列主要行主要顺序更好吗?

是否可以在opencl中更改值的排序方式?

2 个答案:

答案 0 :(得分:0)

您将内存布局的概念与工作组维度混淆。 OpenCL定义了最多3维的工作空间的抽象细分。它们不必与任何特定的内存布局相对应。最佳内存布局取决于您要实现的特定算法。但是,OpenCL不会将工作项映射到内存 - 您可以通过内存访问操作在内核中执行此操作。

OpenCL驱动程序逻辑(因为它实际上是并行的)迭代工作组维度,但是标准中没有指定顺序,因为它取决于体系结构。在工作组中,所有工作项都可以被视为并行执行(尽管实际上它们可能不是)。但即使它们并不代表特定的内存布局 - 例如,本地维度可能是(16,1),但您可以访问内存中的4x4区域。

最佳映射取决于设备类型(GPU / FPGA与CPU),因为它们的架构不同。

总而言之,在一般情况下无法确定存储器布局和逻辑维度(或域分解)这两个方面;它们取决于您正在实施的算法。

您对特定内核的问题是因为您无意义地混合逻辑索引,然后将它们用作物理索引。如果您逐步完成代码,您将看到为什么在输出中出现重复条目​​。

顺便说一句,你的代码看起来不像真正的内核 - 当然这些参数应该是指针;然后用支架符号()来访问它们,我想。

答案 1 :(得分:0)

据我所知,如果您具有C / OpenCL中按列排序的有序内核(在连接到一个OpenCL缓冲区的列上工作),那么唯一的解决方案是在行中有一些样本时从数组中转置fortran矩阵(由rowflux.append(sample)创建)进行分析:

columnflux = np.transpose(np.asarray(rowflux, dtype=np.float64, order='F'))
...
_knl = mavg_k.yourcolumnorientedkernel
_knl.set_scalar_arg_dtypes([None,np.uint32,np.uint32,None])
_knl(queue,(globalSize,),(maxWorkGroupSize,),columnfluxbuffer,w,h,outputbuffer)

否则,您可以为numpy矩阵编写面向行的矩阵内核(当pyOpenCL cl.Buffer从一个接一个的矩阵行创建一条OpenCL缓冲行时)。