@reprompting: https://x.com/reprompting/status/2074133435401064486
摘要
一条详细总结《大规模并行处理器编程》一书的推文串,重点介绍CUDA和GPU编程概念、优化技术以及并行模式。
查看缓存全文
缓存时间: 2026/07/06 18:17
总结《大规模并行处理器编程》
最近我读完了《大规模并行处理器编程》(Programming Massively Parallel Processors),每天一章,并在每章之后分享简短总结。与其重复那些章节总结,我更想退一步,从整体上看这本书:它的结构如何,哪些部分我觉得最有趣/最有价值,以及我认为学习进程是如何设计的。
背景:我来自机器学习的计算机视觉方向,在此之前并未深入探索性能工程或CUDA,不过我有一些SIMD编程经验。这里讨论的所有内容都来自一个刚踏入CUDA生态系统的人的视角。
然而,有一件事确实有所帮助:我已经有了并行执行的心智模型。能够可视化一个函数如何展开为指令、这些指令如何执行、以及它们最终如何产生程序的输出,这使得书中的许多概念更容易内化。我认为拥有这种可视化能力在初次接触CUDA时是一个显著的优势。
现在,继续。这本书,我大致将其分为三个阶段(我个人分组):
-
基础章节:构建GPU执行和内存的心智模型
-
优化章节:解释GPU程序为何以某种方式运行,以及如何推理性能
-
应用章节:将相同的原理应用于越来越复杂的算法和工作负载
第一阶段:
对我来说,基础章节最为重要。本书开篇对比了CPU与GPU的设计差异——延迟导向 vs 吞吐量导向——并将这一理念作为贯穿全书的反复主题。许多后来的优化讨论都建立在这个视角之上。第2章立即让你用向量加法编写CUDA C,但最让我印象深刻的章节是第4章(计算架构与调度)和第5章(内存架构与数据局部性)。
第4章真正构建了硬件模型:线程束、SIMD执行、控制分歧、线程束调度和占用率。由于我有SIMD背景,线程束的概念几乎立刻就被理解了:它感觉就像SIMD加上硬件管理的掩码和分歧串行化。本书讲解了为什么线程被分组为线程束,为什么分歧会损害性能,以及为什么需要足够的线程束在飞行中以隐藏延迟。它还建立了许多后来优化技术所依赖的概念。
第5章在此基础上分层介绍了内存层次结构:全局、共享、常量、纹理和寄存器内存。对我来说,平铺矩阵乘法示例是整本书的“顿悟”时刻。从一个朴素的全局内存实现开始,进行基准测试,然后逐步将其转变为平铺共享内存版本。在此过程中,本书并没有简单地展示最终代码,而是详细讲解了内存访问模式、存储体冲突和占用率权衡。
第6章(性能考虑)将所有内容整合成一个实用清单:内存合并、隐藏延迟、线程粗化以及发现瓶颈。到这时,CUDA对我来说已经不再仅仅是一种编程语言。相反,解决性能问题越来越意味着在脑海中运行一个小型硬件模拟器,并推理GPU将如何执行每个内核。
第二阶段:
第7章到第12章是“并行模式”部分,本书从编写CUDA内核转向思考算法应如何并行化。每一章都采用一个常见模式(卷积、模板计算、直方图、归约、前缀和或合并),并使用它来引入一种新的优化技术或硬件特性。
最让我印象深刻的是增量方法论。本书不是直接展示优化后的解决方案,而是从朴素实现开始,识别瓶颈(内存分歧、原子操作争用、控制分歧、浪费的工作等),然后一步一步改进。令人烦恼的是,这也相当忠实地反映了性能优化在实践中通常是如何工作的。
有几章尤其突出。
卷积和模板计算介绍了带有光环单元的平铺、常量内存以及1D、2D和3D线程组织之间的差异。模板计算章节在寄存器平铺和扫描操作背后的数学方面特别强大。
直方图使得同步成本变得非常具体,通过私有化和聚合来绕过原子操作争用。这是第一次协调成本变得难以忽视,而不仅仅是抽象描述。
归约在此基础上采用基于树的方法,既减少了控制分歧也减少了内存分歧。与前缀和一起,它使工作效率与并行性之间的权衡变得更加具体。
合并介绍了协同秩函数、平铺合并和环形缓冲区。此时,这些内容感觉不再像是CUDA特有的练习,而更像是通过GPU视角表达的通用系统编程技术。
从机器学习的角度来看,卷积是最直接的切入点,但直方图和归约对我来说更具启发性,因为它们迫使你面对在简单数据并行内核中容易忽视的协调成本。
第三阶段:
第13章到第19章(高级模式与应用)以及第20章到第22章(高级实践)是本书从教授CUDA作为一种编程模型转向更广泛地思考高性能系统的部分。
排序(第13章)和稀疏矩阵计算(第14章)是本书中最强的两章。排序涵盖了基数排序和归并排序,但真正的重点是内存合并和线程粗化决策——本质上是重新审视第6章的清单,但现在应用于一个更复杂的问题。稀疏矩阵格式(COO、CSR、ELL、JDS)本可以以枯燥的定义列表形式呈现。相反,该章使用它们来激发不规则并行性的具体数据结构设计选择。
图遍历(第15章)和深度学习(第16章)是应用部分的高峰。深度学习章节对于来自视觉领域的人尤其相关:它为卷积层构建了一个CUDA推理内核,将其重新表述为GEMM,然后将其连接到cuDNN。这种递进使编写CUDA内核的能力与理解PyTorch和TensorFlow在GPU上实际做了什么之间的联系更加清晰。
最后章节涵盖了MPI+CUDA集群、动态并行性以及统一内存、零拷贝和分析等高级实践,感觉更像是专家级GPU编程的预览。这些部分在现阶段并未深入理解,更像是需要时再回头查看的材料。
学习进程是如何组织的
在完成本书后,我才恍然大悟,存在一个四步进程。
第一阶段是语法和心智模型形成:理解内核如何启动、线程如何组织以及实际在GPU上执行什么。没有这个,优化就没有目标。
第二阶段是硬件感知推理,每个优化都基于架构约束,如内存带宽、线程束调度和占用率。
第三阶段是模式识别。在看到平铺、私有化和线程粗化应用于多个不同问题后,就能够在文本尚未完全展开优化之前预见其方向。
最后阶段是应用综合:后面的章节引入的全新想法较少,而是专注于在日益受限或不规则的工作负载下组合已知技术。
我发现最有价值的部分
由于我已有并行心智模型,基础章节(尤其是第4、5和6章)对我来说价值最高。它们提供了词汇来匹配我已有的直觉。特别是第6章的优化清单,实际上成为了我阅读本书其余部分的视角。我经常在查看本书提出的解决方案之前,就问自己内核是内存受限还是计算受限,是否存在分歧,或者是否可以进行平铺。
本书在增量优化方面非常一致:从朴素版本开始,测量,识别瓶颈,应用单一变换,再次测量。这个循环既作为教学法也作为实践,正是它建立了像性能工程师一样推理的习惯,而不仅仅是知道CUDA语法的人。
如果有一个局限性,那就是一些后面的应用章节——如MRI重建、静电势等类似示例——除非那些领域已经相关,否则感觉相当小众。即便如此,底层的优化模式仍然可以迁移。
我打算在此基础上做什么
PMPP是基础,但这只是开始。真正的目标是能够推理和优化我实际使用的系统:LLM推理、Transformer内核,以及从CUDA原语到服务系统的完整堆栈。
粗略计划如下:
相似文章
CUDA 书籍
一份精选的CUDA编程主要书籍列表,涵盖从入门到高级主题,包括C++和Python,重点提供适用于NVIDIA GPU并行计算的实用资源。
@SzymonOzog_: 周六阅读:“What happens when you run a CUDA kernel”——非常酷的博客文章,详细介绍了CPU与GPU通信的细节…
推荐一篇博客文章的推文,该文章解释了启动CUDA内核时所需的CPU-GPU通信细节。
@levidiamode: Day 138/365 of GPU Programming 今年我最喜欢的讲座之一是斯坦福大学的CS336第7讲关于GPU…
一位学习者分享了对斯坦福大学CS336第7讲关于GPU并行性的热情,该讲座涵盖了基本操作,并将其连接到多GPU设置以及张量并行、数据并行和流水线并行等技术。
@vivekgalatage:我发现的最好的GPU优化结构化参考资料——450篇论文,14年研究。一些技术已经进化……
一条推文分享了一个涵盖14年、450篇论文的GPU优化结构化参考资料,指出虽然一些技术已经发展,但心智模型仍然有用。还提到了Onur Mutlu关于GPU架构的讲座。
@charles_irl: https://x.com/charles_irl/status/2071606346844442871
本文通过一个简单的向量加法示例,详细介绍了CUDA内核从源代码到硬件执行的编译和启动全过程,并阐述了nvcc、PTX、SASS及ioctls的作用。