Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 系统与高性能 / Systems & Performance

计算系统 / Computing Systems

1. 计算系统:计算机如何执行与加速程序

2. 从 C++ 源码到 CPU 执行

3. CPU 流水线、乱序执行与分支预测

4. Cache、一致性、伪共享与 NUMA

5. GPU、SM、Warp 与显存

6. 计算执行模型:程序怎样映射到机器

7. SIMD 与编译器向量化

8. C++ 多线程与 OpenMP

9. CUDA 平台与编程模型

10. CUDA Kernel、内存与性能

11. CPU-GPU 异构流水线

12. MPI 与分布式并行

13. 并行算法模式

14. 性能模型与工具

15. 递进学习项目:从单线程到集群

历史完整正文 / Original Deep Dives

1. 历史完整正文:统一前文章逐篇保留

原体系结构与硬件 / Original Architecture

1. 硬件编程与高性能计算:一张可走通的学习地图 / A Practical Learning Map for Hardware Programming and HPC

2. 计算机体系结构:CPU、内存与 GPU / Computer Architecture: CPUs, Memory, and GPUs

3. 计算机架构基础——为什么 GPU 比 CPU 更快 / Computer Architecture Fundamentals: Why GPUs Outperform CPUs

4. 并行计算理论——30 天训练能优化到多快? / Parallel Computing Theory and the Limits of Training Acceleration

5. GPU 架构深入——上万个核心如何分工协作 / GPU Architecture and Massive Parallel Execution

6. CUDA 编程模型——把矩阵乘法映射到 GPU / The CUDA Programming Model for Mapping Matrix Multiplication to GPUs

7. CUDA 内存管理——百亿参数如何装进显存 / CUDA Memory Management for Large Models

8. CUDA 性能优化——从 30 天缩短到 10 天 / CUDA Performance Optimization

9. CPU 并行编程——OpenMP 与 SIMD 向量化 / CPU Parallel Programming with OpenMP and SIMD

10. HPC 集群与 MPI——多节点分布式训练 / HPC Clusters and MPI for Distributed Training

11. 异构计算——CPU 与 GPU 如何协同工作 / Heterogeneous Computing with CPUs and GPUs

12. 深度学习训练优化实战——从 30 天到 3 天 / Deep Learning Training Optimization from Thirty Days to Three

13. 性能分析工具——找到真正的瓶颈 / Performance Analysis Tools for Finding Real Bottlenecks

14. NPU 全景——昇腾/寒武纪/TPU/苹果生态 / The NPU Landscape: Ascend, Cambricon, TPU, and Apple

15. 未来趋势——2030 年的计算机会是什么形态 / Future Computing Trends Toward 2030

16. 硬件与高性能计算:从“程序为什么慢”开始 / Hardware and HPC Starting from Why Programs Are Slow

原并行计算 / Original Parallel Computing

1. 并行计算:从 SIMD 到 MPI / Parallel Computing from SIMD to MPI

2. 并行计算全景:从晶体管、CPU、GPU 到计算集群 / Parallel Computing from Transistors, CPUs, and GPUs to Clusters

3. 并行计算基础:任务分解、加速比与可扩展性 / Parallel Computing Fundamentals: Decomposition, Speedup, and Scalability

4. 处理器体系结构:从指令流水线到多核芯片 / Processor Architecture from Instruction Pipelines to Multicore Chips

5. CPU 并行:多线程、SIMD、Cache 一致性与 NUMA / CPU Parallelism with Threads, SIMD, Cache Coherence, and NUMA

6. 内存层次:Cache、带宽、局部性与一致性 / Memory Hierarchies, Bandwidth, Locality, and Coherence

7. GPU 体系结构:SIMT、Warp、SM 与吞吐优先设计 / GPU Architecture with SIMT, Warps, and Streaming Multiprocessors

8. CUDA 编程模型:Thread、Block、Grid 与内存协作 / CUDA Threads, Blocks, Grids, and Cooperative Memory Access

9. 并行算法模式:Map、Reduce、Scan、Stencil 与任务图 / Parallel Patterns: Map, Reduce, Scan, Stencil, and Task Graphs

10. 异构计算:CPU、GPU、NPU 如何协同工作 / Heterogeneous Computing with CPUs, GPUs, and NPUs

11. 分布式并行:MPI、集合通信、RDMA 与多机多卡 / Distributed Parallelism with MPI, Collective Communication, and RDMA

12. 性能工程:测量、Roofline、瓶颈定位与优化闭环 / Performance Engineering with Measurement, Roofline, and Bottleneck Analysis

13. 并行计算实战:AI、CAE、图像与科学计算 / Parallel Computing for AI, CAE, Imaging, and Scientific Computing

14. 并行计算实践路线:从单核优化到多机多卡 / A Parallel Computing Project Path from Single-Core to Multi-Node GPUs

本页目录

计算机体系结构:CPU、内存与 GPU / Computer Architecture: CPUs, Memory, and GPUs ​

性能首先是数据流问题。处理器再快,也无法弥补数据未及时到达、任务不够并行或同步过多。

体系结构学习的目标不是背诵某一代 CPU 或 GPU 的参数,而是理解程序语义如何映射为指令、数据移动和等待。源代码中的一次数组访问,可能命中寄存器或 Cache,也可能触发跨 NUMA 节点访问;一个看似并行的循环,可能因为依赖链、分支或内存带宽而无法利用全部执行单元。

从指令到数据的执行路径 ​

text
程序指令
  -> 前端取指、译码与分支预测
  -> 调度到标量、向量或专用执行单元
  -> 访问寄存器和多级 Cache
  -> 未命中时访问主存或远端 NUMA 内存

GPU Kernel
  -> Grid / Block / Warp 调度
  -> 大量线程隐藏等待
  -> 合并访问设备内存
  -> 必要时经互连与主机交换数据
1
2
3
4
5
6
7
8
9
10
11

CPU 用复杂控制、乱序执行和较大的缓存降低单线程延迟,适合分支多、任务不规则或串行比例较高的工作。GPU 用大量较简单的执行通道提高吞吐,适合规则、数据并行且计算量足以覆盖传输与启动成本的工作。二者不是简单的快慢关系,选择取决于依赖结构、数据规模、访问规律和端到端成本。

核心问题 ​

问题首先检查
CPU 为什么没有跑满?分支、依赖、Cache miss、线程竞争
GPU 为什么不快?并行度、访存合并、占用率、CPU-GPU 传输
多核为何不扩展?串行区、NUMA、共享数据和负载不均

表中的指标只是调查入口。例如 CPU 使用率低可能在等待 I/O,也可能线程被锁阻塞;GPU Occupancy 高不代表访存有效;Cache miss 多是否重要,还取决于处理器能否用其他独立工作隐藏延迟。必须把硬件计数器与源代码调用路径、工作负载和耗时联系起来。

内存层次决定可供给的性能 ​

处理能力的增长通常快于外部内存带宽,因此数据复用和局部性往往比减少几条算术指令更重要。连续遍历有利于预取与缓存行利用,结构体数组和数组结构体会形成不同的向量化与访存行为。多核共享数据还会引入一致性流量;即使线程修改不同变量,只要它们落在同一缓存行,也可能发生伪共享。

NUMA 系统中,页面通常在首次访问时决定物理位置。线程迁移到其他节点后访问这批页面,会产生额外延迟和互连流量。并行程序不仅要把计算分给核心,也要让线程靠近自己的数据,并控制跨节点共享。

指令集与微架构 ​

指令集架构定义软件可见契约,例如寄存器、指令、内存模型和异常。 微架构决定处理器如何实现该契约。

同一 ISA 可以有不同流水线、Cache、执行宽度和功耗特征。 因此“支持相同指令”不代表性能相同。

text
ISA contract
  -> fetch and decode
  -> rename and schedule
  -> execute
  -> retire in architectural order
1
2
3
4
5

乱序执行允许处理器在等待某条指令时执行其他独立工作。 最终退休仍保持架构要求的可观察顺序。

CPU 前端 ​

前端负责取指、分支预测、译码和向后端提供微操作。

前端瓶颈可能来自:

  • 指令 Cache miss;
  • iTLB miss;
  • 分支预测错误;
  • 代码体积;
  • 译码带宽;
  • 微操作 Cache;
  • 间接跳转;
  • 频繁虚调用。

大型展开可能减少循环控制,却增加代码体积和前端压力。 优化需要测量,不能假设展开越多越快。

分支预测 ​

条件分支的真实方向通常在流水线后部才能确定。 处理器预测方向并沿预测路径执行。

预测错误时,错误路径工作被丢弃并重新取指。 代价与流水线深度和可用独立工作有关。

数据相关且近似随机的分支难以预测。 可以考虑排序、分区、查表或无分支写法,但替代方案也可能增加指令和内存访问。

依赖与指令级并行 ​

真实数据依赖形成关键链:

text
a = load(p)
b = f(a)
c = g(b)
d = h(c)
1
2
3
4

后一步必须等待前一步结果。 增加执行单元无法突破这条依赖链。

多个独立累加器、批量处理和算法重构可以暴露更多独立工作。 编译器是否成功调度,需要结合汇编和计数器检查。

标量与向量执行 ​

SIMD 指令一次处理多个数据元素。

向量化收益取决于:

  • 数据连续性;
  • 对齐;
  • 循环依赖;
  • 指针别名;
  • 分支和 Mask;
  • Gather/Scatter;
  • 数据类型;
  • 向量宽度;
  • 频率变化。

更宽向量不保证线性加速。 内存带宽、尾部处理和降频都可能限制收益。

Cache 层次 ​

Cache 以 Cache Line 为单位传输数据。 程序只需要一个字节,也可能搬运整条 Line。

Cache miss 类型常分为:

  • Compulsory:首次访问;
  • Capacity:工作集超过容量;
  • Conflict:映射冲突;
  • Coherence:共享写导致失效。

分类用于提出方向,不同硬件计数器未必能直接精确区分全部类型。

预取 ​

硬件预取器擅长连续和固定步长访问。 依赖指针链和随机访问难以提前发现。

软件预取只有在距离合适、访问确定且硬件预取不足时才可能有益。 过早会挤出有用数据,过晚则没有隐藏延迟。

数据布局 ​

cpp
struct ParticleAoS {
    float x, y, z, mass;
};

struct ParticleSoA {
    std::vector<float> x;
    std::vector<float> y;
    std::vector<float> z;
    std::vector<float> mass;
};
1
2
3
4
5
6
7
8
9
10

只处理坐标的循环通常更喜欢 SoA。 频繁同时读取完整对象的逻辑可能更适合 AoS。

热冷字段拆分可以减少工作集。 AoSoA 可以在对象组织和向量宽度之间折中。

TLB 与页表 ​

虚拟地址需要通过页表转换为物理地址。 TLB 缓存近期转换。

大工作集、随机访问和高线程数可能增加 TLB 压力。 大页减少页表项,却增加内存粒度、碎片和部署约束。

只有计数器与真实工作负载证明瓶颈后,才应引入大页。

Cache 一致性 ​

多核系统需要让共享内存具有可理解行为。 核心修改 Cache Line 时,其他核心的副本可能被失效或更新。

频繁共享写会产生一致性流量。 即使线程修改不同变量,只要位于同一 Cache Line,也可能伪共享。

线程局部累加再归约,通常比每次更新全局原子更容易扩展。

NUMA 拓扑 ​

多插槽系统中,本地内存通常比远端内存延迟低、带宽高。

text
Socket 0 CPUs <-> Local Memory 0
       | interconnect
Socket 1 CPUs <-> Local Memory 1
1
2
3

页面可能根据首次触碰位置分配。 单线程初始化后并行计算,会让其他节点大量远端访问。

NUMA 策略包括并行初始化、线程绑定、数据分片和只读复制。 应同时测量吞吐、远端访问和负载均衡。

GPU 执行资源 ​

GPU 由多个执行簇组成,每个簇调度大量 Warp 或 Wavefront。

线程使用:

  • 寄存器;
  • 共享或本地数据存储;
  • 多级 Cache;
  • 全局设备内存;
  • 常量和纹理路径;
  • Host/Device 互连。

Block 大小会影响可驻留 Warp、寄存器和共享内存。 Occupancy 高只说明驻留条件,不证明指令和访存有效。

GPU 访存 ​

相邻线程访问相邻地址时,更容易形成合并事务。 随机 Scatter/Gather 会增加内存事务和缓存压力。

共享内存用于 Block 内协作和数据复用。 访问模式不合适时可能产生 Bank Conflict。

Host 与 Device 传输必须进入端到端模型。 小 Kernel 即使执行极快,也可能被传输和启动完全覆盖。

异构计算 ​

异构系统把控制、不规则任务和高吞吐 Kernel 分给不同处理器。

text
CPU
  -> prepare and partition
  -> launch accelerator work
  -> overlap independent CPU work
  -> synchronize required results
  -> commit output
1
2
3
4
5
6

分工边界应减少往返和细粒度同步。 在 CPU 与 GPU 之间反复搬运中间结果,常比计算本身更贵。

NPU 与专用加速器 ​

专用加速器针对有限算子、精度和数据流优化能效。

评估时检查:

  • 支持的数据类型;
  • 动态形状;
  • 算子覆盖;
  • 编译时间;
  • 内存容量;
  • Host 回退;
  • 数据传输;
  • 数值容差;
  • 工具和调试能力。

峰值 TOPS 不等于实际模型吞吐。 算子回退和布局转换可能显著降低端到端收益。

I/O 与设备 ​

CPU 通过 MMIO、DMA、中断和驱动与设备协作。

DMA 允许设备直接搬运内存数据,减少 CPU 逐字节复制。 但仍需要缓冲区固定、同步和完成通知。

中断适合稀疏事件,高速设备可能使用轮询或中断合并降低开销。

性能计数器 ​

硬件计数器可观察周期、指令、Cache、分支和内存事件。

解释计数器时注意:

  • 事件定义依处理器而异;
  • 计数器数量有限,可能时间复用;
  • 推测执行会影响部分事件;
  • 虚拟化可能限制可见性;
  • 绝对值要与工作量归一化;
  • 单个事件不能独立证明瓶颈。

计数器与调用栈、时间线和基准结合使用。

功耗与热限制 ​

处理器性能受功耗、温度和频率策略影响。

长时间负载可能从短时 Boost 降到稳定频率。 只测几秒钟会高估持续任务性能。

向量宽度、核心数量和 GPU 功耗限制都会改变频率。 实验应记录预热、温度和电源计划。

体系结构实验 ​

建议完成:

  1. 顺序与随机内存访问;
  2. 工作集跨越 Cache 层次;
  3. AoS 与 SoA;
  4. 分支可预测与随机分支;
  5. 单累加器与多累加器;
  6. 单线程与多线程扩展;
  7. 伪共享与填充;
  8. NUMA 本地和远端访问;
  9. GPU 合并与非合并访存;
  10. 传输加 Kernel 端到端测量。

每个实验保存硬件、编译参数、输入和原始样本。

实验结论还应回答:

  • 工作量是否一致;
  • 正确性是否保持;
  • 冷热状态是否明确;
  • 数据移动是否计入;
  • 资源数量是否记录;
  • 差异是否超过噪声;
  • 瓶颈是否发生迁移;
  • 结论适用于哪些规模;
  • 不同硬件是否复现;
  • 是否建立回归基准。

推荐路线 ​

  1. 计算机架构基础
  2. 处理器体系结构
  3. 内存层次
  4. GPU 架构
  5. 异构计算

CUDA、SIMD 和 MPI 是如何使用这些硬件的编程模型,分别进入并行计算专题。

怎样验证理解 ​

每个概念都应配合最小实验:改变数组访问步长观察缓存行为,比较 AoS 与 SoA 的向量化结果,固定线程亲和性检查 NUMA 放置,或把 GPU 传输时间与 Kernel 时间分开测量。实验要记录处理器、编译器、优化选项、输入规模和重复方法。

学完本路线后,应能从程序的访问模式推断潜在瓶颈,解释 CPU 与 GPU 的适用边界,并选择正确的计数器或 Profile 工具验证假设。具体型号参数会过时,但“工作如何分解、数据在哪里、等待由什么造成”这三个问题长期有效。

最后更新于:

Pager
上一篇1. 硬件编程与高性能计算:一张可走通的学习地图 / A Practical Learning Map for Hardware Programming and HPC
下一篇3. 计算机架构基础——为什么 GPU 比 CPU 更快 / Computer Architecture Fundamentals: Why GPUs Outperform CPUs

持续记录,持续成长

Copyright © Tidenflow