ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SIMD 与 GPU 编程前置课:硬件基础(时钟频率终结、CPU 执行模型、Roofline 模型与芯片架构全景)

SIMD 与 GPU 编程前置课:硬件基础(时钟频率终结、CPU 执行模型、Roofline 模型与芯片架构全景) SIMD 与 GPU 编程前置课硬件基础时钟频率终结、CPU 执行模型、Roofline 模型与芯片架构全景【免费下载链接】maths-cs-ai-compendiumBecome a cracked AI/ML researcher/engineer with this unconventional textbook covering maths, computing, and ML with intuition.项目地址: https://gitcode.com/GitHub_Trending/mat/maths-cs-ai-compendium在动手写任何 SIMD 或 GPU 代码之前必须先理解你正在编程的硬件。本文是 Maths, CS AI Compendium 第 16 章「SIMD GPU Programming」的第一篇从为什么 2005 年之后单核频率不再增长讲起覆盖现代 CPU 的乱序执行、分支预测与投机执行SIMD 向量寄存器与 Roofline 性能模型延迟与吞吐量的权衡x86 / ARM / Apple Silicon / RISC-V / GPU / TPU 的芯片架构版图以及用 C 实测内存带宽的完整基准代码。读完本文你将能用算术强度Arithmetic Intensity判定任意 ML 算子属于计算密集还是访存密集并据此选择正确的优化路径——这也是理解后续 ARM 与 NEON、x86 与 AVX、GPU 架构与 CUDA 的基础。免费性能的终结为什么并行取代了主频在很长一段时期里软件性能是白捡的买一颗主频更高的新 CPU不改一行代码程序就跑得更快。这个时代大约在 2005 年结束。理解它为何结束、以及什么取代了它是任何想写出高性能代码的人的第一课。Moores Law 与功率墙**摩尔定律1965**观察到芯片上的晶体管数量大约每两年翻一番。这一规律维持了约 60 年。更多晶体管意味着更小的晶体管更小的晶体管意味着更高的主频更高的主频意味着更快的程序。但大约在 2005 年主频撞上了约 4 GHz 的功率墙。问题出在功耗。芯片功耗近似为$$P \propto C \cdot V^2 \cdot f$$其中 $C$ 是电容与晶体管数量成正比$V$ 是电压$f$ 是时钟频率。要提高频率就必须提高电压让晶体管更快翻转而功耗按 $V^2 \cdot f$ 增长——频率的微小提升会带来功耗与发热的巨大上升。在 4 GHz 时芯片功耗已达 100 瓦以上若继续冲 8 GHz散热将变得不切实际。出路与其让单核更快不如把多个核心放进同一颗芯片。一颗 3 GHz 的四核芯片与一颗 4.5 GHz 的单核芯片功耗相近却可以完成 4 倍的并行工作量。这就是为什么现代 CPU 都是多核也是为什么并行SIMD、多线程、GPU 计算是获取更多性能的唯一路径。对 ML 的含义单核上耗时 10 分钟的一次训练步无法靠买更快的 CPU 变快只能靠使用更多核心数据并行见第 6 章、更宽的 SIMD 单元本章或 GPU数千个核心来加速。现代 CPU 如何执行指令现代 CPU 核心远比第 13 章计算机架构介绍的简单取指-译码-执行模型复杂得多。它用几项关键技巧让每周期执行的指令数远超 1超标量执行SuperscalarCPU 拥有多个执行单元ALU、FPU、load/store 单元可以同时执行多条相互独立的指令。一个现代核心在指令彼此无依赖时每周期可执行 4~6 条指令。乱序执行Out-of-order, OoOCPU 并不按程序顺序执行指令。它会向前扫描指令流找到输入已经就绪的指令立即执行无论它在程序中排在哪里。这用于隐藏延迟当一条指令在等内存数据100 周期时CPU 会去执行其他就绪的指令。分支预测Branch prediction条件分支if语句、循环条件会带来不确定性——在条件求值完成之前 CPU 不知道走哪条路。与其停顿CPU 会预测结果并沿预测路径投机执行。现代预测器预测正确率超过 95%预测错误则丢弃投机工作、执行正确路径约 15 周期惩罚。更完整的流水线冒险数据冒险、控制冒险、结构冒险分析见 chapter 13 的流水线一节。投机执行Speculative execution分支预测的延伸——CPU 执行可能不需要的指令赌它们会被用到以此填满流水线、保持执行单元忙碌。以上全部是自动发生的——CPU 无需程序员干预就能完成。但它们只帮助指令级并行ILP单条指令流中的相互独立指令。对于数据级并行对大量数据元素执行同一操作我们需要 SIMD。这也是第 13 章强调的流水线让吞吐量逼近每周期一条指令而 SIMD 把吞吐量推到每周期多条数据。SIMD单指令多数据SIMDSingle Instruction, Multiple Data的思想是用一条指令同时处理多个数据元素——不是加两个数而是用一条指令加两个各含 4或 8、16个数的向量。不使用 SIMD标量方式// Add two arrays element by element: 4 add instructions for (int i 0; i 4; i) { c[i] a[i] b[i]; // one add per iteration }使用 SIMD向量化方式// Add two arrays: 1 SIMD instruction does all 4 adds #include immintrin.h // x86 SIMD intrinsics __m128 va _mm_load_ps(a); // load 4 floats into a 128-bit register __m128 vb _mm_load_ps(b); // load 4 floats into another register __m128 vc _mm_add_ps(va, vb); // add all 4 pairs simultaneously _mm_store_ps(c, vc); // store 4 resultsSIMD 版本用 1/4 的指令完成了同样的工作——理论 4 倍加速因为每条指令处理 4 个 float 而不是 1 个。向量寄存器SIMD 指令操作的对象是向量寄存器能容纳多个数据元素的宽寄存器。寄存器宽度Floats (32-bit)Doubles (64-bit)名称128-bit42SSE (x86), NEON (ARM)256-bit84AVX/AVX2 (x86)512-bit168AVX-512 (x86)Variable (128–2048)variesvariesSVE/SVE2 (ARM)寄存器越宽 并行度越高。一条 512-bit 的 AVX-512 指令同时处理 16 个 float理论上是标量代码的 16 倍加速。实际加速比会更低因为受内存带宽限制计算速度可以快于数据喂给 CPU 的速度。对 ML 的意义float32 矩阵乘法能从 SIMD 中获益巨大。内层循环两个向量的点积直接映射为 SIMD 乘加指令FMA。这正是 NumPy 和 PyTorch 调用的 BLAS 库如 Intel MKL、OpenBLAS被 SIMD 重度优化的原因——关于框架如何把 Python 调用分派到 C/BLAS 后端可回顾 第 16 章第 0 篇为什么是 C 以及 ML 框架如何工作。在 ARM 侧NEON 的vfmaq_f32等 FMA 指令是点积、矩阵乘和卷积的基础构件详见 ARM 与 NEONx86 侧的 AVX/AVX2 内在函数命名与用法见 x86 与 AVX。Roofline 模型判断代码到底快不快怎么知道你的代码是否够快Roofline 模型给出一个框架用两个硬件上限刻画性能峰值计算能力FLOPS每秒最大浮点运算次数。例如一颗 4 GHz CPU、256-bit AVX每条指令 8 个 float、2 个 FMA 单元$4 \times 10^9 \times 8 \times 2 64$ GFLOPS。峰值内存带宽bytes/second数据从内存搬到 CPU 的速度。现代 CPU 大约有 50 GB/s 的内存带宽。代码的**算术强度Arithmetic Intensity**是计算量与访存量的比值$$\text{Arithmetic Intensity} \frac{\text{FLOPS}}{\text{Bytes transferred}}$$算术强度低每载入一个字节只做少量运算代码就是访存密集memory-bound大部分时间在等数据。这时把计算做得更快更宽 SIMD、更高主频毫无帮助。算术强度高每字节对应大量运算代码就是计算密集compute-bound大部分时间在计算。这时更快的内存也无济于事。Roofline 公式$$\text{Achievable FLOPS} \min\left(\text{Peak FLOPS}, ; \text{Bandwidth} \times \text{Arithmetic Intensity}\right)$$矩阵乘法算术强度很高$O(n^3)$ 次运算对应 $O(n^2)$ 个数据强度 $\approx O(n)$。对大矩阵它是计算密集的——这就是 GPU高算力主导矩阵类 ML 负载的原因。逐元素运算ReLU、加、乘算术强度很低每个元素载入只做 1 次运算是访存密集的。让 GPU 更快没有用你需要更快的内存或者把这些算子与计算密集算子融合避免单独的内存往返。Roofline 模型也解释了为什么kernel 融合kernel fusion如此重要把 matmul、bias add 和 ReLU 合并进单一 kernel避免了中间结果写回内存再读回把三个访存密集操作变成一个计算密集操作。第 16 章第 0 篇中何时写自定义 C kernel一节对此有更细的展开。延迟 vs 吞吐量**延迟Latency**是完成一次操作的时间**吞吐量Throughput**是单位时间内完成的操作数。一个类比公交车延迟高每站都停但吞吐量大一次载 50 人出租车延迟低直达目的地但吞吐量小载 1~4 人。GPU 是公交车单次操作延迟高每条指令要很多周期才完成但吞吐量巨大数千核心并行处理。CPU 是出租车延迟低乱序执行、分支预测、深层缓存把延迟压到最小但吞吐量有限4~64 核。这正是 GPU 更适合 ML 训练吞吐量重要处理数百万样本而 CPU 更适合操作系统任务延迟重要立即响应按键的原因。**流水线Pipelining**把延迟转化为吞吐量。若一条指令需 5 个周期完成但流水线每周期启动一条新指令吞吐量就是每周期 1 条指令尽管每条要 5 个周期才完成。这与第 13 章的 CPU 流水线同理但它适用于每一层SIMD 单元、内存控制器、GPU 核心全部是流水线化的。芯片架构版图你为其写代码的硬件决定了可用的 SIMD 指令集。各主要架构一览x86Intel、AMD主导台式机、笔记本和数据中心 CPU。SIMDSSE128-bit、AVX/AVX2256-bit、AVX-512512-bit。Intel AMX 为 AI 负载提供专用矩阵乘单元。x86 SIMD 从 MMX 到 AMX 的演进史寄存器宽度、年份、关键特性见 x86 与 AVX。优势最高的单核性能、最宽的 SIMD、成熟的软件生态MKL、oneDNN。劣势功耗高、指令集复杂、价格昂贵。ARM主导移动端每部智能手机在服务器AWS Graviton、Ampere Altra与笔记本Apple M 系列增长迅猛。SIMDNEON128-bit、SVE/SVE2可扩展128~2048 bit。优势出色的能效每瓦性能定制核心Apple M4 在单核性能上以极低功耗比肩 Intel。劣势SIMD 较窄NEON 仅 128-bitSVE 可以更宽、HPC 软件生态较小。Apple SiliconM1/M2/M3/M4基于 ARM 并有定制增强。包含AMXApple Matrix eXtensions——未公开文档的矩阵乘单元Accelerate 框架用它做 BLAS 运算。统一内存架构CPU 与 GPU 共享同一物理内存消除了 CPU↔GPU 拷贝瓶颈。对 MLApple Neural Engine16 核专用 ML 加速器与统一内存让 M 系列芯片在本地 ML 推理和小规模训练上相当能打。但没有 CUDA必须用 MetalApple 的 GPU API或 MLXApple 的 ML 框架。RISC-V开源 ISA无授权费不像 ARM。在嵌入式、IoT 和研究领域增长。SIMDVvector扩展提供类似 ARM SVE 的可扩展向量处理。对 ML在 ML 负载上尚无法与 x86/ARM 竞争但值得关注——不少 AI 加速器创业公司使用 RISC-V 核心。GPUNVIDIA、AMD、Intel在本章第 04、05 篇深入展开。数千个面向吞吐量优化的简单核心。NVIDIA 凭 CUDA 主导 MLAMD 以 ROCm 竞争Intel 以 Arc GPU 和 Gaudi 加速器入场。CPU 与 GPU 的设计哲学差异核心数、时钟、缓存、分支预测、FLOPS、内存带宽对比表见 GPU 架构与 CUDA。TPUGoogle专为 ML 设计的定制 ASIC。以**脉动阵列systolic arrays**针对矩阵乘法优化。详见本章第 05 篇。热与功耗约束性能最终受制于功耗与散热TDPThermal Design Power芯片可持续消耗的最大功率。笔记本 CPU 约 15W服务器 CPU 约 250W数据中心 GPU 可达 700W如 NVIDIA B200。暗硅Dark silicon在任意时刻为了不超出热预算有相当比例的晶体管必须关掉。芯片理论上可同时使用全部晶体管但那样会熔化。能效FLOPS/watt正日益成为比原始 FLOPS 更重要的指标。这解释了为什么ARM 正在接管数据中心每瓦 FLOPS 优于 x86。TPU 尽管峰值 FLOPS 更低却能与 GPU 竞争在 ML 负载上每瓦 FLOPS 好得多。量化INT8、FP8不只是省内存它同时降低了每次运算的功耗。量化技术的细节见 第 17 章量化。大规模 ML训练一个前沿大语言模型要连续数月消耗兆瓦级电力电费可能超过硬件成本。能效直接决定 AI 研究的经济性。实践在 C 中测量性能要对性能做推理先得测量它。以下是最小化的 C 基准设置#include iostream #include chrono #include vector // Scalar addition void add_scalar(const float* a, const float* b, float* c, int n) { for (int i 0; i n; i) { c[i] a[i] b[i]; } } int main() { const int N 1 24; // ~16 million elements std::vectorfloat a(N, 1.0f), b(N, 2.0f), c(N); // Warm up (fill caches, trigger frequency scaling) add_scalar(a.data(), b.data(), c.data(), N); // Benchmark auto start std::chrono::high_resolution_clock::now(); for (int trial 0; trial 100; trial) { add_scalar(a.data(), b.data(), c.data(), N); } auto end std::chrono::high_resolution_clock::now(); double elapsed std::chrono::durationdouble(end - start).count(); double total_bytes 3.0 * N * sizeof(float) * 100; // read a, read b, write c double bandwidth total_bytes / elapsed / 1e9; // GB/s std::cout Time: elapsed s\n; std::cout Bandwidth: bandwidth GB/s\n; return 0; }# Compile with optimisations g -O3 -marchnative -o bench bench.cpp ./bench这段代码里的关键 C 概念更系统的 C 速成见第 16 章第 0 篇#include vector动态数组std::vectorfloat——类似 Python 的list但有类型且在内存中连续。a.data()返回底层数组的裸指针float*——SIMD 内在函数需要它。std::chrono用于基准测试的高精度计时器。-O3最大编译器优化级别。编译器可能自动向量化你的循环自动使用 SIMD。-marchnative启用你的 CPU 支持的全部 SIMD 指令。为什么需要热身warm up第一次运行会填充缓存并可能触发 CPU 频率提升turbo boost之后的运行才更有代表性。为什么测带宽对访存密集操作如逐元素加法有意义的指标是带宽GB/s而非 FLOPS。如果你的实测带宽接近硬件上限DDR5 约 50 GB/s你就是访存密集的SIMD 帮助不大——瓶颈是内存而非计算。与内存层级结合看上面的带宽测量与第 13 章的内存层级直接相关寄存器约 0.3 ns→ L1约 1 ns→ L2约 4 ns→ L3约 10 ns→ DRAM约 50–100 ns寄存器到内存的差距约 300 倍。这解释了为什么矩阵运算应按顺序访问内存行主序 vs 列主序布局至关重要batch size 影响性能更大的 batch 摊薄内存延迟混合精度float16/bfloat16让有效内存带宽翻倍——而这往往正是瓶颈。编码任务用 CoLab 或 notebook 完成1. 计算常见 ML 操作的算术强度并分类import jax.numpy as jnp def arithmetic_intensity(flops, bytes_transferred): return flops / bytes_transferred # Element-wise ReLU: 1 comparison per element, read write n 1024 relu_flops n # 1 op per element relu_bytes 2 * n * 4 # read input write output (float32) print(fReLU: {arithmetic_intensity(relu_flops, relu_bytes):.2f} FLOPS/byte → memory-bound) # Matrix multiply: 2*n^3 ops, read 2*n^2 write n^2 floats matmul_flops 2 * n**3 matmul_bytes 3 * n**2 * 4 # read A read B write C print(fMatmul ({n}×{n}): {arithmetic_intensity(matmul_flops, matmul_bytes):.0f} FLOPS/byte → compute-bound) # Layer norm: ~5n ops (mean, var, normalise), read write ln_flops 5 * n ln_bytes 2 * n * 4 print(fLayerNorm: {arithmetic_intensity(ln_flops, ln_bytes):.2f} FLOPS/byte → memory-bound) # Convolution 3x3: 2*9*C_in*C_out*H*W, read kernel feature map write output C_in, C_out, H, W 64, 128, 32, 32 conv_flops 2 * 9 * C_in * C_out * H * W conv_bytes (9 * C_in * C_out C_in * H * W C_out * H * W) * 4 print(fConv3x3: {arithmetic_intensity(conv_flops, conv_bytes):.0f} FLOPS/byte → compute-bound)运行结果印证了本章的核心判断ReLU 和 LayerNorm 是访存密集的每字节只有个位数的 FLOPS矩阵乘与 3×3 卷积是计算密集的每字节数千 FLOPS。在真实 kernel 优化中前者应做算子融合以减少内存往返后者才值得投入 SIMD / GPU 算力。2. 演示为什么并行重要import numpy as np import time for n in [1000, 10000, 100000, 1000000, 10000000]: a np.random.randn(n).astype(np.float32) b np.random.randn(n).astype(np.float32) # Sequential (Python loop) start time.time() c [a[i] * b[i] for i in range(min(n, 100000))] # cap at 100K for sanity seq_time time.time() - start if n 100000: seq_time * n / 100000 # extrapolate # Parallel (NumPy, uses SIMD multithreading internally) start time.time() c a * b par_time time.time() - start print(fn{n:10,} sequential{seq_time:.4f}s parallel{par_time:.6f}s fspeedup{seq_time/par_time:.0f}x)随着数据规模增长Python 逐元素循环与 NumPy 向量化内部调用 SIMD 优化的 C/BLAS 后端见第 16 章第 0 篇的框架结构之间的差距会扩大为数量级的加速比——这就是数据级并行的力量也是第 13 章并发与并行概念的实践演示。小结从硬件基础到后续章节的路线图本章第 16 章的路线图是一条不断升高的抽象阶梯C intrinsics最低层、控制最强→CUDAGPU 专用→Triton / PallasPython 化、可编译→JAX / PyTorch最高层、全自动。本文件解决的是最底层问题——硬件是什么样、性能从哪里来、用什么框架去思考性能Roofline接下来的文件在此基础上逐层展开文件 01本文硬件本身——CPU 架构、SIMD、Roofline、延迟/吞吐量、芯片版图、功耗约束文件 02–03CPU 上的 SIMD 编程ARM NEON、x86 AVX——用 C 使用 CPU 的向量单元文件 04CUDA GPU 编程——在数千个 GPU 核心上运行 C文件 05Triton、Pallas 等更高级的 GPU 编程——用 Python 写出编译为 GPU kernel 的代码。每一层都在用更少的控制换取更多的便利而理解了最底层你才能成为更优秀的上层使用者——这正是本文作为硬件基础存在的意义。【免费下载链接】maths-cs-ai-compendiumBecome a cracked AI/ML researcher/engineer with this unconventional textbook covering maths, computing, and ML with intuition.项目地址: https://gitcode.com/GitHub_Trending/mat/maths-cs-ai-compendium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表