Skip to content

子字并行

1. 子字并行 (Subword Parallelism) 概述

1.1. 产生背景

  • 图形与多媒体需求:现代计算机普遍配备图形显示器,推动处理器增加对图形和音频操作的支持。
    • 图形:常使用8位数据表示颜色分量(如RGB)。
    • 音频:采样通常需要8位以上精度,16位已足够。
  • 数据特性:许多视频和音频应用中,通常对一组较窄位宽的数据(向量)执行相同的操作。

1.2. 定义与原理

  • 子字并行:指在一个较宽的数据字(如64位、128位、256位甚至更宽)内部,将这个宽字分割成多个较窄的数据单元(子字,如8位、16位、32位),并对这些子字同时执行相同的并行操作。
  • 实现方式:通过在宽字内部对进位链等算术逻辑单元进行分割,使得处理器可以同时处理多个子字。例如,一个128位的加法器可以被配置为:
    • 同时执行 16 个 8 位加法
    • 同时执行 8 个 16 位加法
    • 同时执行 4 个 32 位加法
    • 同时执行 2 个 64 位加法
  • 成本:对加法器等进行此类分割的硬件开销相对较小。

1.3. 别称与相关概念

  • 数据级并行 (Data-Level Parallelism, DLP):更通用的术语,子字并行是其一种形式。
  • 向量处理 (Vector Processing)
  • SIMD (Single Instruction, Multiple Data):单指令多数据流。一条指令作用于多个数据元素。

2. ARM NEON 多媒体指令集扩展

2.1. 概述

  • ARM为支持子字并行,在NEON多媒体指令集中增加了超过100条指令 (ARMv7/ARMv8)。
  • 寄存器:NEON引入了新的宽寄存器,例如:
    • 128位宽寄存器(可视为多个不同宽度的子字寄存器,如 Q 寄存器)。
    • 更新:后续ARM架构如SVE/SVE2支持更灵活的向量长度,可能达到2048位。

2.2. 支持的数据类型 (NEON)

几乎涵盖所有常见的子字数据类型(除了64位浮点数,早期NEON主要关注单精度和整数): * 8位、16位、32位、64位有符号和无符号整数。 * 32位浮点数 (单精度)。

2.3. 定点数支持

  • ARM NEON 还支持 I8, I16, I32, I64 定点 (Fixed-point) 格式。
  • 定点数:一部分表示整数部分,一部分表示小数部分,二进制小数点位置由软件约定。
  • 优势:对于没有硬件浮点单元 (FPU) 的ARM处理器,定点运算比软件实现的浮点库快得多。
  • 劣势:需要程序员进行更多的工作来管理小数点位置和溢出。

3. x86 中的 SIMD 扩展:MMX, SSE, AVX

3.1. 发展历程

  • MMX (MultiMedia eXtension):早期x86的SIMD扩展,主要针对整数操作,复用浮点寄存器。
  • SSE (Streaming SIMD Extension):引入了新的128位专用寄存器 (XMM0-XMM7,后来AMD64扩展到XMM0-XMM15) 和针对单精度浮点数的SIMD操作。
  • SSE2:在SSE基础上增加了对双精度浮点数和更多整数类型的SIMD支持。
  • AVX (Advanced Vector Extensions)
    • 将SIMD寄存器宽度从128位 (XMM) 扩展到256位 (YMM)。
    • YMM寄存器的低128位与对应的XMM寄存器兼容。
    • 引入了三地址指令格式 (e.g., dest = src1 + src2),减少了指令数量和寄存器压力。
    • SSE/SSE2指令可以通过添加 V 前缀并使用YMM寄存器名来升级为AVX指令,操作YMM寄存器的低128位或整个256位。

3.2. AVX 扩展

  • YMM 寄存器:256位宽,可容纳:
    • 8个单精度浮点数。
    • 4个双精度浮点数。
  • 指令示例转换
    • SSE2: addpd %xmm0, %xmm4 (2个双精度加法: %xmm4 = %xmm4 + %xmm0)
    • AVX: vaddpd %ymm0, %ymm1, %ymm4 (4个双精度加法: %ymm4 = %ymm1 + %ymm0, 使用三地址形式)

4. 性能加速实例:子字并行与矩阵乘法 (DGEMM)

4.1. DGEMM (Double-precision General Matrix Multiply)

一个常见的科学计算核心操作:C = C + A * B

4.2. 未优化版本

  • 三重嵌套循环,逐元素计算。
  • 在 Intel Core i7 (Sandy Bridge, 2.6GHz, Turbo关闭) 单核上性能: 1.7 GFLOPS (每秒十亿次浮点操作)。

4.3. 优化版本

  • 思路:利用AVX指令一次处理多个双精度浮点数 (4个,因为YMM是256位,双精度是64位)。
  • 关键Intrinsic函数 (编译器内建函数,直接映射到特定指令):
    • _m256d: AVX的256位数据类型,用于存储4个双精度浮点数。
    • _mm256_load_pd(double* mem_addr): 从内存加载4个双精度数到YMM寄存器 (packed double)。
    • _mm256_store_pd(double* mem_addr, _m256d data): 将YMM寄存器中的4个双精度数存回内存。
    • _mm256_add_pd(_m256d a, _m256d b): 并行加法,4对双精度数相加。
    • _mm256_mul_pd(_m256d a, _m256d b): 并行乘法。
    • _mm256_broadcast_sd(double* mem_addr): 将内存中的一个双精度标量值复制扩展到YMM寄存器的所有4个双精度元素位置。这用于将矩阵B的一个元素与矩阵A的一行中的多个元素相乘。
  • 循环调整:外层循环 i 每次增加4 (因为一次处理4行或4个C矩阵的元素)。
  • 性能:在相同硬件条件下: 6.4 GFLOPS
  • 加速比6.4 / 1.7 ≈ 3.85 倍,接近理论上的4倍加速 (因为一次处理4个元素)。

4.4. 汇编代码对比

  • 图 3-22 (未优化C编译的内循环):虽然编译器可能使用了AVX的3地址格式指令 (如vmovsd, vmulsd, vaddsd),但它们操作的是XMM寄存器中的标量双精度 (sd),即一次只处理一个双精度数。
  • 图 3-24 (优化C编译的内循环):使用了YMM寄存器和并行双精度 (pd) 指令 (如 vmovapd, vbroadcastsd, vmulpd, vaddpd),实现了真正的子字并行。

4.5. Intel Turbo Boost 影响

  • Turbo Boost:Intel的一种动态超频技术,在散热允许的情况下,暂时提高处理器核心的时钟频率。
  • 若开启Turbo模式 (频率从2.6GHz提升到3.3GHz,约1.27倍):
    • 未优化DGEMM性能: 1.7 * 1.27 ≈ 2.1 GFLOPS
    • AVX优化DGEMM性能: 6.4 * 1.27 ≈ 8.1 GFLOPS
  • Turbo模式在单核负载较高而其他核心负载较低时效果更明显,因为单个核心可以获得更多的功耗预算。

5. 总结

子字并行 (SIMD) 技术通过在单个指令周期内对多个较小数据单元执行相同操作,显著提高了数据密集型应用(如图形、音视频处理、科学计算)的性能。现代处理器(如ARM NEON, Intel SSE/AVX)都提供了丰富的SIMD指令集和宽寄存器来支持这种并行性。通过编译器优化或使用内建函数 (intrinsics),开发者可以利用这些硬件特性来大幅提升程序性能。