异构计算与CUDA异构计算异构架构计算能力异构计算范例CUDA一种异构计算平台运行时API与驱动API用GPU输出Hello WorldCUDA编程结构异构计算异构计算可以理解为让 CPU 和 GPU 协同工作来完成计算任务。CPU 是通用处理器核心数量较少但每个核心能力强适合处理复杂逻辑、任务调度、分支判断和串行计算GPU 则拥有大量计算核心单个核心相对简单但非常擅长同时处理大量相同或相似的计算任务比如矩阵运算、图像处理、深度学习中的大规模并行计算等。在异构计算中通常由 CPU 负责程序的整体控制、数据准备和任务分发再把适合并行处理的部分交给 GPU 执行GPU 计算完成后再把结果返回给 CPU。这样可以充分发挥 CPU 的控制能力和 GPU 的并行计算能力从而提高程序的运行速度和计算效率。比如在深度学习训练中CPU 负责读取数据、调度训练流程而 GPU 负责大量矩阵乘法和张量运算这就是典型的 CPUGPU 异构计算。异构架构异构架构指的是在同一个计算系统中同时使用不同类型的处理器来协同完成任务。这里主要指 CPU GPU 的架构。CPU 和 GPU 的设计目标不同CPU 更擅长复杂控制逻辑、任务调度、分支判断和串行计算GPU 更擅长大规模并行计算比如矩阵乘法、图像处理、深度学习训练等。异构架构的核心思想就是让 CPU 做它擅长的控制和调度工作把大量重复、可并行的计算交给 GPU 执行从而提高整体计算性能。这张图展示的就是一个典型的 CPU-GPU 异构计算架构。左边是 CPU右边是 GPU中间通过 PCIe Bus 连接。CPU 有比较大的 Control 控制单元说明 CPU 很擅长处理复杂的逻辑控制比如判断、调度、系统调用、程序流程管理等。CPU 也有少量比较强的 ALU也就是算术逻辑单元用来执行计算。下面的 Cache 比较大表示 CPU 依赖缓存来降低访问内存的延迟。最下面是 CPU 侧的 DRAM也就是主机内存。GPU 部分可以看到右边上方是一大片密集的小格子表示 GPU 内部有大量计算单元。图中红框标出的 SM 是 Streaming Multiprocessor可以理解为 GPU 中的一个计算核心组。一个 GPU 里面通常有很多个 SM每个 SM 里又包含很多 CUDA Core / ALU因此 GPU 能同时运行大量线程适合处理大规模并行任务。GPU 下面也有自己的 DRAM通常叫显存比如 GDDR 或 HBM。GPU 计算时主要访问自己的显存而不是直接频繁访问 CPU 的主存。中间的 PCIe Bus 表示 CPU 和 GPU 之间通过 PCIe 总线通信。数据通常需要先从 CPU 内存拷贝到 GPU 显存GPU 完成计算后再把结果从 GPU 显存拷贝回 CPU 内存。这个传输速度比 GPU 内部访问显存慢很多所以在 CUDA 编程中减少 CPU 和 GPU 之间的数据传输非常重要。一个异构应用包含两种以上架构所以代码也包括不止一部分主机代码设备代码衡量GPU计算能力的主要靠下面两种容量特征CUDA核心数量越多越好内存大小越大越好相应的也有计算能力的性能指标:峰值计算能力内存带宽峰值计算性能是用来评估计算容量的一个指标通常定义为每秒能处理的单精度或双 精度浮点运算的数量。峰值性能通常用GFlops每秒十亿次浮点运算或TFlops每秒万亿次浮点运算来表示。内存带宽是从内存中读取或写入数据的比率。内存带宽通常用 GB/s表示。计算能力NVIDIA 的计算能力是 CUDA 用来描述 GPU 硬件架构和功能支持程度的版本号。它决定了这张 GPU 能运行哪些 CUDA 特性但不直接等同于性能高低。真正的性能还要看 SM 数量、CUDA Core 数量、显存带宽、频率、Tensor Core 能力等因素。异构计算范例GPU计算并不是要取代CPU计算。对于特定的程序来说每种计算方法都有它自己的优点。CPU计算适合处理控制密集型任务GPU计算适合处理包含数据并行的计算密集型任务。GPU与CPU结合后能有效提高大规模计算问题的处理速度与性能。低并行逻辑复杂的程序适合用CPU高并行逻辑简单的大数据计算适合GPU因为CPU和GPU的功能互补性导致了CPUGPU的异构并行计算架构的发展这两种处理器的类型能使应用程序获得最佳的运行效果。CPU上的线程通常是重量级的实体。操作系统必须交替线程使用启用或关闭CPU执行 通道以提供多线程处理功能。上下文的切换缓慢且开销大。GPU上的线程是高度轻量级的。在一个典型的系统中会有成千上万的线程排队等待工 作。如果GPU必须等待一组线程执行结束那么它只要调用另一组线程执行其他任务即可。CPU的核被设计用来尽可能减少一个或两个线程运行时间的延迟而GPU的核是用来处理大量并发的、轻量级的线程以最大限度地提高吞吐量。CUDA一种异构计算平台CUDA平台不是单单指软件或者硬件而是建立在Nvidia GPU上的一整套平台并扩展出多语言支持。CUDA提供了两层API来管理GPU设备和组织线程如图所示。驱动API是一种低级API它相对来说较难编程但是它对于在GPU设备使用上提供了更多的控制。运行时API是一个高级API它在驱动API的上层实现。每个运行时API函数都被分解为更多传给驱动API的基本运算。运行时API与驱动API运行时API和驱动API之间没有明显的性能差异。这两种API是相互排斥的你必须使用两者之一从两者中混合函数调用是不可能的。一个CUDA程序包含了以下两个部分的混合在CPU上运行的主机代码在GPU上运行的设备代码NVIDIA的CUDA nvcc编译器在编译过程中将设备代码从主机代码中分离出来。主机代码是标准的C代码使用C编译器进行编译。nvcc 是从LLVM开源编译系统为基础开发的。用GPU输出Hello World用专用扩展名.cu来创建一个源文件。使用CUDA nvcc编译器来编译程序。//hello.cu#includestdio.h__global__voidhello_world(void){printf(GPU: Hello world!\n);}intmain(intargc,char**argv){printf(CPU: Hello world!\n);hello_world1,10();cudaDeviceReset();//if no this line ,it can not output hello world from gpureturn0;}nvcc hello.cu -o hello ./hello 输出 CPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world! GPU: Hello world!__global__:告诉编译器这个函数将会从CPU中调用然后在GPU上执行。hello_world1,10():三重尖括号意味着从主线程到设备端代码的调用。一个内核函数通过一组线程来执行所有线程执行相同的代码。三重尖括号里面的参数是执行配置用来说明使用多少线程来执行内核函数。cudaDeviceRest():用来显式地释放和清空当前进程中与当前设备有关的所有资源。CUDA编程结构一个典型的CUDA编程结构包括5个主要步骤。分配GPU内存。从CPU内存中拷贝数据到GPU内存。调用CUDA内核函数来完成程序指定的运算。将数据从GPU拷回CPU内存。释放GPU内存空间。