CUDA学习2-CPU和GPU的性能优化

基础知识

latency:完成一个指令的耗时

memory latency:从memory获取内存数据等待的时间,是CPU的优化方向

throughput:单位时间内可以执行的指令数,是GPU的优化方向

multi-threading:多线程

CPU Core从内存中读取数据分两种情形(简便起见,忽略多级的Cache)

  • 缓存命中:数据请求时,所需数据已存在于缓存中,可直接读取。
  • 缓存未命中:数据请求时,缓存中没有目标数据,需从下级memory、主存或其他存储层级加载,这个加载是比较耗费时间的,在等待数据加载完成这个等待的时间叫做stall

在这个金字塔中,越往上越靠近处理器,访问数据的速度越快,但是价格越贵

可以看到从不同的层级访问数据的难易程度是无法忽略的差距。

性能优化

CPU instruction pipeline

我们先看一个指令在CPU中是如何执行的

IF(Instruction Fetch): 取指阶段:从内存中读取当前要执行的指令。

ID(Instruction Decode): 译码阶段:解析指令的操作码和操作数地址,明确指令功能。

OF(Operand Fetch): 取操作数阶段:根据译码结果,从寄存器或内存中取出所需操作数。

EX(Execution): 执行阶段:通过 ALU(算术逻辑单元)完成指令规定的运算或操作。

WB(Execution): 写回阶段:将执行结果写回寄存器,供后续指令使用。

没有优化的指令是串行执行的,如下所示

那么流水线CPU instruction pipeline优化后,指令可以并发执行,这样多条指令执行的时间被大大压缩了。

Memory Hierarchy

  1. CPU 发起数据请求,首先查询L1 缓存(离 CPU 核心最近、速度最快、容量最小)。
  2. 若 L1 缓存命中,直接读取数据并返回 CPU,流程结束。
  3. 若 L1 未命中,查询L2 缓存(速度次之、容量大于 L1,通常为核心独享或共享)。
  4. 若 L2 命中,读取数据并同步到 L1 缓存(为后续请求提速),再返回 CPU。
  5. 若 L2 未命中,查询L3 缓存(所有核心共享、容量更大、速度慢于 L1/L2)。
  6. 若 L3 命中,数据同步到 L2 和 L1 缓存后返回 CPU;若 L3 未命中,最终访问主存(容量大、速度最慢)。
  7. 主存中的数据会逐级写入 L3、L2、L1 缓存,再返回 CPU,确保后续同类请求能命中缓存。

|---------|-----------|-------------|--------------|----------------------|
| L1 缓存 | 最快(100%) | 几 KB--几十 KB | 最低(1x) | 核心专属,存储最常访问数据 / 指令 |
| L2 缓存 | 次之(~80%) | 几十 KB--几 MB | 较低(3x--5x) | 补充 L1,部分核心独享或小集群共享 |
| L3 缓存 | 中等(~50%) | 几 MB--几十 MB | 中等(10x--20x) | 全核心共享,承接 L2 未命中请求 |
| 主存(RAM) | 较慢(~10%) | 几十 GB--数 TB | 较高(100x+) | 存储 CPU 未缓存的所有数据 / 程序 |

Pre-fetch

  1. CPU 会分析历史数据访问规律,比如连续地址读取、指令流执行顺序等。
  2. 基于这些规律预判后续可能需要的数据或指令,在 CPU 实际发起请求前主动加载。
  3. 加载路径是从低层级存储(主存或下一级缓存)到高速缓存(如 L1/L2),提前 "备货"。
  • 减少缓存未命中率,避免 CPU 等待主存加载数据的漫长延迟。
  • 让 CPU 执行指令时,所需数据大概率已在缓存中,提升整体运算效率。
  • 适配程序的局部性原理(时间局部性、空间局部性),最大化缓存利用率。

举个例子:

未Pre-fetch

存在Pre-fetch

如果碰到条件的指令怎么办,机器如何Pre-fetch?

Branch-Prediction (CPU专属)

  1. CPU 会基于分支指令的历史执行记录(比如之前多次走哪个分支),预判本次最可能的执行方向。
  2. 提前按预判方向加载并执行后续指令,若预判正确,流水线持续高效运行;若预判错误,丢弃已执行的错误指令,重新加载正确指令(会产生少量延迟)。

关键作用

  • 解决流水线 "断流" 问题:没有分支预测时,CPU 需等待分支指令执行完毕才能确定下一条指令,导致流水线阻塞。
  • 大幅提升 CPU 吞吐量:现代 CPU 分支预测准确率可达 90% 以上,让流水线始终保持高利用率。
  • 适配复杂程序逻辑:满足多分支、循环嵌套等场景的高效执行需求。

举个例子:

无Branch-Prediction

Stall状态下是灰色的

存在无Branch-Prediction

多指令并发执行,当指令1的EX(上图第一行的EX)的执行结果是false,不能执行指令2、3时,只需要撤回就好。

Multi-threading

  1. 线程是进程的最小执行单元,多个线程共享所属进程的内存、文件句柄等资源,创建和销毁的开销远低于进程。
  2. 逻辑上实现 "并行":单核心 CPU 通过时间片轮转(快速切换线程执行)模拟并行;多核心 CPU 可让不同线程在不同核心上真并行执行。
  3. 配合 CPU 调度机制:当一个线程等待 I/O 或资源时,CPU 可切换到其他就绪线程,避免核心闲置。

关键作用

  • 提升程序响应速度:比如软件 UI 操作与后台数据处理并行,避免操作卡顿。
  • 最大化 CPU 利用率:让多核心 CPU 的每个核心都有任务执行,减少资源浪费。
  • 适配多任务场景:支持同一程序同时处理多个请求(如服务器同时响应多个用户)。

举个例子

两个指令存在数据依赖关系,指令2在执行OF前需要等待a的结果写回,所以有两个cycle的等待时间

那么cpu可以在stall时候执行其他的指令使得计算资源不至于被浪费

总结

CPU优化路线有两个方向

减少memory latency

  • cache hierarchy
  • pre-fetch
  • branch prediction

提高throughput

  • pipeline
  • multi-threading

CPU需要处理大量的复杂逻辑运算,所以增加core的带来throughput的收益一般不太高

而没有复杂逻辑运算,单纯大量数据计算的时候,增加core的throughput的收益就很高,所以这类运算就被放在GPU上了,可以说GPU就是为计算而生的。

CPU和GPU架构对比

  1. 设计目标
  • CPU:追求低延迟、高单线程性能,适配复杂多样的任务(如系统调度、逻辑判断、单任务运算)。并行处理threads数量规模数十个。
  • GPU:追求高吞吐量、大规模并行,专注重复且数据独立的任务(如图形渲染、AI 训练、数值计算)。并行处理threads数量规模达上千甚至上万。
  1. 核心与控制单元
  • CPU:核心数量少(常见 4-64 核),每个核心配备完善的控制单元(如分支预测、乱序执行),缓存层级丰富(L1/L2/L3 缓存),擅长复杂指令流处理。
  • GPU:核心数量极多(数千甚至数万流处理器 / CUDA 核心),控制单元简化(弱化分支预测、少乱序执行),缓存容量小且以共享缓存为主,侧重简单指令的批量执行。
  1. 并行能力
  • CPU:支持任务级并行(多线程),适合少量任务的并行处理,单个核心能高效应对复杂逻辑。
  • GPU:支持数据级并行,通过 "SIMT(单指令多线程)" 架构,让大量核心同时执行相同指令、处理不同数据,并行规模远超 CPU。
  1. 内存访问
  • CPU:优先访问高速缓存,缓存命中率对性能影响极大,主存访问延迟低但带宽相对有限。
  • GPU:缓存命中率要求低,依赖高带宽显存(HBM/GDDR) 弥补缓存不足,通过批量数据访问掩盖内存延迟。

每个core的运算逻辑很简单

  • CUDA Core

D = A * B + C

  • Tensor Core:

4*4*4的matrix 计算

D = A * B + C

SIMT

  • 一条指令同时控制多个独立线程,每个线程处理一份数据。线程有独立的寄存器、程序计数器,可灵活分支(但分支会降低效率),是 GPU 专门针对大规模并行任务设计的架构。
  • threads的调度是有wrap来管理的,GPU体系中,wrap schedular专门负责线程调度

|------|--------------|---------|----------------|
| SISD | 一条指令仅处理一份数据 | 无并行(串行) | 早期 CPU、简单串行计算 |
| SIMD | 一条指令同时处理多份数据 | 数据级并行 | CPU 向量运算、多媒体处理 |
| SIMT | 一条指令控制多个独立线程 | 线程级并行 | GPU 大规模并行计算 |

  • SIMD 是 "数据打包" 并行,多个数据必须执行相同操作(无独立分支);
  • SIMT 是 "线程独立" 并行,线程可有不同分支(但同批次线程分支一致时效率最高);
  • SISD 无任何并行,完全串行执行,是最基础的计算架构。

注意事项

由于GPU的并行程度高,所以memory latency带来的性能损耗并不明显,但是CPU与GPU以及不同GPU通信时产生的memory latency需要关注。

相关推荐
麻瓜生活睁不开眼1 小时前
Android16修改全局桌面视图边框四直角显示为弧边圆角
android·java·深度学习
workflower1 小时前
装备企业的 AI 路线图
人工智能·深度学习·机器学习·设计模式·机器人
西柚研究生1234565 小时前
创建自己的数据集(GoogLeNet)
深度学习·神经网络·cnn
逻辑君8 小时前
基于 PPO 的双足机器人行走控制
人工智能·深度学习·机器人
美狐美颜SDK开放平台10 小时前
直播APP开发,美颜SDK和相机SDK有什么区别?
android·深度学习·数码相机·ios·直播美颜sdk·视频美颜sdk
逻辑君11 小时前
基于 A2C 算法的双足机器人行走控制
人工智能·深度学习·算法·机器学习·机器人
罗西的思考12 小时前
【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 — (14)— Teacher
人工智能·笔记·深度学习·算法·机器学习
薛定e的猫咪12 小时前
如何高效构建一个RAG知识库 dify实例与常见问题
人工智能·深度学习
手写码匠13 小时前
华为云Flexus+DeepSeek征文|DeepSeek+RAG知识库实战:基于Flexus X实例与Dify构建企业级智能问答系统
人工智能·深度学习·算法·aigc
bittersuite13 小时前
LeNet,AlexNet
人工智能·深度学习·机器学习