Skip to content
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

Try to guess a smarter initial capacity in Vec::from_iter #53086

Closed
wants to merge 2 commits into from

Conversation

scottmcm
Copy link
Member

@scottmcm scottmcm commented Aug 5, 2018

Another possibility is collect could look at the upper bound and be smarter about what capacity to use? ~ #45840 (comment)

This is obviously good for hints like (60, Some(61)) where today we allocate space for 60, then double it should the additional element show up, and it'd be much better to just always allocate 61.

More nuanced are hints like (0, Some(150)), where today the code uses just the 0, and thus starts at a capacity of 1, but with this change will start at 10 instead.

This can undeniably increase memory pressure over where it is today, so I expect at least some controversy 🙂 It does use try_reserve for the allocation that's more than the lower bound, and thus shouldn't introduce new aborts, at least. And the starting point grows by the root, keeping things fairly contained: even with an hint of (0, Some(1_000_000_000)) it'll only start at 30_517.

cc @ljedrz
cc #48994

@rust-highfive
Copy link
Collaborator

r? @kennytm

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 5, 2018
@ljedrz
Copy link
Contributor

ljedrz commented Aug 5, 2018

This is potentially awesome not only for Option/Result::FromIterator, but also for all interators with a lower bound of zero (filters etc.). I would love to see a perf run.

@kennytm
Copy link
Member

kennytm commented Aug 5, 2018

@bors try

@bors
Copy link
Contributor

bors commented Aug 5, 2018

⌛ Trying commit fe30b5b with merge 8612aa2...

@kennytm kennytm added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 5, 2018
bors added a commit that referenced this pull request Aug 5, 2018
Try to guess a smarter initial capacity in Vec::from_iter

> Another possibility is collect could look at the upper bound and be smarter about what capacity to use?  ~ #45840 (comment)

This is obviously good for hints like `(60, Some(61))` where today we allocate space for 60, then double it should the additional element show up, and it'd be much better to just always allocate 61.

More nuanced are hints like `(0, Some(150))`, where today the code uses just the `0`, and thus starts at a capacity of `1`, but with this change will start at `10` instead.

This can undeniably increase memory pressure over where it is today, so I expect at least some controversy 🙂  It does use `try_reserve` for the allocation that's more than the lower bound, and thus shouldn't introduce new aborts, at least.  And the starting point grows by the root, keeping things fairly contained: even with an hint of `(0, Some(1_000_000_000))` it'll only start at `30_517`.

cc @ljedrz
cc #48994
@bors
Copy link
Contributor

bors commented Aug 5, 2018

☀️ Test successful - status-travis
State: approved= try=True

@kennytm
Copy link
Member

kennytm commented Aug 5, 2018

@rust-timer build 8612aa2

@rust-timer
Copy link
Collaborator

Success: Queued 8612aa2 with parent b47c314, comparison URL.

@kennytm
Copy link
Member

kennytm commented Aug 6, 2018

Perf is ready.

@kennytm kennytm removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 6, 2018
@ljedrz
Copy link
Contributor

ljedrz commented Aug 6, 2018

Some greens, some reds... I'd say the results are inconclusive 🤔.

@scottmcm
Copy link
Member Author

scottmcm commented Aug 6, 2018

Hmm, for instructions things seem slightly worse overall :(

How reliable are the time measurements? It's interesting that webrender-clean-opt is +0.3% for instructions:u, but -1.5% for wall-time.

(Another thing that surprised me: max-rss -3.5% for webrender-debug-clean.)

I think I'll try something less complicated than the sqrt approximation for the guess; maybe it's just not worth doing that work and making LLVM compile it when people use Vec, even though it's simple integer instructions. (It's less and less helpful the larger the gap anyway.)

@kennytm kennytm added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 7, 2018
This one only helps lower>0, but by doing so means it's always strictly less than 100% overhead, same as the normal doubling algorithm.  And thus doesn't need to do the try_reserve dance or a post-extend cleanup.
@scottmcm
Copy link
Member Author

scottmcm commented Aug 8, 2018

Ok, I've pushed a much simpler change that's only targeted at one side of the problem. Could I get another try+perf run to see whether it's fruitful overall, please?

@kennytm
Copy link
Member

kennytm commented Aug 8, 2018

@bors try

@bors
Copy link
Contributor

bors commented Aug 8, 2018

⌛ Trying commit aa080f4 with merge 68f12661b56cdca600c5eca7158eb2ba4026e7f3...

@kennytm kennytm added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-perf Status: Waiting on a perf run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 8, 2018
@bors
Copy link
Contributor

bors commented Aug 8, 2018

☀️ Test successful - status-travis
State: approved= try=True

@kennytm
Copy link
Member

kennytm commented Aug 8, 2018

@rust-timer build 68f12661b56cdca600c5eca7158eb2ba4026e7f3

@rust-timer
Copy link
Collaborator

Success: Queued 68f12661b56cdca600c5eca7158eb2ba4026e7f3 with parent 26d7b64, comparison URL.

@kennytm
Copy link
Member

kennytm commented Aug 9, 2018

Perf is ready.

@kennytm kennytm removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 9, 2018
@scottmcm
Copy link
Member Author

Hmm, that's again a bit too mixed for me to be happy about.

I'll just close this. Anyone interested should feel free to pick this space up again; feel free to use or ignore anything I did in this PR 🙂

@scottmcm scottmcm closed this Aug 12, 2018
bors added a commit to rust-lang-ci/rust that referenced this pull request Jan 20, 2022
…rom_iter_48994_2, r=Mark-Simulacrum

Improve capacity estimation in Vec::from_iter

Iterates on the attempt made in rust-lang#53086.

Closes rust-lang#48994
@qm3ster
Copy link
Contributor

qm3ster commented Jan 26, 2022

Is lower.saturating_add(1) actually a good idea?
There are many cases, like filtering, where the lower bound becomes 0.
Wouldn't it be better to defer allocation until there's an actual item, at which point follow Vec's built-in allocation strategy?

On the other hand, what this PR seems to be trying to solve is that it's impossible to inform the Vec of the upper bound.
Imagine Vec::from_iter((0..128).chain((0..2).filter(|_|true))) for example.
This will currently reserve 129 and then reallocate to much more than the hard upper bound, even though the very close upper bound of 130 was available.
why did I rewrite the OP lol

@scottmcm
Copy link
Member Author

@qm3ster Note that this PR is approaching 4 years old, so you might have meant to comment somewhere else.

But the reason the saturating_add(1) is there is that the hint it looked at after calling next for the first time. So we need to add one for the item we already have.

(And it's done this way because some iterators only really return a useful hint after looking at an item -- flat_map being the easiest example.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants