Zhangzhe's Blog

The projection of my life.

0%

CUDA 基础之矩阵乘优化

CUDA(Compute Unified Device Architecture,统一计算设备架构)资料:

GPU 体系结构

  • 物理模型
    - 典型的 `GPU` 包含一组流处理器 (`stream multi-processors`, `SM`),每个流处理器都有许多核心,硬件实现上这些核心之间可共享内存(`shared memory`)
  • 逻辑模型
    - 逻辑模型中,引入了 `Grid` / `Block` / `Thread` 三级概念,逻辑模型与物理的对应关系如下:
    > 因此:同一个 `Block` 中的 `Thread` 可共享 `shared memory`
  • Memory Hierarchy
    memory_hierarchy.png

    shared memory 速度几乎和 L1 cache 一样,比 local memoryglobal memory 都快的多(在物理上,local memoryglobal memory 是同一块 DRAM

  • 在对 GPU 进行编程时,需要创建一组进程块 (thread blocks),每个 thread 映射到单个核心,而 block 映射到流式多处理器 (SM),如下图所示:
    2.png
  • 每个线程可由 threadIdxblockIdx 索引,在实际应用中,可以有多维线程索引

共享内存优化

  • 以矩阵乘为例,AR1024×1024,BR1024×1024A\in \mathbb{R}^{1024\times 1024},B\in \mathbb{R}^{1024\times 1024}
    4.png
    • 同一个 block 中的多个 thread 可共享内存,因此可以重排同一个 block 中的 thread 数据,使得尽可能少的数据缓存到 shared memory
    • 优化前:
      • 每个 thread 需要计算输出矩阵中 8 * 8 的数据,需要从 local memory 中读取 8 * 8 * 1024 * 2 数据
      • 每个 block 中的 thread 之间没有数据共享,所以需要从 local memory 中读取 888810242=2238 * 8 * 8 * 8 * 1024 * 2 = 2^{23} 个矩阵元素
    • 优化后:
      • 每个 block 计算输出矩阵的 64 * 64 的数据最少需要 6410242=21764 * 1024 * 2=2^{17} 的数据,可提前将这部分数据缓存到 shared memory
      • 然后每个 threadshared memory 读数据计算,需读取 6410242=21764 * 1024 * 2=2^{17} 个数据
    • 内存优化前后每个 block 读取数据对比:
      • 优化前:从 local memory 读取 2232^{23} 个矩阵元素
      • 优化后:从 local memory 读取 2172^{17} 个矩阵元素到 shared memory,再从 shared memory 读取 2172^{17} 个数据计算