-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Add intrusive iterators to BTree. #19796
Conversation
Unfortunately, tree structures are intrinsically slower to iterate over externally than internally. This can be demonstrated in benchmarks. In fact, it's so bad at external iteration that calling `.find` on each element in succession is currently slightly faster. This patch implements a faster intrusive way to iterate over BTrees. This is about 5x faster, but you lose all iterator composition infrastructure. This is a tradeoff that is acceptable in some applications. Relevant benchmarks: ``` test btree::map::bench::intrusive_iter_1000 ... bench: 2658 ns/iter (+/- 602) test btree::map::bench::intrusive_iter_100000 ... bench: 346353 ns/iter (+/- 189565) test btree::map::bench::intrusive_iter_20 ... bench: 55 ns/iter (+/- 16) test btree::map::bench::iter_1000 ... bench: 15892 ns/iter (+/- 3717) test btree::map::bench::iter_100000 ... bench: 1383714 ns/iter (+/- 444706) test btree::map::bench::iter_20 ... bench: 366 ns/iter (+/- 104) ``` r? @gankro @huonw @aturon how does this fit into 1.0 stabilization plans. Is marking this as #[experimental] enough?
605c97b
to
def348d
Compare
} | ||
} | ||
|
||
intrusive_into_iter_impl(self.root, &mut f); |
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.
Do you believe that the recursive version will be faster/more efficient than an explicit stack?
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 do, but only because the benchmarks as written agree.
Just like to say that this is really unfortunate to have to provide for performance. 😞 |
What's the B value and how do the results compare with a bit larger fan out? My immediate thought was to micro optimizations, like replacing Zip with an iterator that knows to do the bounds check once, but I realize now that the Zip part is common to both alternatives in this comparison. Is this a hint that a simpler b-tree external iterator can be written (maybe without range support?) |
I believe @pczarn was investigating this. One "easy" one would be to not support DoubleEnded. Another is we could probably ditch the RingBufs for Vecs, since pop_front should only happen if you're mixing next and next_back, which should already be slow. Also they can physically only get to like max ~40 depth or something. |
I'd like to flesh these ideas out out-of-tree for now. In particular https://github.com/reem/rust-traverse and https://github.com/Gankro/collect-rs/ are exploring this space right now. Only a performance issue, not a back-compat hazard. |
Unfortunately, tree structures are intrinsically slower to
iterate over externally than internally. This can be
demonstrated in benchmarks. In fact, it's so bad at external
iteration that calling
.find
on each element in successionis currently slightly faster.
This patch implements a faster intrusive way to iterate over
BTrees. This is about 5x faster, but you lose all iterator
composition infrastructure. This is a tradeoff that is
acceptable in some applications.
Relevant benchmarks:
r? @gankro @huonw @gereeter
@aturon how does this fit into 1.0 stabilization plans. Is
marking this as #[experimental] enough?