美文网首页
CUDA编程学习笔记

CUDA编程学习笔记

作者: Mr_Stark的小提莫 | 来源:发表于2020-08-10 18:47 被阅读0次

    CUDA:Compute Unified Device Architecture,是由NVIDIA所推出的一种集成技术,允许使用标准C来进行GPU代码编程,最终转为PTX汇编代码。


    CPU与GPU

    GPU可以看作是CPU的协助处理器,使用GPU实际指的是基于CPU+GPU的异构计算架构。通过PCle总线连接,CPU端成为Host端,GPU端称为Device端。

    基于CPU+GPU的异构计算架构

    GPU适合数据并行的计算密集型任务,如大型矩阵运算,而CPU的运算核心较少,但是其可以实现复杂的逻辑运算,因此其适合控制密集型任务。此外,CPU上的线程是重量级的,上下文切换开销大,但是GPU由于存在很多核心,其线程是轻量级的。因此,基于CPU+GPU的异构计算平台可以优势互补,CPU负责处理逻辑复杂的串行程序,而GPU重点处理数据密集型的并行计算程序。


    CUDA程序执行流程

    1、分配host内存,并进行数据初始化;

    2、分配device内存,并从host将数据拷贝到device上;

    3、调用CUDA kernel在device上完成指定的运算;(kernel是在device上线程中并行执行的函数,核函数用__global__符号声明,在调用时需要用<<<grid, block>>>来指定kernel要执行的线程数量,在CUDA中,每一个线程都要执行核函数,并且每个线程会分配一个唯一的线程号thread ID,这个ID值可以通过核函数的内置变量threadIdx来获得。)

    4、将device上的运算结果拷贝到host上;

    5、释放device和host上分配的内存。

    CUDA函数类型限定词

            1)__global__:在device上执行,从host中调用(一些特定的GPU也可以从device上调用),返回类型必须是void,不支持可变参数参数,不能成为类成员函数。注意用__global__定义的kernel是异步的,这意味着host不会等待kernel执行完就执行下一步。

            2)__device__:在device上执行,单仅可以从device中调用,不可以和__global__同时用。

            3)__host__:在host上执行,仅可以从host上调用,一般省略不写,不可以和__global__同时用,但可和__device__,此时函数会在device和host都编译。

    Kernel线程结构

    kernel在device上执行时实际上是启动很多线程,一个kernel所启动的所有线程称为一个网格(grid),同一个网格上的线程共享相同的全局内存空间,grid是线程结构的第一层次,而网格又可以分为很多线程块(block),一个线程块里面包含很多线程,这是第二个层次。grid和block都是定义为dim3类型的变量,dim3可以看成是包含三个无符号整数(x,y,z)成员的结构体变量,在定义时,缺省值初始化为1。因此grid和block可以灵活地定义为1-dim,2-dim以及3-dim结构,对于图中结构(主要水平方向为x轴),定义的grid和block如下所示,kernel在调用时也必须通过执行配置<<<grid, block>>>来指定kernel所使用的线程数及结构。

    Kernel线程结构

    一个线程需要两个内置的坐标变量(blockIdx,threadIdx)来唯一标识,它们都是dim3类型变量,其中blockIdx指明线程所在grid中的位置,而threaIdx指明线程所在block中的位置。以Thread(1, 1)为例:

            threadIdx.x = 1           threadIdx.y = 1

            blockIdx.x = 1             blockIdx.y =1

    测试GPU硬件配置

    查看GPU配置

    CUDA内存模型

    每个线程有自己的私有本地内存(Local Memory),而每个线程块有包含共享内存(Shared Memory),可以被线程块中所有线程共享,其生命周期与线程块一致。此外,所有的线程都可以访问全局内存(Global Memory)。还可以访问一些只读内存块:常量内存(Constant Memory)和纹理内存(Texture Memory)。

    分配托管内存 

    分配托管内存 使用统一内存更简洁了,由于托管内存自动进行数据传输,这里要用cudaDeviceSynchronize()函数保证device和host同步,这样后面才可以正确访问kernel计算的结果。

    实例:矩阵加法

    利用上图2-dim结构实现两个矩阵的加法,每个线程负责处理每个位置的两个元素相加,代码如下所示。线程块大小为(16, 16),然后将N*N大小的矩阵均分为不同的线程块来执行加法运算。

    矩阵加法

    实例:矩阵乘法

    设输入矩阵为 

     和 

     ,要得到 

     。实现思路是每个线程计算 

     的一个元素值 

     ,对于矩阵运算,应该选用grid和block为2-D的。首先定义矩阵的结构体:

    nvprof工具

    通过命令nvprof cuda9.exe可以得到kernel的运行情况,


    参考资料

    CUDA编程入门极简教程 - 知乎

    相关文章

      网友评论

          本文标题:CUDA编程学习笔记

          本文链接:https://www.haomeiwen.com/subject/eoiddktx.html