-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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 Extend::{extend_one,extend_reserve} #72162
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
This was developed from the discussion on #72085, overlapping but independent of #72159. I showed that it achieved similar performance to an imperative |
r? @dtolnay |
This comment has been minimized.
This comment has been minimized.
Bikeshed: push instead of extend_one? Are we using size hints already to pre-reserve? I would've expected an extend(Some(foo)) to basically compile down to a push - if that doesn't happen today, perhaps worth investigating? I think the only reason we have the somewhat awkward method names is also because Extend is im the prelude, right? So we don't want to use e.g. push and reserve? |
There's no way to do that in
Here's a playground of the benchmarks from #72085, and my local results:
Note that Looking at the assembly, the biggest difference I see is that That's particular to
Yeah, I think being in the prelude warrants caution in method ambiguity. |
I meant reserving in the Extend impls - those have an iterator to work with, so I would've expected it to be feasible there. But if there's an unconditional reserve already then maybe that is covered. I want to take a closer look at the diff, but I think in principle this is reasonable, so I'll probably approve it (we can bikeshed names on a tracking issue). |
Oh sure, in general, collections will reserve space in |
Okay, I haven't found the time to do the investigation myself I wanted to, but this seems like a good change regardless. Given the amount of code using extend (and zip etc) which is affected by this, I would like to @bors try @rust-timer queue though just to make sure we're not unduly generating more LLVM IR or something like that causing compile times to increase. Also, can someone on @rust-lang/libs sign off on adding these APIs (unstable for now)? Presuming we get a go-ahead can you file a tracking issue, @cuviper and update the attributes?
|
Awaiting bors try build completion |
⌛ Trying commit 36b7b8ee5ce9321f60e21c60f2f85d76cd0b1a0a with merge d448c21d56eddbda45277b26ed4f17faf4c5db3c... |
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.
Looks good to me to land unstable but I haven't gotten to review the whole PR yet, only collect.rs.
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.
r=me with tracking issue assigned
Implementation looks good to me, at least for an initial draft.
These methods look very out of place in the From an API design perspective, this seems to be asking for new |
@SimonSapin for the goal of improving |
I agree that they feel a bit out of place, although they do relatively naturally coincide with extending IMO. I don't think separate traits make a lot of sense, unfortunately, because we lack specialization (and aren't getting it anytime soon I imagine in flexible enough form). You really want to be able to call e.g. push and have that fallback to just extending if there's no separate push implementation defined. I would, though, be fine saying that these are internal methods not currently on a (clear) path to stabilization (and perhaps marking them as doc(hidden)). |
I've made the requested changes and filed tracking issue #72631. I guess we should at least wait for that perf run before merging though.
It would be a wart of its own to put third-party collections at a disadvantage. There's nothing technically special here to warrant permanent unstability, versus actual specialization. I think this is a relatively mild API choice, just with a bit of historical baggage that |
I'll see if I can reproduce the max-rss locally and track that down. Most of those The one hunch I have is with I guess it could also be that the new methods just mean more code, but I wouldn't think |
I blame jemalloc for the RSS variability, and I don't think my change really affected it. Here are my results on the worst in that report,
(measuring |
Hm, I wonder if we can configure jemalloc to be less variable or perhaps disable it on rust-timer entirely. cc @eddyb / @nnethercote Regardless seems like perf is fine -- @bors r+ I think we can discuss @SimonSapin's concern (#72162 (comment)) more on the tracking issue if the responses to the original comment didn't resolve it, given that this is just adding some unstable functionality and can easily be reverted if needed. |
📌 Commit 02226e0 has been approved by |
To understand the memory impact of changes I strongly recommend using either Massif or DHAT, if you are on Linux. Basic docs are here. If you try DHAT you need to look at the |
@nnethercote I just compiled |
@cuviper: that's a very strong indication that it's just noise, then. Indeed, https://perf.rust-lang.org/?start=&end=&absolute=true&stat=max-rss shows that keccak's max-rss numbers are extremely noisy. |
Add Extend::{extend_one,extend_reserve} This adds new optional methods on `Extend`: `extend_one` add a single element to the collection, and `extend_reserve` pre-allocates space for the predicted number of incoming elements. These are used in `Iterator` for `partition` and `unzip` as they shuffle elements one-at-a-time into their respective collections.
Add Extend::{extend_one,extend_reserve} This adds new optional methods on `Extend`: `extend_one` add a single element to the collection, and `extend_reserve` pre-allocates space for the predicted number of incoming elements. These are used in `Iterator` for `partition` and `unzip` as they shuffle elements one-at-a-time into their respective collections.
@bors r- |
This adds new optional methods on `Extend`: `extend_one` add a single element to the collection, and `extend_reserve` pre-allocates space for the predicted number of incoming elements. These are used in `Iterator` for `partition` and `unzip` as they shuffle elements one-at-a-time into their respective collections.
Co-authored-by: David Tolnay <dtolnay@gmail.com>
Rebased. @bors r=Mark-Simulacrum |
📌 Commit a51b22a has been approved by |
Rollup of 10 pull requests Successful merges: - rust-lang#72033 (Update RELEASES.md for 1.44.0) - rust-lang#72162 (Add Extend::{extend_one,extend_reserve}) - rust-lang#72419 (Miri read_discriminant: return a scalar instead of raw underlying bytes) - rust-lang#72621 (Don't bail out of trait selection when predicate references an error) - rust-lang#72677 (Fix diagnostics for `@ ..` binding pattern in tuples and tuple structs) - rust-lang#72710 (Add test to make sure -Wunused-crate-dependencies works with tests) - rust-lang#72724 (Revert recursive `TokenKind::Interpolated` expansion for now) - rust-lang#72741 (Remove unused mut from long-linker-command-lines test) - rust-lang#72750 (Remove remaining calls to `as_local_node_id`) - rust-lang#72752 (remove mk_bool) Failed merges: r? @ghost
This adds new optional methods on
Extend
:extend_one
add a singleelement to the collection, and
extend_reserve
pre-allocates space forthe predicted number of incoming elements. These are used in
Iterator
for
partition
andunzip
as they shuffle elements one-at-a-time intotheir respective collections.