嘉树的日志

PMPP 第一章综述

本文是对 PMPP 第五版的总结笔记,第一章,开始是自己逐字翻译,后来发现效率实在太低,采用 DeepSeek 翻译总结,并核对关键内容。

现在很多应用都需要设备的计算能力。1980 后的二十年,cpu 发展迅速,单CPU 能带来GFLOPS 级别的浮点操作数。这使得软件发展更好,能产生更有用的结果。用户反过来也顺应了设备计算能力的提升,创造了计算机工业的正循环。

然而,2003 年后,由于能源消耗和散热设计问题。限制了CPU 的时钟频率和生产力能力在串行计算过程的表现。多核出现了。用户有多个指令序列,来自相同或者不同的应用,同时在这些处理器上运行。为了能充分利用多核,任务必须分成能在多核上同步执行的指令。在软件开发领域,多核开发影响深远。

传统程序是串行的程序运行在冯诺依曼架构上。这些程序可以通过程序计数器,让人们理解串行的步骤。程序计数器包含下一条指令地址。来自这个应用的顺序逐步执行导致指令执行的序列被称之为执行线程,简称线程。这个概念很重要,后续将会正式定义并且在书后面很多地方用到。

过去的软件开发者依赖底层的增长的时钟周期速度和多指令执行,这种高级特性开发;同样的软件,在下一代处理器上就会更快。用户也习惯了。最近,就没那么有效了。串行程序只能在一个核上运行,不再随着处理器迭代变得更明显的快了。这也导致开发者没法像新处理器一样介绍他们的新程序,减少了计算机工业的成长机会。

然而,并行软件在新一代处理器中崭露头角,多线程合作让计算更快。这种并行程序超过串行的巨大升级,称之为并行革命。实际并行程序不是啥新词。高性能计算社区已经开发并行程序数十年了。

这些并行程序运行在大规模,昂贵的计算机上。只有精英程序能使用这些计算机,导致限制了并行程序只有一小部分开发者。然而,当所有处理器变成并行计算机,大量的并行应用需要开发。需要软件开发者学习并行编程,也就是这本书。

异构并行计算

从 2003 年开始,半导体工业开始驶向两个轨道:多核多线程。多核需要维持串行程序执行速度的同时转移到多个核。多核处理器一开始是两个核,并随着半导体工艺世代的发展增加数量。英特尔,AMD 的服务器处理器能 到 100 核以上,每个处理器都是一个可实现完整 x86 指令集的、支持超线程技术(具有两个硬件线程)的乱序多指令发射处理器,旨在最大化顺序程序的执行速度。

与多核相反,多线程路径专注于并行应用的吞吐。多线程路径开始于大量的线程,并随着每一代增加线程数。例如英伟达的 H100 有着数十万的线程,在一个简单的有序流水线执行。多线程处理器,尤其是GPU,在浮点计算处于领先地位。同样是以 H100 为例,峰值浮点吞吐能达到:

Bits TFLOPS
64bit 34
32bit 64
16bit 1979

CPU的同年的顶尖服务器处理器也只能达到个位数的TFLOPS。这不是必要的应用渠道,而是仅仅在这些芯片中,执行资源理论上能够支持的原始速度。

这两者的路径的差距已经形成一种电势累计,在未来的某一时刻,总有一个路线是走不下去。迄今为止,许多应用开发者转向了GPU 做计算密集任务。并且更为重要的,像深度学习这种本质上计算密集任务,在并行程序性能提升的情况下已经能够带来革命性的应用。计算密集的部分就是并行计算的首要目标。当有更多工作需要做的时候,就有更多的机会切分任务沿着合作的并行 worker,例如线程(threads)。 96740b63-5a43-40da-ae4e-5ae1b62f7271

核心问题

为什么多核与多线程性能差异巨大? → 答案在于两者的基本设计哲学完全不同。


CPU:低延迟导向设计(Latency-Oriented)

设计特点 目的
计算单元与操作数传送逻辑大而强 减少单条指令/操作的延迟
大容量最后一级缓存(LLC) 将长延迟的DRAM访问转换为短延迟的缓存访问
复杂的分支预测与执行控制逻辑 减轻条件分支指令带来的延迟
资源密集:消耗大量芯片面积和功耗 换取每个独立线程的低执行延迟

代价:这些资源本可用于提供更多的算术单元和内存通道。 设计风格低延迟导向设计


GPU:吞吐导向设计(Throughput-Oriented)

驱动因素

关键需求

内存模型优势

延迟 vs 吞吐的量化权衡

操作 代价(面积/功耗)
算术吞吐量翻倍(单元数量翻倍) 面积 ×2,功耗 ×2
算术延迟减半(电流翻倍) 面积 >×2,功耗 ×4

结论:降低延迟比提高吞吐量昂贵得多。 → GPU选择优化吞吐量,允许单个线程有较长延迟,但通过大量线程隐藏延迟。

GPU设计形象比喻

图1.1(a) CPU 图1.1(b) GPU
少数算术单元 大量算术单元
少数内存通道 大量内存通道

执行模型


CPU vs GPU:适用场景

场景 更优选择 原因
单线程或极少数线程 CPU 操作延迟低
大量线程 GPU 执行吞吐量高
混合型应用 CPU + GPU 串行部分跑CPU,计算密集型部分跑GPU

这正是 CUDA(2007年NVIDIA推出) 的设计目标:支持CPU与GPU联合执行


非性能因素:市场与生态

安装基数(Installed Base)

GPU的市场优势

外形尺寸与易访问性


GPU编程的演变

早期(~2006年):GPGPU

革命(2007年):CUDA 发布


补充:其他异构计算加速器

为什么需要更多的速度或者并行?

正如我们在第 1.1 节中所指出的,进行大规模并行编程的主要动机,是为了让应用能够在未来的硬件世代中持续获得速度提升。我们将在“并行模式”、“高级模式”以及“应用”等章节(第 2 部分和第 3 部分,即第 7 章至第 23 章)中讨论到,当一个应用适合并行执行时,其在 GPU 上的良好实现相较于在单个 CPU 核心上的顺序执行,可以实现超过 100 倍的加速。如果应用包含我们称之为“数据并行性”的特征,通常只需几个小时的工作就能实现 10 倍的加速。

尽管许多现有应用看似运行得足够快,但未来的大众市场应用将涉及过去所谓的“超级计算应用”:

所有这些新应用都涉及以不同方式和层次模拟/表达物理并发世界,处理海量数据,且大部分计算可以并行进行。

实际应用的加速比

加速比定义

系统 A 相对于系统 B 的加速比 = B 上执行时间 / A 上执行时间

例如:若应用在 A 上需 10 秒,在 B 上需 200 秒,则 A 比 B 快 20 倍(20×)

Amdahl 定律

并行计算可实现的加速比严重受限于应用可并行化部分的比例

并行部分占比 并行部分速度提升 整体加速比 说明
30% 100× 1.42× 即使并行部分无限加速,整体最多只能削减30%时间
99% 100× 50× 整体执行时间降至原来的1.99%

结论:要让大规模并行处理器有效加速,应用的绝大部分执行时间必须在可并行部分

另一个影响加速比的重要因素就是 内存带宽

CPU GPU 应合理分工

用一个桃子来比喻的话:

比喻 对应内容 特点
桃肉 可并行的部分 适合 GPU 处理
桃核(pit) 串行部分 极难并行化,CPU 擅长处理

并行编程挑战

有人说过:“如果你不在乎性能,并行编程很容易。你可以在一小时内写出并行程序。但如果不在乎性能,何必还要写并行程序呢?

本书聚焦于如何在并行编程中实现高性能,主要面临以下四大挑战:


挑战一:并行算法的计算复杂度


挑战二:内存访问限制


挑战三:对输入数据特性敏感


挑战四:线程协作与同步开销

类型 特点 同步需求
易并行(embarrassingly parallel) 线程间几乎不需协作 无/极少同步
需协作的并行 线程间需要交互 需要屏障(barrier)、原子操作(atomic operation)等

乐观的信息

大多数挑战已被研究人员解决,且不同应用领域之间存在通用模式,可以将一个领域的解决方案应用到其他领域。

这正是本书的核心方法:在重要并行计算模式和应用的背景下,介绍解决这些挑战的关键技术。


四大挑战总结表

挑战 核心问题 后果 解决方案(书中章节)
1. 算法复杂度 并行算法做了更多冗余工作 大数据集可能比串行还慢 work efficiency、prefix-sum(第11章)
2. 内存访问 内存带宽/延迟成为瓶颈 memory-bound 应用难以提速 内存访问优化(第5、6章)
3. 数据敏感性 对输入大小/分布不规则敏感 工作负载不均,性能波动 数据正则化、定制分配
4. 同步开销 线程协作需要同步机制 线程等待,浪费计算资源 减少同步策略(全书)

相关并行编程接口

三种并行编程模型对比总结

特性 OpenMP MPI OpenCL / CUDA
主要应用场景 共享内存多处理器系统 集群计算(分布式内存) 大规模并行处理器(GPU)
内存模型 共享内存 分布式内存(不共享) GPU 内共享内存
编程方式 编译器指令/pragma 显式消息传递 语言扩展 + API
自动化程度 高(编译器自动化) 低(手动域分解) 中(显式控制)
性能可移植性 较好 较高(但移植工作量大) 需修改以优化性能
学习曲线 相对平缓 陡峭 中等
与 CUDA 关系 可用 CUDA 弥补不足 CUDA 用于节点内,MPI 用于节点间 CUDA 与 OpenCL 概念高度相似

核心要点

  1. OpenMP:编译器自动化程度高,适合共享内存系统;但编译器仍在演进,程序员仍需理解并行概念。
  2. MPI:用于分布式内存集群,适合超大规模 HPC;但节点间无共享内存,需做域分解和显式消息传递。
  3. OpenCL:标准化编程模型,跨厂商兼容;与 CUDA 概念高度相似,技术可相互迁移。
  4. CUDA 的价值:提供对并行编程细节的显式控制,是学习并行编程概念的优秀载体,即使在主要使用 OpenMP 或 OpenCL 的场景下也很有帮助。

本书目标

目标一:教授高性能并行编程

主要目标是教会读者如何为大规模并行处理器编程以实现高性能

实现方式

关于硬件知识


目标二:保证正确功能与可靠性

并行计算中的一个微妙问题——达到初始性能还不够,关键在于能够调试代码支持用户

CUDA 编程模型提供的支持

功能 用途
屏障同步(barrier synchronization) 管理并行性
原子操作(atomicity) 保证数据一致性
内存一致性(memory consistency) 管理内存访问顺序

工具支持


目标三:跨未来硬件世代的可扩展性

确保随着未来机器越来越并行化,你的代码能在新机器上运行得更快

关键方法

核心理念

高性能并行代码的开发技术,也是确保应用程序未来可扩展性的关键。


教学方法

本书组织架构

以下是这段全书组织结构的翻译总结:


全书三大部分概览

部分 内容 章节范围
第1部分:基础概念 并行编程基础、数据并行性、GPU、性能优化 第2–6章
第2部分:基本并行模式 基础并行计算模式 第7–15章
第3部分:高级并行模式与应用 更复杂的并行模式及实际应用 第16–23章

第2、3部分将应用第1部分的知识技能,并根据需要引入其他GPU架构特性和优化技术。


第1部分:基础概念(第2–6章)

章节 主题 核心内容
第2章 CUDA编程模型入门 向量加法为例,介绍:识别并行化代码、数据隔离与传输、内核函数编写与启动、结果回传等六步流程。基于C++扩展,支持SPMD模型。
第3章 并行执行模型 多维数据与多维线程组织;线程的创建、组织、资源绑定与数据绑定。
第4章 GPU计算架构 计算核心组织、线程调度;透明可扩展性、SIMD执行与控制流分歧、多线程与延迟容忍、占用率等概念。
第5章 GPU内存架构 特殊内存(用于管理数据传递、提升速度);CUDA内存分配与使用;合理使用可大幅提高数据访问吞吐量、缓解内存系统拥塞。
第6章 性能考量与优化策略 线程执行模式与内存访问模式;常用优化策略清单——将在第2、3部分反复使用。

第2部分:基本并行模式(第7–15章)

章节 模式 核心内容与教学要点
第7章 卷积(Convolution) 源于数字信号处理/计算机视觉;引入常量内存缓存
第8章 模板(Stencil) 源于求解微分方程;引入三维线程与数据组织;演示线程粒度优化。
第9章 直方图(Histogram) 统计数据分析与模式识别;引入原子操作(协调并发更新)和私有化优化
第10章 归约树(Reduction Tree) 汇总输入数据集合;演示控制流分歧过度屏障同步对性能的影响及缓解技术。
第11章 前缀和/扫描(Prefix Sum/Scan) 将固有串行计算转为并行;引入工作高效性概念。
第12章 过滤(Filter) 不稳定过滤(可改变顺序)与稳定过滤(保持顺序);稳定过滤是扫描模式的重要应用。
第13章 并行归并(Parallel Merge) 分治工作分区策略;引入动态输入数据识别与组织
第14章 排序(Sorting) 三种并行排序算法:奇偶排序、归并排序(依赖第13章归并模式)、基数排序(依赖第11章扫描模式)。
第15章 矩阵乘法(Matrix Multiplication) 深入重访,应用第6章优化策略清单中的大量高级优化技术。

第3部分:高级并行模式与应用(第16–23章)

本部分模式更复杂,包含更多应用上下文。重点不是引入新技术,而是应用特定的考量

章节 主题 核心内容
第16章 动态规划与波前并行 Floyd-Warshall算法(图处理)+ Smith-Waterman算法(基因组序列比对)
第17章 稀疏矩阵计算 面向超大数据集;数据重排技术:压缩、填充、排序、转置、规整化
第18章 图算法 图搜索的高效GPU实现;多种并行化策略;图结构对算法选择的影响
第19章 深度学习(CNN) 卷积神经网络的高效实现:分块技术(tiling)+ 卷积模式
第20章 大语言模型(LLM) GPU上训练与推理的先进优化:KV缓存、批处理(batching)
第21章 静电势图计算 散播-收集变换(scatter-to-gather)技术:增强并行性、减少同步开销
第22章 计算思维 将抽象科学问题组织为计算任务;并行算法结构及其性能影响;以输入为中心 vs 以输出为中心两种并行化策略回顾
第23章 异构集群CUDA编程 多GPU节点集群:MPI、NCCL、NVSHMEM 与 CUDA 协同使用,降低通信开销

第24章:结论与展望——大规模并行计算将是未来十年最激动人心的领域之一。


核心教学理念

“从具体例子中学习效果最好。”


章节总览图

第1部分(基础)
第2–6章:概念 + 架构 + 优化策略清单
        ↓
第2部分(基本模式)
第7–15章:卷积、模板、直方图、归约、扫描、过滤、归并、排序、矩阵乘
        ↓
第3部分(高级模式与应用)
第16–23章:动态规划、稀疏矩阵、图算法、深度学习、LLM、静电势图、计算思维、异构集群
        ↓
第24章:结论与展望