我有一个非常简单的cuda内核示例,它添加了两个矩阵的相应行。我有一个关于矩阵的内存访问的问题。我通过mex函数调用内核。我们知道在matlab中我们有一个列主要的顺序访问,而在C / C ++中有一个行主要顺序。基于cuda存储器组织,我们在每个块和线程的网格内都有坐标(x,y)。我试图以行/列主要顺序[1]的方式访问内核示例中的矩阵。在第一个内核中,如果我错了,请更正我,有一个列主要访问权限,而在第二个内核中有一个主要访问权限。两个内核都使用相同的参数,块数和帧数进行初始化。我相信使用矩阵的行主要顺序访问的第二个内核将是访问矩阵的正确方法,就像我们在c ++中一样。不幸的是,具有列主要顺序的内核根据算法返回正确的结果。有没有人有一个很好的解释?这个观察是否与我们通过mex函数调用内核这一事实有关,这意味着matlab并因此成为列主要的订单访问?
两个内核都称为:
int numElements = rows * cols; // rows and cols of d_A or d_B
int threadsPerBlock = 16;
int blocksPerGrid = ceil( (double) (numElements) / threadsPerBlock);
dim3 dimBlock( threadsPerBlock,threadsPerBlock );
dim3 dimGrid( blocksPerGrid, blocksPerGrid );
cudaEuclid<<<dimGrid, dimBlock>>>( d_A, d_B, d_C, rows, cols );
内核1:(工作但不是行主要的c ++样式)
__global__ void cudaEuclid( float* A, float* B, float* C, int rows, int cols )
{
int i, squareeucldist = 0;
int r = blockDim.x * blockIdx.x + threadIdx.x; // rows
int c = blockDim.y * blockIdx.y + threadIdx.y; // cols
if( r < rows ){
for ( i = 0; i < cols; i++ )
//column-major order
squareeucldist += ( A[r + rows*i] - B[r + rows*i] ) * ( A[r + rows*i] - B[r + rows*i] );
C[r] = squareeucldist;
squareeucldist = 0;
}
}
内核2:(行主要顺序,c ++样式)
__global__ void cudaEuclid( float* A, float* B, float* C, int rows, int cols )
{
int i, squareeucldist = 0;
int c = blockDim.x * blockIdx.x + threadIdx.x; // cols
int r = blockDim.y * blockIdx.y + threadIdx.y; // rows
if( r < rows ){
for ( i = 0; i < cols; i++ )
//row-major order
squareeucldist += ( A[i + cols*r] - B[i + cols*r] ) * ( A[i + cols*r] - B[i + cols*r] );
C[r] = squareeucldist;
squareeucldist = 0;
}
答案 0 :(得分:1)
这些观察是否与我们通过mex函数调用内核这一事实有关,这意味着matlab并因此成为列主要订单访问?
是
扩展到这一点,我的意思是说你已经证明没有理由不能在C / C ++中使用简单的1D缓冲区来使用列主要约定(在你的情况下使用CUDA是无关紧要的)。 / p>
将MATLAB数组视为一个特殊类,恰好将数据缓冲区保持为列主要顺序。它实际上被称为mxArray
,你可以使用format debug
只用MATLAB获得细节。
>> format debug
>> x = [1 2 3; 4 5 6]
x =
Structure address = a91d8a0
m = 2
n = 3
pr = 7406f620
pi = 0
1 2 3
4 5 6
pr
地址有一个缓冲区,mxArray
知道它有m=2
行和n=3
列。因为它是MATLAB,x(2)
是4
而不是2
,因为C中的约定是第二个值。在C中,如果将此2D数组定义为int A[2][3] = { {1, 2, 3}, {4, 5, 6} };
,the values will be laid out as 1 2 3 4 5 6
。
但是,如果您有一个简单的1D缓冲区,您可以通过从行和列计算线性索引来访问它,那么没有什么可以阻止您更改约定。在您的C示例中,您只是使用缓冲区(例如float* A
),因此由您决定如何对其进行索引(A[r + rows*c]
与A[c + cols*r]
)。
长话短说,要么在MATLAB中转置并使用行主内核,要么单独保留MATLAB输入并使用列主内核。
答案 1 :(得分:1)
正如您所提到的,Matlab使用列主要排序,因此某个矩阵(例如A
)将相应地存储在CPU内存中。
在程序的某个时刻,您需要A
将cudaMemcpy
从主机内存移动到设备内存。因此,A
将按照列主要顺序存储在设备内存中,并且必须将其考虑在内。
显然,您可以通过转置矩阵虚拟地在Matlab中实现行主排序存储。这可能有一些优点来实现合并的内存访问。