CUDA是一种通用的并行计算平台和编程模型,是在C语言上扩展的。借助于CUDA,你可以像编写C语言程序一样实现并行算法。你可以在NIVDIA的GPU平台上用CUDA为多种系统编写应用程序,范围从嵌入式设备、平板电脑、笔记本电脑、台式机工作站到HPC集群。在CUDA编程平台中,GPU并不是一个独立运行的计算平台,而需要与CPU协同工作,可以看成是CPU的协处理器,因此当我们在说GPU并行计算时,其实是指的基于CPU+GPU的异构计算架构。在异构计算架构中,GPU与CPU通过PCIe总线连接在一起来协同工作,CPU所在位置称为为主机端(host),而GPU所在位置称为设备端(device)。
多层次的并行性设计是架构设计的驱动力。在应用程序中有两种基本的并行类型。
CUDA编程非常适合解决数据并行计算的问题。本书的重点便是如何使用CUDA编程 解决数据并行问题。
弗林分类法(Flynn’s Taxonomy)
计算机架构也能根据内存组织方式进行进一步划分
要么是与同一个物理内存相关联
要么共用一个低延迟的链路(如PCIExpress或PCIe)
多核架构已经永久地取代了单核架构
多线程、 MIMD(多指令多数据)、SIMD(单指令多数据),以及指令级并行。
NVIDIA公司称这 种架构为SIMT(单指令多线程)
“众核”(many-core)通常是指有很多核心(几十或几百个)的多核架构
GPU代表了一种众核架构,几乎包括了前文描述的所有并行结构:
这种系统常被称作集群
分布式内存的多节点系统
共享内存的多处理器系统
GPU核心和CPU核心
GPU指的是离散的设备从同构系统到异构系统的转变是高性能计算 史上的一个里程碑。
同构计算使用的是同一架构下的一个或多个处理器来执行一个应用。
而异构计算则使用一个处理器架构来执行一个应用,为任务选择适合它的架构,使其最终对性能有所改进。
一个典型的异构计算节点
一个异构应用包括两个部分
在计算密集型应用中,往往有很多并行数据的程序段。
GPU就是用来提高这些并行数据的执行速度的。
在设备端加载计算密集型任务之前,CPU代码负责管理设备端的环境、代码和数据。
主机代码(CPU上运行)
设备代码(GPU上运行)
NVIDIA公司的GPU计算平台
描述GPU容量的两个重要特征
两种不同的指标来评估GPU的性能
计算能力
GPU计算并不是要取代CPU计算
Tip:这一段我就不写了,本章节的主要内容用一张图即可概括
CUDA提供了两层API来管理GPU设备和组织线程。
这两种API是相互排斥的,你必须使用两者之一,从两者中混合函数调用是不可能的。
CUDA驱动API
CUDA运行时API
也就是说Runtime api 可以看作是由Driver api 封装而成的
一个CUDA程序包含了以下两个部分的混合。
一个典型的CUDA编程结构包括5个主要步骤
数据局部性在并行编程中是一个非常重要的概念。
CUDA中有内存层次和线程层次的概念
内存层次结构
线程层次结构
例如:
在CUDA编程模型中使用的共享内存(一个特殊的内存)。
共享内存可以视为 一个被软件管理的高速缓存,通过为主内存节省带宽来大幅度提高运行速度。
有了共享内存,你可以直接控制代码的数据局部性。
编译环境:本代码将使用nvcc
编译器来编译,你可以使用以下命令来检查CUDA是否正确安装:
1 | $ which nvcc |
不妨先写一个cuda C程序,命名为helloFromGPU
,用它来输出字符串 “Hello World from GPU!”
1 | ========================== 代码清单 1-1 Hello World from GPU (hello.cu) ========================== |
在linux终端下使用以下命令进行编译hello.cu
,然后执行程序得到
1 | $ nvcc -arch sm_20 hello.cu -o hello |
在上面的代码中,cudaDeviceReset
表示重置当前线程所关联过的当前设备的所有资源;修饰符__global__
告诉编译器这是一个内核函数,它将从CPU中调用,然后在GPU上执行,在CPU上通过下面的代码启动内核函数
1 | helloFromGPU <<<1, 10>>>(); |
三重尖号意味着从主线程到端代码的调用。1和10分别表示有1个块区域和10个线程,后续会作相关介绍。