赞
踩
大小为m×n的矩阵
A
A
A,其转置矩阵
A
T
A^{T}
AT的大小为n×m,且有矩阵
A
A
A的第
i
i
i行第
j
j
j列的元素
a
(
i
,
j
)
a(i,j)
a(i,j)与矩阵
A
T
A^{T}
AT的第
j
j
j行第
i
i
i列的元素
a
T
(
j
,
i
)
a^{T}(j,i)
aT(j,i)相等。
举例如下:
A
=
[
1
2
3
4
5
6
]
A
T
=
[
1
3
5
2
4
6
]
A=
先上代码,解释在后~
__global__ void gpu_matrix_trans(int *matx, int *matxT, int m, int n)
{
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if( row < m && col < n)
matxT[col*m+row] = matx[row*n+col];
}
这里是将二维矩阵展开为一维进行表示(申请的内存为连续的一维形式)。
cudaMalloc((void **) &matx, sizeof(int)*m*n)
坐标计算示意图如下所示:
相较于上述数据所使用的全局内存(Global memory),使用共享内存(Shared memory)可以对矩阵转置进行进一步优化。
共享内存位于GPU芯片上,相较位于DRAM中的全局内存拥有更低的延迟,其存取速度仅次于最快的寄存器。
(上图来自夏令营PPT)
但共享内存大小有限,数据量较大时需要对数据进行划分处理,否则会限制活动warp的数量。实现过程将在后续代码中体现。
同一block中的线程都可以访问共享内存,因此可能出现同时有很多线程访问共享内存中的数据。为了克服此问题,共享内存被划分为32个大小相等的内存块bank。
但同一warp中的多个线程同时访问同一个bank时就会发生冲突,降低效率。(但若访问同一地址,则会触发广播机制,不会发生冲突)
(上图来自夏令营PPT)
如上图所示,为避免冲突,可以在原申请内存的基础上增加一列,所以这里需要在申请共享内存时给BLOCK_SIZE+1。
__shared__ int tile_p[BLOCK_SIZE][BLOCK_SIZE+1];
#define BLOCK_SIZE 16 __global__ void gpu_matrix_trans_shared(int *d_matx,int *d_matxTs, int m, int n) { //申请共享内存 __shared__ int tile_p[BLOCK_SIZE][BLOCK_SIZE+1]; //转置矩阵元素的位置 int row = blockIdx.y * blockDim.y + threadIdx.y; int col = blockIdx.x * blockDim.x + threadIdx.x; //循环“小块”转置 int idx; for(int sub=0; sub<(n/BLOCK_SIZE+1); sub++){ //将数据copy到shared memory里面 idx = row*n + BLOCK_SIZE*sub + threadIdx.x; if(row < m && (BLOCK_SIZE*sub + threadIdx.x) < n) tile_p[threadIdx.y][threadIdx.x] = d_matx[idx]; //转置结果 __syncthreads(); idx = (BLOCK_SIZE*sub + threadIdx.x)*m + row; if(row < m && (BLOCK_SIZE*sub + threadIdx.x) < n) d_matxTs[idx] = tile_p[threadIdx.y][threadIdx.x]; __syncthreads(); } }
上述计算示意图如下所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。