概述
1,CUDA架构
(1)一个GPU包含多个多核处理器;
(2)一个多核处理器包含多个线程处理器
(3)线程处理器是最基本的计算单元,有自己的局部内存和寄存器
2,thread, block, grid含义
(1)thread对应硬件上的线程处理器;
(2)grid对应一块GPU
(3)block是由一个多核处理器中的多个线程处理器组合而成;
(4)一个多核处理器可以划分为多个block;
(5)执行一个指令时,一个执行单元线程束(warp)会并行执行32个thread,所以在我们划分blocksize的时候,一般都会设置成32的倍数
3,CUDA编程
(1)在GPU上分配显存,将CPU上的数据拷贝到显存上
(2)利用核函数完成GPU显存中数据的计算
(3)将显存中的计算结果拷贝回CPU内存中
计算矩阵加法:C = A + B,设A B为一维矩阵,长度为n
//核函数(即在GPU中执行的函数/用__global__申明)
这里再解释一下
threadIdx表示第几个线程,范围是blocksize(blockDim);
blockIdx就是第几个block,范围是gridsize;
__global__
void vecAddKernel(float* A_d, float* B_d, float* C_d, int n)
{
int i = threadIdx.x + blockDim.x * blockIdx.x; //计算线程ID
if (i < n) C_d[i] = A_d[i] + B_d[i]; //筛选ID小于n的线程,即例如线程1计算C_d[1] = A_d[1] + B_d[1]
}
如何调用:
//划分GPU的block和Grid
int threadPerBlock = 256; //一个warp大小为32,一般设置为32的倍数
int blockPerGrid = (n + threadPerBlock - 1)/threadPerBlock; //根据划分的blocksize计算gridsize
//调用核函数
vecAddKernel <<< blockPerGrid, threadPerBlock >>> (da, db, dc, n);
上面的blockPerGrid, threadPerBlock分别对应Gridsize,blocksize(blockDim)
当维度为二维时:
//核函数(传入显存ABC以及维度信息MNK)
__global__ void multiplicateMatrix(float *array_A, float *array_B, float *array_C, int M_p, int K_p, int N_p)
{
//这里我们划分的lblock和grid是二维的,分别计算线程的二维索引(x方向和y方向的索引)
int ix = threadIdx.x + blockDim.x*blockIdx.x;//row number,
int iy = threadIdx.y + blockDim.y*blockIdx.y;//col number
if (ix < N_p && iy < M_p) //筛选线程,每个线程计算C中的一个元素,线程的xy索引与C的元素位置索引对应
{
float sum = 0;
for (int k = 0; k < K_p; k++) //C中的某个元素为A中对应行和B中对应列向量的乘积和。
{
sum += array_A[iy*K_p + k] * array_B[k*N_p + ix];
}
array_C[iy*N_p + ix] = sum;
}
}
//划分GPU的block和Grid
int dimx = 2;
int dimy = 2;
dim3 block(dimx, dimy);
dim3 grid((M + block.x - 1) / block.x, (N + block.y - 1) / block.y);
//调用核函数
multiplicateMatrix<<<grid,block>>> (d_A, d_B, d_C, M, K, N);
疑问:这里dim3 block(2, 2)为什么不需要时32的倍数
4,CUDA进阶加速策略
(1)利用共享内存加速访存
线程寄存器:1周期
Block共享内存:5周期
Grid全局内存:500周期
Grid常量内存:5周期
(2)利用stream加速大批量文件IO读写耗时
当我们使用GPU进行计算时,我们可以主动开启多个stream流,类似CPU开启多线程。我们可以将大批量文件读写分给多个流去执行,或者用不同的流分别计算不同的核函数。开启的多个流之间是异步的,流与CPU端的计算也是异步的。所以我们需要注意加上同步操作。
值得注意的是,受PCIe总线带宽的限制,当一个流在进行读写操作时,另外一个流不能同时进行读写操作,但是其他流可以进行数值计算任务。这个有点类似与CPU中的流水线机制。
(3)调用cuBLAS库API进行矩阵计算
cuBLAS是一个BLAS的实现,允许用户使用NVIDIA的GPU的计算资源。使用cuBLAS 的时候,应用程序应该分配矩阵或向量所需的GPU内存空间,并加载数据,调用所需的cuBLAS函数,然后从GPU的内存空间上传计算结果至主机,cuBLAS API也提供一些帮助函数来写或者读取数据从GPU中。
官方文档:https://docs.nvidia.com/cuda/cublas/index.html
最后
以上就是眯眯眼小虾米为你收集整理的【CUDA入门笔记】概述的全部内容,希望文章能够帮你解决【CUDA入门笔记】概述所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复