第一章: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和操作系统之间的桥梁。安装方法:
- 去英伟达官网下载对应型号的驱动
- 或者用系统自带的包管理器(Linux下推荐)
- 安装完成后重启,运行
nvidia-smi验证
注意:驱动版本要和CUDA Toolkit版本匹配。比如CUDA 11.x需要驱动版本≥450.80.02。不匹配的话,程序会报错。我曾经因为这个折腾了一下午,后来学乖了,每次装之前先查兼容性表。
1.3.3 安装CUDA Toolkit
CUDA Toolkit包含了编译器(nvcc)、库文件、调试工具等。安装步骤:
- 从英伟达官网下载CUDA Toolkit安装包
- 选择对应操作系统和架构的版本
- 运行安装程序(Linux下推荐runfile方式,更可控)
- 配置环境变量
配置环境变量这一步很多人会忘。在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计算,可以不装。但做深度学习的话,必须装。
安装步骤:
- 去英伟达开发者网站注册并下载cuDNN(需要注册账号)
- 选择与CUDA Toolkit版本匹配的cuDNN版本
- 解压后把文件复制到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 本章小结
这一章我们做了三件事:
- 理解了为什么需要GPU计算——说白了就是「人多力量大」
- 了解了CUDA的基本架构——Host、Device、Kernel、Thread、Block、Grid
- 搭建了完整的开发环境——驱动、CUDA Toolkit、cuDNN
我个人觉得,环境搭建是最容易劝退人的一步。如果你卡住了,别灰心。我当年装CUDA Toolkit装了四遍才成功。后来发现是环境变量写错了路径。嗯,这种坑踩过一次就记住了。
下一章,我们会深入讲解CUDA的线程模型和内存模型。到时候你会看到,GPU编程真正的难点不在于语法,而在于怎么让成千上万个线程高效协作。
准备好了吗?我们第二章见。
课后练习:
- 运行上面的Hello World程序,把
<<<1, 5>>>改成<<<2, 5>>>,观察输出有什么变化 - 试试把
threadIdx.x改成blockIdx.x,看看输出什么 - 用
nvidia-smi查看你的显卡信息,记下型号和显存大小