RoaringBitmap学习笔记
RoaringBitmap学习笔记
读代码时,看到一份roaring的实现,读了一下。下面总结下要点
实现思路
- roaringbitmap是一个contaner的数组。
- 每个container内部维护了2^16 个元素,最大有 2^16 个container,按高16位分桶。
- container 内有3种数据维护的方式:bitset,array,run(按区间维护[min, max])。
- roaringbitmap实现了不同的类型的container的各种and\or\xor等集合运算和查询方法,并且他们两两之间的集合运算,也都做了实现,类型互转都做了实现。
- 维护container时会根据数据分布,选择存储更优的container type。
添加一个元素对应方法: roaring_bitmap_add
- 计算高16位
- 二分找到高16位所在的container
- 找到对应的 containers时
- 获取位置i的container,以及他的type
- 将低16位,加入到这个container中
- 释放老的container
- 设置新的container
- 当没有找到所在的container时
- 对于不存在的container创建一个新的
- 将低16位,加入到这个container中
- 数组向后移一个位置,插入这个新的container
SMID指令加速有序集合的交集运算
论文:Fast Sorted-Set Intersection using SIMD Instructions
1. 使用 _mm_load_si128 加载v_a, v_b 2个向量
2. 利用_mm_cmpestrm实现向量内全部比较,同时_mm_extract_epi32获取r,表示 v_a 中哪几个数字在v_b中出现了

3. _mm_extract_epi32 分别提取,v_a和v_b中最大的元素(最后一个元素)
4. 将较小max值较大的指针向后移动(因为不可能再后之后的数字产生重复元素了)
5. 通过r查表,找到对应的排序mask,使用 _mm_shuffle_epi8 从 v_a 提取符合条件的数字,放到结果向量的前面
5. _mm_storeu_si128 将结果记录到 C 中
6. _mm_popcnt_u32 统计 r 中这一轮记录了多少个数字
int intersect(short *A, short *B,
int l_a, int l_b, short* C) {
int count = 0;
short i_a = 0, i_b = 0;
while(i_a < l_a && i_b < l_b) {
// 1. Load the vectors
__m128i v_a = _mm_load_si128((__m128i*)&A[i_a]);
__m128i v_b = _mm_load_si128((__m128i*)&B[i_b]);
// 2. Full comparison
__m128i res_v = _mm_cmpestrm(v_b, 8, v_a, 8,
_SIDD_UWORD_OPS|_SIDD_CMP_EQUAL_ANY|_SIDD_BIT_MASK);
int r = _mm_extract_epi32(res_v, 0);
unsigned short a7 = _mm_extract_epi32(v_a, 7);
unsigned short b7 = _mm_extract_epi32(v_b, 7);
A += ( a7 <= b7 ) * 8;
B += ( a7 >= b7 ) * 8;
// 3. Write back common values
__m128i p = _mm_shuffle_epi8(v_a, sh_mask[r]);
_mm_storeu_si128((__m128i*)&C[count], p);
count += _mm_popcnt_u32(r);
}
return count;
}

浙公网安备 33010602011771号