bank conflict 举例说明
可以,我们就用一个最小、能手算清楚的例子,把为什么32会冲突、33不会冲突,直接算出来。
一、先定规则
假设:
- shared memory 有32 个 bank
- bank 编号规则是
[
bank = index \bmod 32
]
这里index指的是把二维数组线性展开后的位置。
row-major 展开公式:
[
index = row \cdot width + col
]
其中width是每一行长度。
二、先看tile[32][32]
数组:
__shared__floattile[32][32];所以每行长度:
[
width = 32
]
现在看一种访问方式
假设一个 warp 内 4 个线程先看,访问:
tile[tx][0]也就是:
- 线程0访问
tile[0][0] - 线程1访问
tile[1][0] - 线程2访问
tile[2][0] - 线程3访问
tile[3][0]
这是转置里常见的“按列取”。
1. 算 index
公式:
[
index = row \cdot 32 + col
]
这里col = 0
所以:
tile[0][0]:
[
index = 0 \cdot 32 + 0 = 0
]
tile[1][0]:
[
index = 1 \cdot 32 + 0 = 32
]
tile[2][0]:
[
index = 2 \cdot 32 + 0 = 64
]
tile[3][0]:
[
index = 3 \cdot 32 + 0 = 96
]
2. 算 bank
[
bank = index \bmod 32
]
所以:
- 线程0:
[
0 \bmod 32 = 0
]
- 线程1:
[
32 \bmod 32 = 0
]
- 线程2:
[
64 \bmod 32 = 0
]
- 线程3:
[
96 \bmod 32 = 0
]
3. 结果
4 个线程全都去bank 0
线程0 -> bank 0 线程1 -> bank 0 线程2 -> bank 0 线程3 -> bank 0这就是 bank conflict。
如果是 32 个线程,就会变成:
- 线程0 去 bank 0
- 线程1 也去 bank 0
- …
- 线程31 还去 bank 0
于是必须排队。
三、再看tile[32][33]
数组:
__shared__floattile[32][33];所以每行长度变成:
[
width = 33
]
还是看同样访问:
tile[tx][0]1. 算 index
公式变成:
[
index = row \cdot 33 + col
]
这里col = 0
所以:
tile[0][0]:
[
index = 0 \cdot 33 + 0 = 0
]
tile[1][0]:
[
index = 1 \cdot 33 + 0 = 33
]
tile[2][0]:
[
index = 2 \cdot 33 + 0 = 66
]
tile[3][0]:
[
index = 3 \cdot 33 + 0 = 99
]
2. 算 bank
[
bank = index \bmod 32
]
所以:
- 线程0:
[
0 \bmod 32 = 0
]
- 线程1:
[
33 \bmod 32 = 1
]
- 线程2:
[
66 \bmod 32 = 2
]
- 线程3:
[
99 \bmod 32 = 3
]
3. 结果
线程0 -> bank 0 线程1 -> bank 1 线程2 -> bank 2 线程3 -> bank 34 个线程去了 4 个不同 bank。
如果扩展到 32 个线程:
- 线程0 去 bank 0
- 线程1 去 bank 1
- …
- 线程31 去 bank 31
就完全并行了。
四、为什么 33 这么神奇
因为:
[
33 = 32 + 1
]
所以每换一行,起点不再是:
0, 32, 64, 96 ...而变成:
0, 33, 66, 99 ...也就是每一行都比前一行错开 1 个 bank。
五、再举一个带固定列的例子
比如访问:
tile[tx][5]对于tile[32][32]
[
index = tx \cdot 32 + 5
]
取 4 个线程:
- 线程0:
5 - 线程1:
37 - 线程2:
69 - 线程3:
101
算 bank:
5 mod 32 = 537 mod 32 = 569 mod 32 = 5101 mod 32 = 5
还是全撞到bank 5。
对于tile[32][33]
[
index = tx \cdot 33 + 5
]
取 4 个线程:
- 线程0:
5 - 线程1:
38 - 线程2:
71 - 线程3:
104
算 bank:
5 mod 32 = 538 mod 32 = 671 mod 32 = 7104 mod 32 = 8
分散开了。
六、你可以总结成一句话
对
32x32来说,按列访问时,相邻行地址差正好是 32,模 32 后全相同,所以撞 bank。
对32x33来说,按列访问时,相邻行地址差是 33,模 32 后每次加 1,所以分散到不同 bank。
七、最短记忆版
32:整齐对齐,容易撞33:错开一格,不容易撞
