Avoid integer division in filter probing (#4071)
Summary: The cache line size was computed dynamically based on the length of the filter bits, and the number of cache-lines encoded in the footer. This calculation had to be dynamic in case users migrate their data between platforms with different cache line sizes. The downside, though, was bloom filter probing became expensive as it did integer mod and division. However, since we know all possible cache line sizes are powers of two, we should be able to use bit shift to find the cache line, and bitwise-and to find the bit within the cache line. To do this, we compute the log-base-two of cache line size in the constructor, and use that in bitwise operations to replace division/mod. Pull Request resolved: https://github.com/facebook/rocksdb/pull/4071 Differential Revision: D8684067 Pulled By: ajkr fbshipit-source-id: 50298872fba5acd01e8269cd7abcc51a095e0f61
This commit is contained in:
parent
8abafb1feb
commit
a1a546a634
@ -144,13 +144,31 @@ class FullFilterBitsReader : public FilterBitsReader {
|
||||
: data_(const_cast<char*>(contents.data())),
|
||||
data_len_(static_cast<uint32_t>(contents.size())),
|
||||
num_probes_(0),
|
||||
num_lines_(0) {
|
||||
num_lines_(0),
|
||||
log2_cache_line_size_(0) {
|
||||
assert(data_);
|
||||
GetFilterMeta(contents, &num_probes_, &num_lines_);
|
||||
// Sanitize broken parameter
|
||||
if (num_lines_ != 0 && (data_len_-5) % num_lines_ != 0) {
|
||||
num_lines_ = 0;
|
||||
num_probes_ = 0;
|
||||
} else if (num_lines_ != 0) {
|
||||
while (true) {
|
||||
uint32_t num_lines_at_curr_cache_size =
|
||||
(data_len_ - 5) >> log2_cache_line_size_;
|
||||
if (num_lines_at_curr_cache_size == 0) {
|
||||
// The cache line size seems not a power of two. It's not supported
|
||||
// and indicates a corruption so disable using this filter.
|
||||
assert(false);
|
||||
num_lines_ = 0;
|
||||
num_probes_ = 0;
|
||||
break;
|
||||
}
|
||||
if (num_lines_at_curr_cache_size == num_lines_) {
|
||||
break;
|
||||
}
|
||||
++log2_cache_line_size_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,6 +191,7 @@ class FullFilterBitsReader : public FilterBitsReader {
|
||||
uint32_t data_len_;
|
||||
size_t num_probes_;
|
||||
uint32_t num_lines_;
|
||||
uint32_t log2_cache_line_size_;
|
||||
|
||||
// Get num_probes, and num_lines from filter
|
||||
// If filter format broken, set both to 0.
|
||||
@ -222,19 +241,20 @@ bool FullFilterBitsReader::HashMayMatch(const uint32_t& hash,
|
||||
// It is ensured the params are valid before calling it
|
||||
assert(num_probes != 0);
|
||||
assert(num_lines != 0 && (len - 5) % num_lines == 0);
|
||||
uint32_t cache_line_size = (len - 5) / num_lines;
|
||||
const char* data = filter.data();
|
||||
|
||||
uint32_t h = hash;
|
||||
const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits
|
||||
uint32_t b = (h % num_lines) * (cache_line_size * 8);
|
||||
// Left shift by an extra 3 to convert bytes to bits
|
||||
uint32_t b = (h % num_lines) << (log2_cache_line_size_ + 3);
|
||||
PREFETCH(&data[b / 8], 0 /* rw */, 1 /* locality */);
|
||||
PREFETCH(&data[b / 8 + cache_line_size - 1], 0 /* rw */, 1 /* locality */);
|
||||
PREFETCH(&data[b / 8 + (1 << log2_cache_line_size_) - 1], 0 /* rw */,
|
||||
1 /* locality */);
|
||||
|
||||
for (uint32_t i = 0; i < num_probes; ++i) {
|
||||
// Since CACHE_LINE_SIZE is defined as 2^n, this line will be optimized
|
||||
// to a simple and operation by compiler.
|
||||
const uint32_t bitpos = b + (h % (cache_line_size * 8));
|
||||
const uint32_t bitpos = b + (h & ((1 << (log2_cache_line_size_ + 3)) - 1));
|
||||
if (((data[bitpos / 8]) & (1 << (bitpos % 8))) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user