GPU架构基础:GPU与CPU的区别、核心架构与内存层次

大家好,我是你们这门课的老师。今天咱们聊聊GPU的架构基础。说实话,很多初学者一上来就写CUDA代码,结果性能惨不忍睹。为什么?因为你不了解GPU这个“怪物”的脾气。我当年刚接触GPU编程时,也踩过不少坑。今天就把这些经验分享给你。

一、GPU与CPU:两个世界的“打工人”

CPU和GPU,说白了就是两种完全不同的“打工人”。

CPU是那种全能型选手。它能处理复杂的逻辑,能分支预测,能乱序执行。它就像个博士,什么都会,但一次只能处理几件事。CPU的核心数少(通常4-16个),但每个核心都极其强大。

GPU呢?它就是个“搬砖工”。成千上万个简单核心,每个核心能力有限,但胜在人多。GPU适合做那些“简单、重复、可并行”的工作。比如矩阵乘法、图像处理、神经网络训练。

核心区别一句话总结:

  • CPU:延迟优化(尽快完成单个任务)
  • GPU:吞吐量优化(同时完成大量任务)

我举个例子你就明白了。假设你要搬1000块砖:

  • CPU:派1个大力士,一次搬10块,来回100趟
  • GPU:派1000个普通人,每人搬1块,1趟搞定

这就是为什么GPU在并行计算领域这么吃香。但注意,不是所有任务都适合GPU。你想想看,如果砖块形状各异,需要判断怎么搬,那大力士反而更灵活。

特性 CPU GPU
核心数 4-16个 数千个
缓存 大(MB级) 小(KB级)
控制单元 复杂 简单
适合任务 串行、复杂逻辑 并行、数据密集
内存带宽 低 极高

我的经验:判断一个任务是否适合GPU,就看它能不能拆成“互相独立的小任务”。如果任务之间有大量依赖,那GPU反而会拖慢速度。我曾经把一个递归算法硬搬到GPU上,结果比CPU还慢10倍...嗯,那是个惨痛的教训。

二、GPU核心架构:SM、SP、Warp

好,现在咱们深入GPU内部。我习惯把GPU的架构想象成一个“工厂流水线”。

1. SM(Streaming Multiprocessor,流式多处理器)

SM是GPU的核心计算单元。你可以把它理解成一个“车间”。每个SM内部包含多个SP(简单核心)、共享内存、寄存器等资源。一个GPU通常有几十到上百个SM。

2. SP(Streaming Processor,流式处理器)

SP就是那个“搬砖工”。每个SP只能执行简单的算术运算。但胜在数量多——一个SM里通常有几十到上百个SP。

3. Warp(线程束)

这是GPU最核心的概念之一。Warp是GPU调度和执行的基本单位,通常包含32个线程。这32个线程必须执行相同的指令,但可以处理不同的数据。这就是所谓的SIMT(单指令多线程)模型。

记住这个数字:32。在CUDA编程中,很多优化都跟这个数字有关。比如block大小最好设成32的倍数,否则会有线程浪费。

为什么会这样?因为GPU的硬件设计就是一次取一条指令,然后广播给Warp里的所有线程。如果线程执行不同的分支(比如if-else),那就会发生“分支发散”,部分线程被“冻结”,性能大打折扣。

避坑指南:我曾经写过一个核函数,里面有个if判断,结果一半线程走true,一半走false。性能直接腰斩。后来我把数据重新排列,让同一个Warp里的线程走同一个分支,性能立马翻倍。记住:尽量让同一个Warp里的线程执行相同的指令路径。

三、GPU内存层次结构

内存是GPU编程的“命门”。很多性能问题,说白了就是内存访问没搞好。GPU的内存层次从快到慢、从近到远依次是:

1. 寄存器(Register)

最快,但每个线程只有有限的几个。通常每个线程有几十到几百个寄存器。如果寄存器不够用,数据会被“溢出”到本地内存,速度骤降。

2. 共享内存(Shared Memory)

位于SM内部,速度很快(比全局内存快100倍左右)。但容量有限,通常每个SM只有几十KB。共享内存是同一个Block内所有线程共享的,常用于线程间通信和数据复用。

我的习惯:只要数据会被多次访问,我就尽量把它先搬到共享内存里。比如矩阵乘法,我会把子矩阵先加载到共享内存,然后让线程反复读取。这样能减少对全局内存的访问次数,性能提升非常明显。

3. 本地内存(Local Memory)

听起来像“本地”,其实它物理上在全局内存里。只是每个线程私有的。当寄存器不够用,或者访问数组时索引不是常量,编译器就会把数据放到本地内存。速度很慢,尽量避免。

4. 全局内存(Global Memory)

最大的内存空间(GB级),但也是最慢的。所有线程都能访问。访问延迟高达几百个时钟周期。优化全局内存访问是CUDA性能优化的核心。

内存类型 位置 速度 容量 作用域
寄存器 SM内部 最快(1周期) 几十个/线程 线程私有
共享内存 SM内部 快(~5周期) 几十KB/SM Block内共享
本地内存 全局内存 慢(~500周期) 受全局内存限制 线程私有
全局内存 显存 最慢(~500周期) GB级 所有线程

重要提醒:全局内存访问要尽量“合并”。什么意思?就是同一个Warp里的32个线程,最好访问连续的内存地址。这样GPU可以把多次访问合并成一次大的内存事务。如果访问是随机的,那性能会惨不忍睹。我见过有人写代码时没注意这个,结果全局内存带宽利用率只有5%。

四、知识体系总览

下面这张图是我自己画的,帮你理清本章的知识结构:

GPU架构基础知识体系 CPU vs GPU • CPU:延迟优化 • GPU:吞吐量优化 • 核心数差异巨大 • 缓存策略不同 • 适合任务类型不同 GPU核心架构 • SM(流式多处理器) • SP(流式处理器) • Warp(线程束,32线程) • SIMT执行模型 • 分支发散问题 内存层次结构 • 寄存器(最快,线程私有) • 共享内存(快,Block共享) • 本地内存(慢,线程私有) • 全局内存(最慢,所有线程) • 访问合并优化 核心要点 理解GPU的并行本质 → 掌握Warp调度机制 → 优化内存访问模式 实践建议 • Block大小设为32倍数 • 避免Warp内分支发散 • 优先使用共享内存 常见陷阱 • 寄存器溢出导致性能下降 • 全局内存随机访问 • 忽略内存合并 性能指标 • 占用率(Occupancy) • 内存带宽利用率 • 计算吞吐量

这张图把本章的核心内容都串起来了。你仔细看看,会发现GPU架构其实是个“系统工程”——从宏观的CPU/GPU对比,到微观的Warp调度,再到内存层次优化,环环相扣。

好了,这一章的内容就到这里。记住我反复强调的那句话:理解硬件,才能写出高效的CUDA代码。下一章我们会深入CUDA编程模型,到时候你会看到这些架构知识是如何落实到代码里的。

想要更多资料,联系可可