Added CPU prefetch for skiplist

Summary:
This change causes following changes result of test:
./db_bench --writes 10000000 --benchmarks="fillrandom" --compression_type none
from
fillrandom   :       3.177 micros/op 314804 ops/sec;   34.8 MB/s
to
fillrandom   :       2.777 micros/op 360087 ops/sec;   39.8 MB/s
Closes https://github.com/facebook/rocksdb/pull/2961

Differential Revision: D5977822

Pulled By: yiwu-arbug

fbshipit-source-id: 1ea77707bffa978b1592b0c5d0fe76bfa1930f8d
main
Adam Kupczyk 7 years ago committed by Facebook Github Bot
parent 88ed1f6ea6
commit 75f7f42d41
  1. 25
      memtable/inlineskiplist.h

@ -239,6 +239,7 @@ class InlineSkipList {
// point to a node that is before the key, and after should point to // point to a node that is before the key, and after should point to
// a node that is after the key. after should be nullptr if a good after // a node that is after the key. after should be nullptr if a good after
// node isn't conveniently available. // node isn't conveniently available.
template<bool prefetch_before>
void FindSpliceForLevel(const char* key, Node* before, Node* after, int level, void FindSpliceForLevel(const char* key, Node* before, Node* after, int level,
Node** out_prev, Node** out_next); Node** out_prev, Node** out_next);
@ -446,6 +447,9 @@ InlineSkipList<Comparator>::FindGreaterOrEqual(const char* key) const {
Node* last_bigger = nullptr; Node* last_bigger = nullptr;
while (true) { while (true) {
Node* next = x->Next(level); Node* next = x->Next(level);
if (next != nullptr) {
PREFETCH(next->Next(level), 0, 1);
}
// Make sure the lists are sorted // Make sure the lists are sorted
assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x)); assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x));
// Make sure we haven't overshot during our search // Make sure we haven't overshot during our search
@ -485,6 +489,9 @@ InlineSkipList<Comparator>::FindLessThan(const char* key, Node** prev,
while (true) { while (true) {
assert(x != nullptr); assert(x != nullptr);
Node* next = x->Next(level); Node* next = x->Next(level);
if (next != nullptr) {
PREFETCH(next->Next(level), 0, 1);
}
assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x)); assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x));
assert(x == head_ || KeyIsAfterNode(key, x)); assert(x == head_ || KeyIsAfterNode(key, x));
if (next != last_not_after && KeyIsAfterNode(key, next)) { if (next != last_not_after && KeyIsAfterNode(key, next)) {
@ -535,6 +542,9 @@ uint64_t InlineSkipList<Comparator>::EstimateCount(const char* key) const {
while (true) { while (true) {
assert(x == head_ || compare_(x->Key(), key) < 0); assert(x == head_ || compare_(x->Key(), key) < 0);
Node* next = x->Next(level); Node* next = x->Next(level);
if (next != nullptr) {
PREFETCH(next->Next(level), 0, 1);
}
if (next == nullptr || compare_(next->Key(), key) >= 0) { if (next == nullptr || compare_(next->Key(), key) >= 0) {
if (level == 0) { if (level == 0) {
return count; return count;
@ -642,12 +652,21 @@ void InlineSkipList<Comparator>::InsertWithHint(const char* key, void** hint) {
} }
template <class Comparator> template <class Comparator>
template <bool prefetch_before>
void InlineSkipList<Comparator>::FindSpliceForLevel(const char* key, void InlineSkipList<Comparator>::FindSpliceForLevel(const char* key,
Node* before, Node* after, Node* before, Node* after,
int level, Node** out_prev, int level, Node** out_prev,
Node** out_next) { Node** out_next) {
while (true) { while (true) {
Node* next = before->Next(level); Node* next = before->Next(level);
if (next != nullptr) {
PREFETCH(next->Next(level), 0, 1);
}
if (prefetch_before == true) {
if (next != nullptr && level>0) {
PREFETCH(next->Next(level-1), 0, 1);
}
}
assert(before == head_ || next == nullptr || assert(before == head_ || next == nullptr ||
KeyIsAfterNode(next->Key(), before)); KeyIsAfterNode(next->Key(), before));
assert(before == head_ || KeyIsAfterNode(key, before)); assert(before == head_ || KeyIsAfterNode(key, before));
@ -668,7 +687,7 @@ void InlineSkipList<Comparator>::RecomputeSpliceLevels(const char* key,
assert(recompute_level > 0); assert(recompute_level > 0);
assert(recompute_level <= splice->height_); assert(recompute_level <= splice->height_);
for (int i = recompute_level - 1; i >= 0; --i) { for (int i = recompute_level - 1; i >= 0; --i) {
FindSpliceForLevel(key, splice->prev_[i + 1], splice->next_[i + 1], i, FindSpliceForLevel<true>(key, splice->prev_[i + 1], splice->next_[i + 1], i,
&splice->prev_[i], &splice->next_[i]); &splice->prev_[i], &splice->next_[i]);
} }
} }
@ -796,7 +815,7 @@ void InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
// search, because it should be unlikely that lots of nodes have // search, because it should be unlikely that lots of nodes have
// been inserted between prev[i] and next[i]. No point in using // been inserted between prev[i] and next[i]. No point in using
// next[i] as the after hint, because we know it is stale. // next[i] as the after hint, because we know it is stale.
FindSpliceForLevel(key, splice->prev_[i], nullptr, i, &splice->prev_[i], FindSpliceForLevel<false>(key, splice->prev_[i], nullptr, i, &splice->prev_[i],
&splice->next_[i]); &splice->next_[i]);
// Since we've narrowed the bracket for level i, we might have // Since we've narrowed the bracket for level i, we might have
@ -811,7 +830,7 @@ void InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
for (int i = 0; i < height; ++i) { for (int i = 0; i < height; ++i) {
if (i >= recompute_height && if (i >= recompute_height &&
splice->prev_[i]->Next(i) != splice->next_[i]) { splice->prev_[i]->Next(i) != splice->next_[i]) {
FindSpliceForLevel(key, splice->prev_[i], nullptr, i, &splice->prev_[i], FindSpliceForLevel<false>(key, splice->prev_[i], nullptr, i, &splice->prev_[i],
&splice->next_[i]); &splice->next_[i]);
} }
assert(splice->next_[i] == nullptr || assert(splice->next_[i] == nullptr ||

Loading…
Cancel
Save