第一章:CUDA入门——GPU计算概述、CUDA架构简介、开发环境搭建

各位同学,欢迎来到《英伟达GPU编程与CUDA优化指南》的第一章。

说实话,每次开始讲这门课,我都会想起自己第一次接触CUDA时的情景。那时候我还在做图像处理,CPU算不动了,导师扔给我一块GTX 280,说:「你试试这个。」我连CUDA是什么都不知道,硬着头皮啃了三天文档。嗯,那三天真是又痛苦又兴奋。痛苦的是啥都看不懂,兴奋的是——原来代码可以跑这么快。

今天,我们就从零开始,把GPU计算这层窗户纸捅破。

1.1 为什么需要GPU计算?

先问一个问题:你写过一个需要跑好几个小时的程序吗?

我遇到过。有一次做视频编码的算法优化,CPU上跑一帧要200毫秒,一秒钟只能处理5帧。客户要求实时处理30帧。怎么办?换更强的CPU?成本太高了。后来我把核心算法移植到GPU上,一帧只用了8毫秒。你想想看,这差距有多大。

GPU计算的核心思想很简单:

  • CPU:几个很强的大核,适合处理复杂、串行的任务
  • GPU:成千上万个简单的小核,适合处理大量可并行的简单任务

说白了,CPU是几个博士,GPU是一万个小学生。让博士去算一万次1+1,太浪费了。让小学生去干,又快又便宜。

核心概念:GPU计算不是取代CPU,而是让CPU和GPU协同工作。CPU负责控制逻辑和串行部分,GPU负责大规模并行计算。

1.2 CUDA架构简介

CUDA是英伟达推出的并行计算平台和编程模型。我习惯把它理解成「让GPU听你指挥的翻译官」。

CUDA架构有几个关键概念,你得先记住:

概念 类比 说明
Host 指挥官(CPU) 负责调度、控制、数据搬运
Device 工人(GPU) 负责执行大规模并行计算
Kernel 施工图纸 在GPU上运行的函数
Thread 单个工人 最小的执行单元
Block 班组 一组线程,可以协作
Grid 整个工地 所有Block的集合

我记得第一次看到Thread、Block、Grid这三层结构时,觉得好复杂。后来我做了个比喻:

  • Grid = 整个建筑工地
  • Block = 每个楼层的施工队
  • Thread = 施工队里的每个工人

每个工人干自己的活,但同楼层的工人可以互相借工具(共享内存)。不同楼层的工人不能直接交流。这个比喻我一直用到现在,很管用。

小技巧:刚开始学CUDA,别纠结于Block和Thread的精确数量。先记住「线程越多,并行度越高」,但也不是越多越好——硬件资源有限,线程太多反而会排队。

1.3 CUDA开发环境搭建

好,理论说完了,咱们来动手。搭建环境是第一步,也是很多人卡住的地方。我曾经帮一个同事调了两天环境,最后发现是他显卡太老,不支持CUDA。所以第一步,先确认你的硬件。

1.3.1 检查硬件

你需要一块英伟达的独立显卡。怎么查?

  • Windows:设备管理器 → 显示适配器
  • Linux:运行 lspci | grep -i nvidia
  • 或者直接运行 nvidia-smi(装了驱动后)

我建议至少是GTX 900系列以上,或者RTX系列。太老的卡(比如GT 710)虽然也能跑,但性能太差,学起来没意思。

1.3.2 安装NVIDIA驱动

驱动是GPU和操作系统之间的桥梁。安装方法:

  1. 去英伟达官网下载对应型号的驱动
  2. 或者用系统自带的包管理器(Linux下推荐)
  3. 安装完成后重启,运行 nvidia-smi 验证

注意:驱动版本要和CUDA Toolkit版本匹配。比如CUDA 11.x需要驱动版本≥450.80.02。不匹配的话,程序会报错。我曾经因为这个折腾了一下午,后来学乖了,每次装之前先查兼容性表。

1.3.3 安装CUDA Toolkit

CUDA Toolkit包含了编译器(nvcc)、库文件、调试工具等。安装步骤:

  1. 从英伟达官网下载CUDA Toolkit安装包
  2. 选择对应操作系统和架构的版本
  3. 运行安装程序(Linux下推荐runfile方式,更可控)
  4. 配置环境变量

配置环境变量这一步很多人会忘。在Linux下,你需要在 ~/.bashrc 里加上:

export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH

然后运行 source ~/.bashrc 使其生效。

验证安装:

nvcc --version

如果能看到版本号,恭喜你,CUDA Toolkit装好了。

1.3.4 安装cuDNN

cuDNN是英伟达为深度学习优化的加速库。如果你只是做通用GPU计算,可以不装。但做深度学习的话,必须装。

安装步骤:

  1. 去英伟达开发者网站注册并下载cuDNN(需要注册账号)
  2. 选择与CUDA Toolkit版本匹配的cuDNN版本
  3. 解压后把文件复制到CUDA安装目录

具体命令:

tar -xzvf cudnn-linux-x86_64-8.x.x.x_cuda11.x-archive.tar.xz
sudo cp cudnn-*-archive/include/cudnn*.h /usr/local/cuda/include
sudo cp -P cudnn-*-archive/lib/libcudnn* /usr/local/cuda/lib64
sudo chmod a+r /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*

验证cuDNN:

cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2

个人经验:我建议初学者先装CUDA Toolkit,跑通第一个程序,再装cuDNN。一步到位容易出问题,出了问题你都不知道是哪个环节错了。

1.4 第一个CUDA程序

环境搭好了,我们来写个Hello World。别小看这个程序,它能验证你的整个环境是否正常。

#include <stdio.h>

__global__ void hello_from_gpu() {
    printf("Hello from GPU thread %d\n", threadIdx.x);
}

int main() {
    printf("Hello from CPU\n");
    hello_from_gpu<<<1, 5>>>();
    cudaDeviceSynchronize();
    return 0;
}

编译运行:

nvcc hello.cu -o hello
./hello

如果看到输出:

Hello from CPU
Hello from GPU thread 0
Hello from GPU thread 1
Hello from GPU thread 2
Hello from GPU thread 3
Hello from GPU thread 4

那就说明你的CUDA环境完全OK了。

这里解释一下代码:

  • __global__ 表示这个函数在GPU上运行
  • <<<1, 5>>> 表示启动1个Block,每个Block有5个线程
  • threadIdx.x 是每个线程的编号,从0开始
  • cudaDeviceSynchronize() 等待GPU执行完毕

你想想看,5个线程同时打印,顺序可能乱,但每个线程都执行了。这就是并行的魅力。

1.5 本章小结

这一章我们做了三件事:

  1. 理解了为什么需要GPU计算——说白了就是「人多力量大」
  2. 了解了CUDA的基本架构——Host、Device、Kernel、Thread、Block、Grid
  3. 搭建了完整的开发环境——驱动、CUDA Toolkit、cuDNN

我个人觉得,环境搭建是最容易劝退人的一步。如果你卡住了,别灰心。我当年装CUDA Toolkit装了四遍才成功。后来发现是环境变量写错了路径。嗯,这种坑踩过一次就记住了。

下一章,我们会深入讲解CUDA的线程模型和内存模型。到时候你会看到,GPU编程真正的难点不在于语法,而在于怎么让成千上万个线程高效协作。

准备好了吗?我们第二章见。

课后练习:

  1. 运行上面的Hello World程序,把 <<<1, 5>>> 改成 <<<2, 5>>>,观察输出有什么变化
  2. 试试把 threadIdx.x 改成 blockIdx.x,看看输出什么
  3. nvidia-smi 查看你的显卡信息,记下型号和显存大小