-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
reduce the number of calls to operator< made by lower_bound and upper… #2882
Conversation
fdbclient/VersionedMap.h
Outdated
} | ||
|
||
template<class T, class X> | ||
void upper_bound(const Reference<PTree<T>>& p, Version at, const X& x, std::vector<const PTree<T>*>& f){ | ||
void lower_bound(const Reference<PTree<T>>& p, Version at, const X& x, std::vector<const PTree<T>*>& f) { | ||
std::vector<bool> lessThan; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I follow, there's an implicit invariant that lessThan.size() == f.size()
. Can we assert that f.size() == 0
here? We might also consider changing f to std::vector<std::pair<const PTree<T>*, bool>>
then. Not sure which would perform better, but I think the vector of pairs closer matches the intent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add the assert. f
is actually the thing this method returns, and I didn't want to change the signature.
@@ -114,30 +114,51 @@ namespace PTreeImpl { | |||
return contains(p->child(!less, at), at, x); | |||
} | |||
|
|||
// TODO: Remove the number of invocations of operator<, and replace with something closer to memcmp. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bool operator<(const StringRef&, const StringRef&)
is implemented using memcmp already, is that not close enough? Is the goal to not lose the extra information memcmp provides? Then we wouldn't need to call operator< twice to confirm x == p->data
below.
Btw #2875 seems related.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The goal is to avoid losing the extra information. I'm working on a second PR that adds a compare operator to everything that's stored by these data structures (and remove the call to confirm ==), but that's a more invasive change.
fdbclient/VersionedMap.h
Outdated
if (!p) { | ||
while (f.size() && !(x < f.back()->data)) | ||
while (f.size() && !(x < f.back()->data)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not use lessThan.back()
instead of x < f.back()->data
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Without that, this change doesn't actually help anything.
The force push added the asserts and the lessThan.back() call. |
@fdb-build test this please |
return iterator(t); | ||
t = t->child[d]; | ||
if (cmp == 0) return iterator(t); | ||
t = t->child[cmp > 0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a functional change? I think the equivalent code would be t = t->child[cmp >= 0]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just returned if cmp==0
on the previous line, so cmp > 0
is the same as cmp >= 0
.
flow/IndexedSet.h
Outdated
@@ -871,8 +874,6 @@ void IndexedSet<T,Metric>::erase( typename IndexedSet<T,Metric>::iterator begin, | |||
// Removes all nodes in the set between first and last, inclusive. | |||
// toFree is extended with the roots of completely removed subtrees. | |||
|
|||
ASSERT(!end.i || (begin.i && *begin <= *end)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this removed because it's expensive? Can we still call the assert in simulation at least?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. How do I add a simulation-only assert?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can guard it with g_network->isSimulated()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not available here (it's defined in flow.h, which includes this file). I put the assert back in place.
fe6054c
to
fd8f7a6
Compare
675eb75
to
a88a5ba
Compare
This should be ready to get more eyeballs on it. I benchmarked it yesterday, and got these results. 18 of 42 experiments showed throughput differences at 99% confidence. Here they are (operators is the name of the experiment run; everything else should be self-explanatory).
A quick check suggests I fixed the Changing to the |
flow/Arena.h
Outdated
size_t minSize = std::min(size(), other.size()); | ||
if (minSize != 0) { | ||
int c = memcmp(begin(), other.begin(), minSize); | ||
if (c != 0) return { c < 0, false, c > 0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not convinced this is faster than doing if (c != 0) return c < 0 ? { -1 } : { 1 };
The changes in Redwood unfortunately will conflict with a lot of changes in |
…e to 96 based on calculation in check()
@sears Is there an updated performance results? |
I don't have updated numbers, but I was testing as I went along. Moving from I couldn't get circus to run anything yesterday, so I don't have end-to-end numbers. The idea is to merge this, and see if we see any improvement in the nightlies. |
inline bool operator > ( const ExtStringRef& lhs, const ExtStringRef& rhs ) { return lhs.cmp(rhs)>0; } | ||
inline bool operator <= ( const ExtStringRef& lhs, const ExtStringRef& rhs ) { return lhs.cmp(rhs)<=0; } | ||
inline bool operator >= ( const ExtStringRef& lhs, const ExtStringRef& rhs ) { return lhs.cmp(rhs)>=0; } | ||
inline bool operator<(const ExtStringRef& lhs, const ExtStringRef& rhs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is possible to replace these functions with global templates taking const T &
for both arguments such that the template is ignored if T does not have a .compare()
member.
// This is as good a place as any, I guess. | ||
|
||
template <typename T> | ||
typename std::enable_if<std::is_integral<T>::value, int>::type compare(T l, T r) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return type should be a signed integer of the same precision, I think something of the form
typename std::make_signed<T>::type
will get you that, and then the implementation can just be l - r
.
EDIT: Nevermind, the result can be wrong for unsigned types, the return type would actually need to be a larger precision signed number to catch all cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that this file is the best place for these definitions, but then I also don't have a better suggestion so I guess it's fine.
…eneration for that seems a bit more stable, and it is probably more commonly used than "(l > r) - (l < r)"
Apparently Rusty isn't in our CI as someone to automatically run for, and this broke the build. |
…_bound #2877