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

BTreeMap: introduce marker::ValMut and reserve Mut for unique access #75200

Merged
merged 1 commit into from
Sep 5, 2020

Conversation

ssomers
Copy link
Contributor

@ssomers ssomers commented Aug 5, 2020

The mutable BTreeMap iterators (apart from DrainFilter) are double-ended, meaning they have to rely on a front and a back handle that each represent a reference into the tree. Reserve a type category marker::ValMut for them, so that we guarantee that they cannot reach operations on handles with borrow type marker::Mutand that these operations can assume unique access to the tree.

Including #75195, benchmarks report no genuine change:

benchcmp old new --threshold 5
 name                                 old ns/iter  new ns/iter  diff ns/iter   diff %  speedup
 btree::map::iter_100                 3,333        3,023                -310   -9.30%   x 1.10
 btree::map::range_unbounded_vs_iter  36,624       31,569             -5,055  -13.80%   x 1.16

r? @Mark-Simulacrum

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

ssomers commented Aug 6, 2020

I wonder if we should allow copies of ValMut handles, just like for Immut handles. ValMut-based iterators (so all but IntoIter and DrainFilter) already thrive in pairs, front and back, and client code can switch between them willy-nilly, thus juggling with handles to the same or different nodes. We (probably) still don't want client code to copy iterators and reach the same element twice and pry out multiple mutable references to the same value. But inside map's implementation, since the only mutability you obtain with ValMut handles is references to values, what is the trouble copying them? And all the fuss with replace to make sure handles don't have to be duplicated.

Code is 39d212aa11e018e6edf7c33f7dbfed20429ac5fa and not a great leap forward, performance the same.

@bors
Copy link
Contributor

bors commented Aug 8, 2020

☔ The latest upstream changes (presumably #75071) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Aug 11, 2020

☔ The latest upstream changes (presumably #75329) made this pull request unmergeable. Please resolve the merge conflicts.

@ssomers ssomers force-pushed the btree_valmut branch 2 times, most recently from 553756c to f611130 Compare August 12, 2020 10:17
@ssomers
Copy link
Contributor Author

ssomers commented Aug 12, 2020

Now also moved range_search down into the rest of iterator support navigate.rs, ruling out its use on Mut handlers, and emphasizing the unsafe part. And putting map.rs on a diet.

@@ -512,6 +525,24 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
}
}

impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hands out a &'a mut [K] to the key slice despite being just ValMut, which seems wrong?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but this PR tries to only stick the ValMut label on (copies of) existing code and #73971 replaces this copy of into_slices_mut entirely. Though I did already remove the mut-ness of tbe keys in into_kv_valmut, which also gets replaced, so that's not consistent. And in the navigate methods and all the way up to the map functions, but these take on their final form.

I guess, looking at this in solation, it's not sound to call it ValMut and have mut keys. One could also argue that changing keys is not a problem, as long as you preserve order. Like we used to manually renumber lines in Basic programs, What really matters in this PR is the separation between structure altering handle types and methods versus K/V-altering tpyes and methods. So instead of ValMut, it could be KeyValMut, or ImmutLayout or so.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyways, fixed according to the ValMut philosophy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I see that now, but I think if we're going to call it ValMut and not something like TreeImmut (which sounds confusing, don't use it), we should go with this.

@Mark-Simulacrum
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Aug 14, 2020

📌 Commit 55bdf17e1bacbf681d98e0adcef89b41a1984fbb has been approved by Mark-Simulacrum

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 14, 2020
tmandry added a commit to tmandry/rust that referenced this pull request Aug 14, 2020
… r=Mark-Simulacrum

BTreeMap: purge innocent use of into_kv_mut

Replace the use of `into_kv_mut` into more precise calls. This makes more sense if you know that the single remaining use of `into_kv_mut` is in fact evil and can be trialled in court (rust-lang#75200) and sent to a correction facility (rust-lang#73971).

No real performance difference reported (but functions that might benefit a tiny constant bit like `BTreeMap::get_mut` aren't benchmarked):
```
benchcmp old new --threshold 5
 name                       old ns/iter  new ns/iter  diff ns/iter  diff %  speedup
 btree::map::clone_fat_100  63,073       59,256             -3,817  -6.05%   x 1.06
 btree::map::iter_100       3,514        3,235                -279  -7.94%   x 1.09
```
@bors
Copy link
Contributor

bors commented Aug 15, 2020

☔ The latest upstream changes (presumably #75538) made this pull request unmergeable. Please resolve the merge conflicts.

@bors bors 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-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Aug 15, 2020
@crlf0710
Copy link
Member

crlf0710 commented Sep 4, 2020

@Mark-Simulacrum seems this needs to be re r+'ed after the rebase

@crlf0710 crlf0710 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 4, 2020
@Mark-Simulacrum
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Sep 4, 2020

📌 Commit e5f9d7f has been approved by Mark-Simulacrum

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 4, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Sep 4, 2020
…crum

 BTreeMap: introduce marker::ValMut and reserve Mut for unique access

The mutable BTreeMap iterators (apart from `DrainFilter`) are double-ended, meaning they have to rely on a front and a back handle that each represent a reference into the tree. Reserve a type category `marker::ValMut` for them, so that we guarantee that they cannot reach operations on handles with borrow type `marker::Mut`and that these operations can assume unique access to the tree.

Including rust-lang#75195, benchmarks report no genuine change:
```
benchcmp old new --threshold 5
 name                                 old ns/iter  new ns/iter  diff ns/iter   diff %  speedup
 btree::map::iter_100                 3,333        3,023                -310   -9.30%   x 1.10
 btree::map::range_unbounded_vs_iter  36,624       31,569             -5,055  -13.80%   x 1.16
```

r? @Mark-Simulacrum
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Sep 4, 2020
…crum

 BTreeMap: introduce marker::ValMut and reserve Mut for unique access

The mutable BTreeMap iterators (apart from `DrainFilter`) are double-ended, meaning they have to rely on a front and a back handle that each represent a reference into the tree. Reserve a type category `marker::ValMut` for them, so that we guarantee that they cannot reach operations on handles with borrow type `marker::Mut`and that these operations can assume unique access to the tree.

Including rust-lang#75195, benchmarks report no genuine change:
```
benchcmp old new --threshold 5
 name                                 old ns/iter  new ns/iter  diff ns/iter   diff %  speedup
 btree::map::iter_100                 3,333        3,023                -310   -9.30%   x 1.10
 btree::map::range_unbounded_vs_iter  36,624       31,569             -5,055  -13.80%   x 1.16
```

r? @Mark-Simulacrum
@bors
Copy link
Contributor

bors commented Sep 4, 2020

⌛ Testing commit e5f9d7f with merge 70c5f6e...

@bors
Copy link
Contributor

bors commented Sep 5, 2020

☀️ Test successful - checks-actions, checks-azure
Approved by: Mark-Simulacrum
Pushing 70c5f6e to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Sep 5, 2020
@bors bors merged commit 70c5f6e into rust-lang:master Sep 5, 2020
@rustbot rustbot added this to the 1.48.0 milestone Sep 5, 2020
@ssomers ssomers deleted the btree_valmut branch September 5, 2020 19:03
@ecstatic-morse
Copy link
Contributor

Final perf results are here. This is a small but steady increase to instruction counts. @ssomers, this seems like part of a larger effort to eliminate UB in BTreeMap. Is this regression worth it in your opinion?

@ssomers
Copy link
Contributor Author

ssomers commented Sep 8, 2020

I doubt this PR alone, which is indeed a ramp up to others, has any discernable effect on performance, but I'm beyond caring.

bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 14, 2021
…lacrum

BTree: remove outdated traces of coercions

The introduction of `marker::ValMut` (rust-lang#75200) meant iterators no longer see mutable keys but their code still pretends it does. And settle on the majority style `Some(unsafe {…})` over `unsafe { Some(…) }`.

r? `@Mark-Simulacrum`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants