我是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中更改值的排序方式?
答案 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缓冲行时)。