当前位置:数码通 > 硬件

CUDA学习笔记第1部分:一个基础的CUDA C程序

来源于 数码通 2023-10-04 16:25

来源:AI人工智能初学者
作者:乔叟G

目录

1.CUDA简介
2. GPU架构和CUDA简介
3.CUDA架构
4.开发环境说明及配置
5.启动第一个Hello CUDA程序
5.1.在VS2017中创建NVIDIA CUDA项目
5.2.在VS2017中输入CUDA代码(.cu代码及说明附后)
5.3. VS2017生成并开始执行
参考

1.CUDA简介

计算统一设备架构(CUDA)是由NVIDIA(NVIDIA)开发的非常流行的并行计算平台和编程模型。它仅支持 NVIDIA GPU 卡。 OpenCL 用于为其他类型的 GPU 编写并行代码,例如AMDIntel,但它比 CUDA 更复杂。 CUDA 可以使用简单的编程 API 在图形处理单元 (GPU) 上创建大规模并行应用程序。

使用 C 和C++ 的软件开发人员可以利用 GPU 的强大性能,通过使用 CUDA C 或 C++ 来加速其软件应用程序。用 CUDA 编写的程序与用简单 C 或 C++ 编写的程序类似,只是添加了利用 GPU 并行性所需的关键字。 CUDA 允许程序员指定 CUDA 代码的哪些部分在 CPU 上执行以及哪些部分在 GPU 上执行。

2.GPU架构和CUDA简介

GeFce 256是NVIDIA于1999年开发的第一款GPU。最初仅用于在显示器上渲染高端图形。它们仅用于像素计算。后来,人们意识到,如果可以进行像素计算,那么还可以进行其他数学计算。如今,除了渲染图形图像之外,GPU 还用于许多其他应用程序。这些 GPU 称为通用 GPU (GPGPU)。

CPU的控制硬件复杂,数据计算硬件较少。复杂的控制硬件在性能方面提供了CPU的灵活性和简单的编程接口,但在功耗方面价格昂贵。另一方面,GPU拥有简单的控制硬件和较多的数据计算硬件,使其具备执行并行计算的能力。这种结构使其更加节能。缺点是它有更严格的编程模型。在 GPU 计算的早期,OpenGL 和 DirectX 等图形 API 是与 GPU 交互的唯一方式。对于不熟悉 OpenGL 或 DirectX 的普通程序员来说,这是一项复杂的任务。这导致了 CUDA 编程架构的发展,它提供了一种与 GPU 交互的简单高效的方式。

一般来说,任何硬件架构的性能都是通过延迟和吞吐量来衡量的。延迟是完成给定任务所需的时间,而吞吐量是在给定时间内完成的任务数。这些概念并不矛盾。通常,如果你改善其中一个,另一个也会改善。大多数硬件架构的设计都是为了在一定程度上改善延迟或吞吐量。

同样,普通串行 CPU 旨在优化延迟,而 GPU 旨在优化吞吐量。 CPU 的设计目的是在最短的时间内执行所有指令,而 GPU 的设计目的是在给定时间内执行更多的指令。 GPU 的这种设计理念使其在图像处理和计算机视觉应用中非常有用,这也是本书的目的,因为我们不介意单个像素处理的延迟。我们想要的是在给定时间内处理更多像素,这可以在 GPU 上完成。

综上所述,如果我们想要在相同时钟速度和功耗要求的情况下提高计算性能,那么并行计算就是我们所需要的。 GPU 通过允许许多简单的计算单元并行工作来提供此功能。现在,为了与GPU交互并利用其并行计算能力,我们需要CUDA提供的简单的并行编程架构。

3.CUDA架构

CUDA 架构包含一些专门为 GPU 上的通用计算而设计的功能,而这些功能在早期架构中并不存在。它包括一个统一的 shedder 管道,允许 CUDA 程序对 GPU 芯片 上的所有算术逻辑单元 (ALU) 进行编组。 ALU 的设计还符合 IEEE 浮点单精度和双精度标准,因此可用于通用应用。该指令集还面向通用计算而不是特定于像素的计算。它还允许对内存进行任意读写访问。这些特性使得 CUDA GPU 架构在通用应用程序中非常有用。

所有 GPU 都有许多称为核心的并行处理单元。

在硬件方面,这些内核分为流式处理器和流式多处理器。 GPU 具有这些流式多处理器网格。

在软件方面,CUDA 程序作为一系列并行运行的多线程 (Thread) 执行。每个线程在不同的核心上执行。 GPU可以被认为是多个块的组合,每个块可以执行多个线程。每个块都绑定到 GPU 上的不同流式多处理器。

CUDA 程序员不知道如何在块多处理器和流式多处理器之间进行映射,但调度程序知道并执行映射。来自同一块的线程可以 相互通信 。 GPU 具有分层内存结构,可处理一个块内和多个块内的线程之间的通信。这将在下面的章节中详细讨论。

作为一名程序员,您会好奇 CUDA 中的编程模型是什么,以及代码如何理解它应该在 CPU 还是 GPU 上执行。我们将 CPU 及其内存称为主机,将 GPU 及其内存称为设备。 CUDA代码包含主机和设备的代码。主机代码由普通的 C 或 C++ 编译器在 CPU 上编译,设备代码由 GPU 编译器在 GPU 上编译。主机代码通过所谓的内核调用来调用设备代码。它将在设备上并行启动多个线程。由程序员决定在设备上启动多少个线程。

现在,您可能会问此设备代码与普通 C 代码有何不同。答案是它与普通的串行C 代码类似。只是这段代码是在大量的核心上并行执行的。但是,要使此代码正常工作,它需要设备视频内存上的数据。因此,在启动线程之前,主机将数据从主机内存复制到设备内存。该线程处理来自设备视频内存的数据并将结果存储在设备视频内存中。最后,该数据被复制回主机内存以进行进一步处理。综上所述,CUDA C程序的开发步骤如下:

1) 为主机和设备显存中的数据分配内存。
2) 将数据从主机内存复制到设备视频内存。
3) 通过指定并行度来启动内核。
4)所有线程完成后,将数据从设备内存复制回主机内存。
5) 释放主机和设备上使用的所有内存。

4.开发环境说明及配置

先决条件:

1. 电脑有支持CUDA的GPU(一般独立显卡就够了,但最好不要旧版本);
2、NVIDIA显卡驱动;
3、标准C编译器;
4.CUDA开发工具包。

windows10下cuda工具包的安装:

1.MicroSoft Visio Studio 2017的安装(也可以是其他版本,笔者使用的是2017)
2. 下载cuda10.1安装包(最新的为10.2);
3、直接点击.exe文件安装,选择自定义安装,勾选所有选项;
4. 配置CUDA系统环境变量(配置系统环境变量与配置深度学习环境相同)。

5.启动第一个Hello CUDA程序

5.1.在VS2017中创建NVIDIA CUDA项目

步骤如下:

1) 打开 Microsoft Visual Studio。
2) 输入文件|新建|项目。
3) 选择NVIDIA|CUDA 10.1|CUDA 10.1运行time。
4) 为项目自定义一个名称,然后单击“确定”按钮。
5) 它将创建一个带有 m.smtshopping.cn 示例文件的项目。现在双击打开该文件。
6) 从文件中删除现有代码并写入您之前编写的代码。
7) 在Build选项卡中选择build进行编译,按快捷键Ctrl+F5调试代码。

5.2.在VS2017中输入CUDA代码

#包括

与 C 编程的区别:

1) 名为 myfirstkernel 的空函数,带有前缀 /_/_global/_/_

2)使用<<1,1>>>调用myfirstkernel函数

/_/_global/_/_ 是 CUDA C 添加到标准 C 的限定符,它告诉编译器该限定符后面的函数定义应该在设备上运行,而不是在主机上运行。在前面的代码中,myfirstkernel 将在设备而不是主机上运行,​​但是在这段代码中,它是空的。

那么,main函数会在哪里运行呢? NVCC编译器会将此函数提供给C编译器,因为它没有用global关键字修饰,因此main函数将在主机上运行。

代码中的第二个区别是对空 myfirstkernel 函数的调用有一些尖括号和一个数值。这是 CUDA C 技巧:从主机代码调用设备代码。这称为内核调用。内核调用的细节将在后面的章节中解释。尖括号内的值表示我们要在运行时从主机传递到设备的参数。基本上,它表示将在设备上并行运行的块数和线程数。因此,在这段代码中,<<<1,1>>>意味着myfirstkernel将在设备上的一个块和一个线程或块上运行。尽管这不是设备资源的最佳利用方式,但了解在主机上执行的代码和在设备上执行的代码之间的区别是一个很好的起点。

让我们重新审视并修改“Hello, CUDA!”代码,以便 myfirstkernel 函数将在只有一个块和一个线程或块的设备上运行。它将通过一个名为 kernel launch 的方法从 main 函数内的主机代码启动。

5.3. VS2017生成并开始执行

审稿编辑黄浩宇

-->
登录后参与评论