目录
[1. 解决的问题](#1. 解决的问题)
[2. 分析](#2. 分析)
[3. 方法](#3. 方法)
[4. 代码示例](#4. 代码示例)
1. 解决的问题
利用块和线程索引,从全局内存中访问指定的数据。
2. 分析
通常情况下,矩阵 是用行优先的方法在全局内存中线性存储的。如下。
8列6行矩阵(nx,ny)=(8,6)。
3. 方法
这里建立二维网格(2,3)+二维块(4,2)为例,使用其块和线程索引映射矩阵索引。
(1)第一步,可以用以下公式把线程和块索引映射到矩阵坐标上;
(2)第二步,可以用以下公式把矩阵坐标映射到全局内存中的索引/存储单元上;
比如要获取矩阵元素(col,row) = (2,4) ,其全局索引是34,映射到矩阵坐标上,
ix = 2 + 0*3=2; iy = 0 + 2*2=4. 然后再映射到全局内存idx = 4*8 + 2 = 34.
4. 代码示例
cpp
#include "cuda_runtime.h"
#include "device_launch_parameters.h" // threadIdx
#include <stdio.h> // io
#include <time.h> // time_t
#include <stdlib.h> // rand
#include <memory.h> //memset
#define CHECK(call) \
{ \
const cudaError_t error_code = call; \
if (error_code != cudaSuccess) \
{ \
printf("CUDA Error:\n"); \
printf(" File: %s\n", __FILE__); \
printf(" Line: %d\n", __LINE__); \
printf(" Error code: %d\n", error_code); \
printf(" Error text: %s\n", \
cudaGetErrorString(error_code)); \
exit(1); \
} \
}
void initiaInt(int* p, const int N)
{
for (int i = 0; i < N; i++)
{
p[i] = i;
}
}
/// <summary>
///
/// </summary>
/// <param name="c">全局内存中线性存储的二维矩阵</param>
/// <param name="nx">列</param>
/// <param name="ny"></param>
void printMatrix(int* c, const int nx, const int ny)
{
int* ic = c;
printf("\n matrix: [%d, %d] \n", nx, ny);
for (int i = 0; i < ny; i++)
{
for (int j = 0; j < nx; j++)
{
int cur_ele = ic[i * nx + j];
printf("%d ", cur_ele);
}
printf("\n");
}
printf("\n");
}
/// <summary>
///
/// </summary>
/// <param name="a">全局内存中是线性存储的</param>
/// <param name="nx">col</param>
/// <param name="ny"></param>
/// <returns></returns>
__global__ void printThreadIdx(int* a, const int nx, const int ny)
{
// 矩阵行列
int ix = threadIdx.x + blockIdx.x * blockDim.x;
int iy = threadIdx.y + blockIdx.y * blockDim.y;
// 全局索引
unsigned int idx = iy * nx + ix; // 前面有iy行,每行有nx个数。
printf("thread_idx (%d, %d) block_idx (%d, %d) coordinate (%d, %d) global index %d val %d\n",
threadIdx.x, threadIdx.y, blockIdx.x, blockIdx.y, ix, iy, idx, a[idx]
);
}
int main(void)
{
// get device info
int device = 0;
cudaDeviceProp deviceProp;
CHECK(cudaGetDeviceProperties(&deviceProp, device));
printf("Using device: %d %s", device, deviceProp.name); // 卡号0的显卡名称。
CHECK(cudaSetDevice(device)); // 设置显卡号
// set matrix dimension
int nx = 8, ny =6, nxy = nx * ny;
int nBytes = nxy * sizeof(int);
// malloc host memory
int* h_a;
h_a = (int*)malloc(nBytes);
// init data
initiaInt(h_a, nxy);
printMatrix(h_a, nx, ny);
// malloc device memory
int* d_Mat_a;
cudaMalloc((void**)&d_Mat_a, nBytes);
// transfer data from host to device
cudaMemcpy(d_Mat_a, h_a, nBytes, cudaMemcpyHostToDevice);
// config
dim3 block(4, 2); // 二维线程块(x,y)=(4,2)
dim3 grid((nx+block.x-1) / block.x, (ny+block.y-1)/block.y); // 二维网格(2,3)
// 直接nx/block.x = 8/4=2. (8+4-1)/4=2.
// invoke kernel
printThreadIdx << <grid, block >> > (d_Mat_a, nx, ny);
cudaDeviceSynchronize();
// free memory
cudaFree(d_Mat_a);
free(h_a);
// reset device
cudaDeviceReset();
return 0;
}
可以看到,全局索引值就是矩阵中存储的值。