Skip to content

Kernel 3: Bank Conflict Free

通过填充消除共享内存 bank 冲突

共享内存 Bank 详解

内存组织

GPU 共享内存分为 32 个 bank(现代架构)。每个 bank 每时钟周期可服务一次访问。

地址 → Bank 索引:  address % 32

Bank 0  Bank 1  ...  Bank 31
┌─────┐ ┌─────┐     ┌─────┐
│ [0] │ │ [1] │ ... │ [31]│  ← 地址 0-31
├─────┤ ├─────┤     ├─────┤
│ [32]│ │ [33]│ ... │ [63]│  ← 地址 32-63
├─────┤ ├─────┤     ├─────┤
│ ... │ │ ... │ ... │ ... │
└─────┘ └─────┘     └─────┘

冲突场景

cpp
__shared__ float tile[32][32];

// 在内积循环中:
for (int k = 0; k < 32; ++k) {
    sum += tile[ty][k] * tile[k][tx];  // 所有线程访问第 k 列
}

当 warp 中的线程读取 tile[k][0], tile[k][1], ..., tile[k][31] 时:

  • 线程 0 访问地址:k * 32 + 0 → Bank (k * 32) % 32 = 0
  • 线程 1 访问地址:k * 32 + 1 → Bank (k * 32) % 32 = 0
  • ...
  • 线程 31 访问地址:k * 32 + 31 → Bank (k * 32) % 32 = 0

结果:所有 32 个线程同时命中 Bank 032 路冲突

性能影响

指标Tiled (32×32)Bank-Free (32×33)改进
GFLOPS (1024³)753673略有变化
Bank 冲突32 路已消除
共享内存8 KB8.4 KB+5.5% 开销
访问周期32×32× 更快

Bank-free kernel 在不同场景下提供更一致的性能。

关键要点

  1. 32 个 Bank:共享内存分为 32 个 bank(现代 GPU)
  2. 冲突:多个线程命中同一 bank 时访问串行化
  3. 填充:第二维加 1 将步长从 32 变为 33
  4. 公式:Bank 索引 = (row × (TILE_SIZE + 1) + col) % 32
  5. 开销:仅 3% 更多共享内存换取 32× 性能提升

MIT Licensed