Commit f85b4b76 authored by Giuseppe Ottaviano's avatar Giuseppe Ottaviano Committed by Noam Lerner

Reduce footprint of EliasFanoReader

Summary:
`EliasFanoReader` has a copy of `EliasFanoCompressedList` as member, but it only needs few of its members. With this diff, it only copies the members it needs.
Also, `progress_` is a duplicate of `upper_.position()`, so it was removed.
Microbenchmarks do not indicate any significant change in performance.

Test Plan: unit tests

Reviewed By: philipp@fb.com

Subscribers: chaoyc, search-fbcode-diffs@, unicorn-diffs@, folly-diffs@, yfeldblum, tudort, chalfant

FB internal diff: D2125956

Signature: t1:2125956:1433381848:2a333ce7a741bec5d059e9e771309463d6018ea2
parent a3537a0f
...@@ -522,6 +522,10 @@ class UpperBitsReader { ...@@ -522,6 +522,10 @@ class UpperBitsReader {
return skipToNext(v); return skipToNext(v);
} }
void setDone(size_t endPos) {
position_ = endPos;
}
private: private:
ValueType setValue() { ValueType setValue() {
value_ = static_cast<ValueType>(8 * outer_ + inner_ - position_); value_ = static_cast<ValueType>(8 * outer_ + inner_ - position_);
...@@ -555,52 +559,51 @@ class EliasFanoReader : private boost::noncopyable { ...@@ -555,52 +559,51 @@ class EliasFanoReader : private boost::noncopyable {
typedef typename Encoder::ValueType ValueType; typedef typename Encoder::ValueType ValueType;
explicit EliasFanoReader(const EliasFanoCompressedList& list) explicit EliasFanoReader(const EliasFanoCompressedList& list)
: list_(list), : size_(list.size),
lowerMask_((ValueType(1) << list_.numLowerBits) - 1), lower_(list.lower),
upper_(list_) { upper_(list),
lowerMask_((ValueType(1) << list.numLowerBits) - 1),
numLowerBits_(list.numLowerBits) {
DCHECK(Instructions::supported()); DCHECK(Instructions::supported());
// To avoid extra branching during skipTo() while reading // To avoid extra branching during skipTo() while reading
// upper sequence we need to know the last element. // upper sequence we need to know the last element.
if (UNLIKELY(list_.size == 0)) { if (UNLIKELY(list.size == 0)) {
lastValue_ = 0; lastValue_ = 0;
return; return;
} }
ValueType lastUpperValue = 8 * list_.upperSize() - list_.size; ValueType lastUpperValue = 8 * list.upperSize() - size_;
auto it = list_.upper + list_.upperSize() - 1; auto it = list.upper + list.upperSize() - 1;
DCHECK_NE(*it, 0); DCHECK_NE(*it, 0);
lastUpperValue -= 8 - folly::findLastSet(*it); lastUpperValue -= 8 - folly::findLastSet(*it);
lastValue_ = readLowerPart(list_.size - 1) | lastValue_ = readLowerPart(size_ - 1) | (lastUpperValue << numLowerBits_);
(lastUpperValue << list_.numLowerBits);
} }
void reset() { void reset() {
upper_.reset(); upper_.reset();
progress_ = 0;
value_ = 0; value_ = 0;
} }
bool next() { bool next() {
if (UNLIKELY(progress_ >= list_.size)) { if (UNLIKELY(position() + 1 >= size_)) {
return setDone(); return setDone();
} }
value_ = readLowerPart(progress_) | upper_.next();
(upper_.next() << list_.numLowerBits); value_ = readLowerPart(upper_.position()) |
++progress_; (upper_.value() << numLowerBits_);
return true; return true;
} }
bool skip(size_t n) { bool skip(size_t n) {
CHECK_GT(n, 0); CHECK_GT(n, 0);
progress_ += n; if (LIKELY(position() + n < size_)) {
if (LIKELY(progress_ <= list_.size)) {
if (LIKELY(n < kLinearScanThreshold)) { if (LIKELY(n < kLinearScanThreshold)) {
for (size_t i = 0; i < n; ++i) upper_.next(); for (size_t i = 0; i < n; ++i) upper_.next();
} else { } else {
upper_.skip(n); upper_.skip(n);
} }
value_ = readLowerPart(progress_ - 1) | value_ = readLowerPart(upper_.position()) |
(upper_.value() << list_.numLowerBits); (upper_.value() << numLowerBits_);
return true; return true;
} }
...@@ -615,7 +618,7 @@ class EliasFanoReader : private boost::noncopyable { ...@@ -615,7 +618,7 @@ class EliasFanoReader : private boost::noncopyable {
return setDone(); return setDone();
} }
size_t upperValue = (value >> list_.numLowerBits); size_t upperValue = (value >> numLowerBits_);
size_t upperSkip = upperValue - upper_.value(); size_t upperSkip = upperValue - upper_.value();
// The average density of ones in upper bits is 1/2. // The average density of ones in upper bits is 1/2.
// LIKELY here seems to make things worse, even for small skips. // LIKELY here seems to make things worse, even for small skips.
...@@ -632,9 +635,8 @@ class EliasFanoReader : private boost::noncopyable { ...@@ -632,9 +635,8 @@ class EliasFanoReader : private boost::noncopyable {
} }
bool jump(size_t n) { bool jump(size_t n) {
if (LIKELY(n - 1 < list_.size)) { // n > 0 && n <= list_.size if (LIKELY(n - 1 < size_)) { // n > 0 && n <= size_
progress_ = n; value_ = readLowerPart(n - 1) | (upper_.jump(n) << numLowerBits_);
value_ = readLowerPart(n - 1) | (upper_.jump(n) << list_.numLowerBits);
return true; return true;
} else if (n == 0) { } else if (n == 0) {
reset(); reset();
...@@ -651,27 +653,27 @@ class EliasFanoReader : private boost::noncopyable { ...@@ -651,27 +653,27 @@ class EliasFanoReader : private boost::noncopyable {
return setDone(); return setDone();
} }
upper_.jumpToNext(value >> list_.numLowerBits); upper_.jumpToNext(value >> numLowerBits_);
iterateTo(value); iterateTo(value);
return true; return true;
} }
size_t size() const { return list_.size; } size_t size() const { return size_; }
size_t position() const { return progress_ - 1; } size_t position() const { return upper_.position(); }
ValueType value() const { return value_; } ValueType value() const { return value_; }
private: private:
bool setDone() { bool setDone() {
value_ = std::numeric_limits<ValueType>::max(); value_ = std::numeric_limits<ValueType>::max();
progress_ = list_.size + 1; upper_.setDone(size_);
return false; return false;
} }
ValueType readLowerPart(size_t i) const { ValueType readLowerPart(size_t i) const {
DCHECK_LT(i, list_.size); DCHECK_LT(i, size_);
const size_t pos = i * list_.numLowerBits; const size_t pos = i * numLowerBits_;
const unsigned char* ptr = list_.lower + (pos / 8); const unsigned char* ptr = lower_ + (pos / 8);
const uint64_t ptrv = folly::loadUnaligned<uint64_t>(ptr); const uint64_t ptrv = folly::loadUnaligned<uint64_t>(ptr);
return lowerMask_ & (ptrv >> (pos % 8)); return lowerMask_ & (ptrv >> (pos % 8));
} }
...@@ -679,21 +681,21 @@ class EliasFanoReader : private boost::noncopyable { ...@@ -679,21 +681,21 @@ class EliasFanoReader : private boost::noncopyable {
void iterateTo(ValueType value) { void iterateTo(ValueType value) {
while (true) { while (true) {
value_ = readLowerPart(upper_.position()) | value_ = readLowerPart(upper_.position()) |
(upper_.value() << list_.numLowerBits); (upper_.value() << numLowerBits_);
if (LIKELY(value_ >= value)) break; if (LIKELY(value_ >= value)) break;
upper_.next(); upper_.next();
} }
progress_ = upper_.position() + 1;
} }
constexpr static size_t kLinearScanThreshold = 8; constexpr static size_t kLinearScanThreshold = 8;
const EliasFanoCompressedList list_; size_t size_;
const ValueType lowerMask_; const uint8_t* lower_;
detail::UpperBitsReader<Encoder, Instructions> upper_; detail::UpperBitsReader<Encoder, Instructions> upper_;
size_t progress_ = 0; const ValueType lowerMask_;
ValueType value_ = 0; ValueType value_ = 0;
ValueType lastValue_; ValueType lastValue_;
uint8_t numLowerBits_;
}; };
}} // namespaces }} // namespaces
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment