Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upOptimize implementations of FromIterator and Extend for Vec #22681
Conversation
mzabaluev
added some commits
Feb 22, 2015
rust-highfive
assigned
Gankro
Feb 22, 2015
This comment has been minimized.
This comment has been minimized.
|
r? @Gankro (rust_highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
|
Can you post your experimental results. |
This comment has been minimized.
This comment has been minimized.
|
Does it optimize to a memcpy if the src is contiguous? If not then it will have to be changed anyway. |
pczarn
reviewed
Feb 22, 2015
| // self.push(item); | ||
| // } | ||
| loop { | ||
| match iterator.next() { |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Results of benchmarking on i686: https://gist.github.com/mzabaluev/df41c2f50464416b0a26 tl;dr: Notable losers are (observed consistently over multiple bench runs):
Winners:
Overall, I don't think too much trust should be put in microbenchmarks repeatedly testing one call-site optimized function. |
This comment has been minimized.
This comment has been minimized.
|
How much is "winning" and "losing'"? |
This comment has been minimized.
This comment has been minimized.
|
@mahkoh These changes should not drastically change the performance with slice iterators, in which case it's as close to |
This comment has been minimized.
This comment has been minimized.
|
@huonw I've added percentages to the comment above. |
This comment has been minimized.
This comment has been minimized.
|
Two of these methods have |
This comment has been minimized.
This comment has been minimized.
|
I actually ran benchmarks once with |
This comment has been minimized.
This comment has been minimized.
|
There should be more benchmarks with extending from sizeless/pessimistic iterators. Any good candidates in libcollections? |
This comment has been minimized.
This comment has been minimized.
|
BTreeMap's |
This comment has been minimized.
This comment has been minimized.
|
@pczarn Without looking too closely into the results (I get easily frustrated with the long build times of the library crates and their tests), I assume the optimizer has more "reason" to share |
mzabaluev
referenced this pull request
Feb 26, 2015
Closed
RFC: improve CString construction methods #912
This comment has been minimized.
This comment has been minimized.
|
How do we all feel about this PR today? |
This comment has been minimized.
This comment has been minimized.
|
Oh geez, this slipped right through the cracks! I don't have a great gut on this since it seems to just be shuffling perf around. r? @huonw |
rust-highfive
assigned
huonw
and unassigned
Gankro
Apr 22, 2015
huonw
reviewed
Apr 22, 2015
| if vector.len() == vector.capacity() { | ||
| for element in iterator { | ||
| vector.push(element); | ||
| let mut vector = match iterator.next() { |
This comment has been minimized.
This comment has been minimized.
huonw
Apr 22, 2015
Member
Hm, does this actually improve performance, over the simpler:
let mut vector = Vec::with_capacity(iterator.size_hint().0);
vector.extend_desugared(iterator);
vector
This comment has been minimized.
This comment has been minimized.
mzabaluev
Apr 22, 2015
Author
Contributor
This avoids a branch that is present in extend_desugared. That branch tends to be not taken, but in the first iteration the vector is always expanded.
This comment has been minimized.
This comment has been minimized.
huonw
Apr 22, 2015
Member
Hm, why it does it avoid that branch? It seems that if the iterator has a non-zero size hint the with_capacity will ensure that it isn't taken, and in the case that the iterator has a zero-size hint it seems both with and without this are equally bad off?
Basically, I'm asking if this was noticeable in practice.
This comment has been minimized.
This comment has been minimized.
mzabaluev
Apr 22, 2015
Author
Contributor
You are right, and it was somehow lost on me that Vec::with_capacity(1) allocates exactly one element. I should simplify the code to your suggestion; the performance difference will likely be negligible.
This comment has been minimized.
This comment has been minimized.
mzabaluev
Apr 23, 2015
Author
Contributor
With the suggested change, vec::bench_from_iter_0000 regresses
from 29 ns/iter (+/- 2) to 87 ns/iter (+/- 48) in my testing
(rebased against commit 3dbfa74), the other benchmarks seemingly unaffected. I wonder if it can be considered an edge case.
This comment has been minimized.
This comment has been minimized.
|
@huonw @mzabaluev What's up with this? |
alexcrichton
added
the
T-libs
label
May 26, 2015
This comment has been minimized.
This comment has been minimized.
|
Closing due to inactivity. |
Gankro
closed this
May 28, 2015
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@huonw Any reason not to merge this? |
This comment has been minimized.
This comment has been minimized.
|
huon's busy |
Gankro
reopened this
Jun 4, 2015
Gankro
reviewed
Jun 9, 2015
| while let Some(element) = iterator.next() { | ||
| let len = self.len(); | ||
| if len == self.capacity() { | ||
| let (lower, _) = iterator.size_hint(); |
This comment has been minimized.
This comment has been minimized.
Gankro
Jun 9, 2015
Contributor
Calling size_hint in a loop seems really bad. This is not necessarily a straight-forward or cheap method. Is hoisting it out not worth it in your testing?
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
At worst I like this better than the old code. r+ |
This comment has been minimized.
This comment has been minimized.
|
@bors r+ |
This comment has been minimized.
This comment has been minimized.
|
|
mzabaluev commentedFeb 22, 2015
Instead of a fast branch with a sized iterator falling back to a potentially poorly optimized iterate-and-push loop, a single efficient loop can serve all cases.
In my benchmark runs, I see some good gains, but also some regressions, possibly due to different inlining choices by the compiler. YMMV.