一. SIMD 的 store/ load 指令
1.1 selective store
将 vector lane(simd 寄存器) 的一部分(根据 mask)写入连续内存
1.2 selective load operation
从连续内存读入到 vector lane(simd 寄存器)
1.3 Gather operation
从非连续内存(根据 index vector)读入到 vector lane
1.4 Scatter operation
将 vector lane 写入到非连续内存(根据 index vector)
1.5 Issues:
二. Selection Scans
2.1 Scalar Braching 和 Branchless
实现:
性能对比:
如果条件的选择性既不是很低也不是很高,CPU 分支预测器就无法正确猜测分支结果,因此 no branching 比 branching 快。反之,如果选择性很低或者很高时,branching 更快。
2.2 Vectorized(SIMD)
卡比神总结(引用1):
使用 SIMD 结构利用评估谓词(selection)产生一个 bitmask,譬如 [0, 1, 1, 0] (0代表没有选择,1代表符合条件选择了)。
vector 选择每次从 bitmask 中选一个 bit 并访问元组,这样的话性能不好,因为选择性很低时,会有由于内存带宽造成的性能下降。见下图,其中没有被选择(x)的空间浪费掉了。
相反,使用 bitmask 一次将符合条件的元组存储到输出 vector 中,为了避免减少带宽,使用了一个小的 buffer,存储的是 index 而不是实际的值。 当 buffer 满时,从 buffer 重新加载 index,从列中收集实际值,输出到 output 中出。
见下图,也就是每次不直接输出,而是攒满一批后再输出。
selectivity 越大受到内存带宽的原因,其中 Xeon Phi 的机器会比 Xeon E3 的机器内存带宽更加大,所以向量化对比标量的优势更为明显。
2.3 Vectorized(SIMD) 多条件选择下 input selection vector 稀疏度的性能影响
出自论文 《Everything You Always Wanted to Know About Compiled and Vectorized Queries But Were Afraid to Ask》(引用2)
Sparse data loading occurs in all selection primitives except for the first one. From the second selection primitive on, all primi- tives receive a selection vector that determines the elements to con- sider for comparison. These elements must be gathered from non- contiguous memory locations.
多个条件下,从第二个条件开始,input selection vector (里面存有上一个条件选中的索引)的稀疏程度(选择率)会产生性能的不同。主要原因是因为当选择率低的时候,这些元素必须通过 simd gather 从非连续内存中加载到 simd 寄存器,会比较慢(这边感觉还不是有100%的理由进行解释)。那么和标量版本相比,选择率越低,这部分消耗的时间越多,优势也越不明显。
三. 引用
- 《Rethinking SIMD Vectorization for In-Memory Databases》
- 《Everything You Always Wanted to Know About Compiled and Vectorized Queries But Were Afraid to Ask》
- 卡比神写的专栏: https://zhuanlan.zhihu.com/p/432895054
- cum15721: https://15721.courses.cs.cmu.edu/spring2020/slides/15-vectorization1.pdf