Skip to content

Commit 5b5a198

Browse files
committed
Succinct counting Bloom filter: support non-BMI2 processors
1 parent 716f774 commit 5b5a198

File tree

1 file changed

+51
-46
lines changed

1 file changed

+51
-46
lines changed

src/counting_bloom.h

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,53 @@
66

77
#include "hashutil.h"
88

9-
#include <array>
10-
#include <type_traits>
119
#if defined(__BMI2__)
1210
#include <immintrin.h>
1311
#endif
1412

15-
16-
17-
1813
using namespace std;
1914
using namespace hashing;
2015

2116
namespace counting_bloomfilter {
2217

18+
inline int bitCount64(uint64_t x) {
19+
return __builtin_popcountll(x);
20+
}
21+
22+
inline int select64(uint64_t x, int n) {
23+
#if defined(__BMI2__)
24+
// with this, "add" is around 310 ns/key at 10000000 keys
25+
// from http://bitmagic.io/rank-select.html
26+
// https://github.com/Forceflow/libmorton/issues/6
27+
// This is a rather unusual usage of the bit deposit operation,
28+
// as we use the x as the mask, and we use n as the value.
29+
// We deposit (move) the bits of x = 1 << n to the locations
30+
// defined by x.
31+
uint64_t d = _pdep_u64(1ULL << n, x);
32+
// and now we count the trailing zeroes, to find out
33+
// where the '1' was deposited
34+
return __builtin_ctzl(d);
35+
// return _tzcnt_u64(d);
36+
#else
37+
// slow implementation
38+
// with this, "add" is around 680 ns/key at 10000000 keys
39+
for(int i = 0; i < 64; i++) {
40+
if ((x & 1) == 1) {
41+
if (n-- == 0) {
42+
return i;
43+
}
44+
}
45+
x >>= 1;
46+
}
47+
return -1;
48+
#endif
49+
}
50+
51+
inline int numberOfLeadingZeros64(uint64_t x) {
52+
// If x is 0, the result is undefined.
53+
return x == 0 ? 64 : __builtin_clzl(x);
54+
}
55+
2356
enum Status {
2457
Ok = 0,
2558
NotFound = 1,
@@ -66,7 +99,7 @@ Status CountingBloomFilter<ItemType, bits_per_item, branchless, HashFamily, k>::
6699
uint32_t b = (uint32_t)hash;
67100
for (int i = 0; i < k; i++) {
68101
uint index = reduce(a, this->arrayLength);
69-
data[index] += 1L << ((a << 2) & 63);
102+
data[index] += 1ULL << ((a << 2) & 63);
70103
a += b;
71104
}
72105
return Ok;
@@ -147,34 +180,6 @@ Status SuccinctCountingBloomFilter<ItemType, bits_per_item, branchless, HashFami
147180
return Ok;
148181
}
149182

150-
inline int numberOfLeadingZeros64(uint64_t x) {
151-
// If x is 0, the result is undefined.
152-
return x == 0 ? 64 : __builtin_clzl(x);
153-
}
154-
155-
inline int bitCount64(uint64_t x) {
156-
return __builtin_popcountll(x);
157-
}
158-
159-
160-
inline int selectInLong64(uint64_t x, int n) {
161-
// from http://bitmagic.io/rank-select.html
162-
// https://github.com/Forceflow/libmorton/issues/6
163-
uint64_t d = _pdep_u64(1L << n, x);
164-
return _tzcnt_u64(d);
165-
/*
166-
for(int i = 0; i < 64; i++) {
167-
if ((x & 1) == 1) {
168-
if (n-- == 0) {
169-
return i;
170-
}
171-
}
172-
x >>= 1;
173-
}
174-
return -1;
175-
*/
176-
}
177-
178183
template <typename ItemType, size_t bits_per_item, bool branchless,
179184
typename HashFamily, int k>
180185
void SuccinctCountingBloomFilter<ItemType, bits_per_item, branchless, HashFamily, k>::
@@ -191,8 +196,8 @@ void SuccinctCountingBloomFilter<ItemType, bits_per_item, branchless, HashFamily
191196
// allocate overflow
192197
index = nextFreeOverflow;
193198
if (index >= overflowLength) {
194-
::std::cout << "WARNING: overflow too small\n";
195-
data[group] |= 1L << bit;
199+
::std::cout << "ERROR: overflow too small\n";
200+
data[group] |= 1ULL << bit;
196201
return;
197202
}
198203
nextFreeOverflow = (size_t) overflow[index];
@@ -203,29 +208,29 @@ void SuccinctCountingBloomFilter<ItemType, bits_per_item, branchless, HashFamily
203208
// convert to a pointer
204209
for (int i = 0; i < 64; i++) {
205210
int n = ReadCount(group, i);
206-
overflow[index + i / 16] += n * (1L << (i * 4));
211+
overflow[index + i / 16] += n * (1ULL << (i * 4));
207212
}
208213
uint64_t count = 64;
209214
c = 0x8000000000000000L | (count << 32) | index;
210215
counts[group] = c;
211216
} else {
212217
// already
213218
index = (size_t) (c & 0x0fffffff);
214-
c += 1L << 32;
219+
c += 1ULL << 32;
215220
counts[group] = c;
216221
}
217-
overflow[index + bit / 16] += (1L << (bit * 4));
218-
data[group] |= 1L << bit;
222+
overflow[index + bit / 16] += (1ULL << (bit * 4));
223+
data[group] |= 1ULL << bit;
219224
return;
220225
}
221-
data[group] |= 1L << bit;
226+
data[group] |= 1ULL << bit;
222227
int bitsBefore = bitCount64(m & (0xffffffffffffffffL >> (63 - bit)));
223-
int before = selectInLong64((c << 1) | 1, bitsBefore);
228+
int before = select64((c << 1) | 1, bitsBefore);
224229
int insertAt = before - d;
225-
uint64_t mask = (1L << insertAt) - 1;
230+
uint64_t mask = (1ULL << insertAt) - 1;
226231
uint64_t left = c & ~mask;
227232
uint64_t right = c & mask;
228-
c = (left << 1) | ((1L ^ d) << insertAt) | right;
233+
c = (left << 1) | ((1ULL ^ d) << insertAt) | right;
229234
counts[group] = c;
230235
}
231236

@@ -246,8 +251,8 @@ int SuccinctCountingBloomFilter<ItemType, bits_per_item, branchless, HashFamily,
246251
return (int) (n & 15);
247252
}
248253
int bitsBefore = bitCount64(m & (0xffffffffffffffffL >> (63 - bit)));
249-
int bitPos = selectInLong64(c, bitsBefore - 1);
250-
uint64_t y = ((c << (63 - bitPos)) << 1) | (1L << (63 - bitPos));
254+
int bitPos = select64(c, bitsBefore - 1);
255+
uint64_t y = ((c << (63 - bitPos)) << 1) | (1ULL << (63 - bitPos));
251256
return numberOfLeadingZeros64(y) + 1;
252257
}
253258

0 commit comments

Comments
 (0)