GPU/CUDA: 重新排序设备内存
GPU/CUDA: Re-ordering device memory
我在设备内存中存储了一个多维数组。我想"permute"/"transpose",即根据新的维度顺序重新排列它的元素。
例如,如果我有一个二维数组
A = [0, 1, 2
3, 4, 5]
我想改变维度的顺序所以我得到
B = [0, 3
1, 4
2, 5]
这种重新排序实际上是按照 [0,1,2,3,4,5]
和 return 的顺序复制存储在内存中的元素,一个新的排序 [0,3,1,4,2,5]
.
我知道如何将索引从 A
映射到 B
,我的问题是如何使用 cuda 在设备上高效地执行此映射?
你可以检查这个http://devblogs.nvidia.com/parallelforall/efficient-matrix-transpose-cuda-cc/
朴素矩阵转置:
__global__ void transposeNaive(float *odata, const float *idata)
{
int x = blockIdx.x * TILE_DIM + threadIdx.x;
int y = blockIdx.y * TILE_DIM + threadIdx.y;
int width = gridDim.x * TILE_DIM;
for (int j = 0; j < TILE_DIM; j+= BLOCK_ROWS)
odata[x*width + (y+j)] = idata[(y+j)*width + x];
}
通过共享内存合并转置:
__global__ void transposeCoalesced(float *odata, const float *idata)
{
__shared__ float tile[TILE_DIM][TILE_DIM];
int x = blockIdx.x * TILE_DIM + threadIdx.x;
int y = blockIdx.y * TILE_DIM + threadIdx.y;
int width = gridDim.x * TILE_DIM;
for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
tile[threadIdx.y+j][threadIdx.x] = idata[(y+j)*width + x];
__syncthreads();
x = blockIdx.y * TILE_DIM + threadIdx.x; // transpose block offset
y = blockIdx.x * TILE_DIM + threadIdx.y;
for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
odata[(y+j)*width + x] = tile[threadIdx.x][threadIdx.y + j];
}
我在设备内存中存储了一个多维数组。我想"permute"/"transpose",即根据新的维度顺序重新排列它的元素。
例如,如果我有一个二维数组
A = [0, 1, 2
3, 4, 5]
我想改变维度的顺序所以我得到
B = [0, 3
1, 4
2, 5]
这种重新排序实际上是按照 [0,1,2,3,4,5]
和 return 的顺序复制存储在内存中的元素,一个新的排序 [0,3,1,4,2,5]
.
我知道如何将索引从 A
映射到 B
,我的问题是如何使用 cuda 在设备上高效地执行此映射?
你可以检查这个http://devblogs.nvidia.com/parallelforall/efficient-matrix-transpose-cuda-cc/
朴素矩阵转置:
__global__ void transposeNaive(float *odata, const float *idata)
{
int x = blockIdx.x * TILE_DIM + threadIdx.x;
int y = blockIdx.y * TILE_DIM + threadIdx.y;
int width = gridDim.x * TILE_DIM;
for (int j = 0; j < TILE_DIM; j+= BLOCK_ROWS)
odata[x*width + (y+j)] = idata[(y+j)*width + x];
}
通过共享内存合并转置:
__global__ void transposeCoalesced(float *odata, const float *idata)
{
__shared__ float tile[TILE_DIM][TILE_DIM];
int x = blockIdx.x * TILE_DIM + threadIdx.x;
int y = blockIdx.y * TILE_DIM + threadIdx.y;
int width = gridDim.x * TILE_DIM;
for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
tile[threadIdx.y+j][threadIdx.x] = idata[(y+j)*width + x];
__syncthreads();
x = blockIdx.y * TILE_DIM + threadIdx.x; // transpose block offset
y = blockIdx.x * TILE_DIM + threadIdx.y;
for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
odata[(y+j)*width + x] = tile[threadIdx.x][threadIdx.y + j];
}