首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

CUDA 共享記憶體深度解析:Bank Conflict、同步與效能優化實戰

     編輯:關於C語言

CUDA 共享記憶體深度解析:Bank Conflict、同步與效能優化實戰

共享記憶體是 GPU 片上可編程快取,延遲比全域記憶體低 20-30 倍、頻寬高 10 倍。善用它需掌握 Bank 組織、存取模式、同步原語、資料佈局。

硬體架構

  • 每 SM 擁有 48KB/96KB/164KB 共享記憶體 (視架構)。
  • 劃分為 32 個 Bank (對應 Warp 32 執行緒),可並行存取。
  • Fermi (CC 2.x):4 Byte/Bank,bank = (addr/4)%32。
  • Kepler+ (CC 3.x+):8 Byte/Bank,bank = (addr/8)%32,相鄰 64-bit 同 Bank 無衝突。
  • 可動態切換:cudaDeviceSetSharedMemConfig(cudaSharedMemBankSizeFourByte/EightByte)。

三種存取模式與衝突

關鍵優化技巧

1. 二維陣列佈局:Row-Major 存取

__shared__ float tile[32][32];
// 好:連續 threadIdx.x 存取連續地址 → 無衝突
val = tile[threadIdx.y][threadIdx.x];
// 差:threadIdx.x 變化導致同 Bank → 32-way 衝突 (Fermi)
val = tile[threadIdx.x][threadIdx.y];

2. Padding 消除 Bank Conflict

// Fermi: +1 column 即可
__shared__ float tile[32][33]; // 32*33*4=4224B
// Kepler (8B/Bank): 需根據陣列大小試誤,可能需 +2/+4

3. 動態共享記憶體 + 手動索引

extern __shared__ int tile[]; // 1D
int row_idx = threadIdx.y * blockDim.x + threadIdx.x;
int col_idx = threadIdx.x * blockDim.y + threadIdx.y;
tile[row_idx] = ...; // Row-major 寫
__syncthreads();
val = tile[col_idx]; // Column-major 讀 → 有衝突

4. 同步原語

  • __syncthreads():Block 級 Barrier,所有執行緒到達才繼續。必須所有執行緒均遇到,否則死鎖。
  • __threadfence_block():Block 級 Memory Fence,確保寫入對 Block 內其他執行緒可見。
  • __threadfence() / __threadfence_system():Grid/系統級 Fence。
  • volatile:強制每次從共享/全域記憶體讀取,防編譯器快取優化。

實戰案例:歸約與矩陣轉置

  • Reduction:樹狀歸約在共享記憶體中,每步 __syncthreads(),避免 Warp Divergence。
  • Matrix Transpose:以 32x32 Tile 為單位,Row-major 讀全域 → 共享記憶體 → Column-major 寫全域,配合 Padding 消除共享記憶體衝突。

效能分析工具

nvprof --metrics shared_load_transactions_per_request,shared_store_transactions_per_request ./kernel
// 理想值 = 1.0,>1 表示有 Bank Conflict
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
模式描述衝突度吞吐
Parallel (無衝突)32 執行緒存取 32 不同 Bank1-way1 週期完成
Broadcast多執行緒讀同一地址1-way (硬體廣播)1 週期
Serial (衝突)多執行緒存取同 Bank 不同地址N-way (N=衝突執行緒數)N 週期序列化