-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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: move up reference to map's root from NodeRef #74437
Conversation
This slightly improves performance, presumably because immutable/owned access (and soon mutable iteration) no longer carries around a useless null pointer:
Note that the increase in |
8bd3676
to
ae19245
Compare
@bors r+ |
📌 Commit ae19245db324e8b46cbc1c0e9b5e778ad6121e51 has been approved by |
🌲 The tree is currently closed for pull requests below priority 5, this pull request will be tested once the tree is reopened |
ae19245
to
8dab618
Compare
Oh well if you think it's good enough, let me squash those two commits. But I'll be interrogating Miri for this. |
CAD97 estimates that the code still has UB and that my uglifying tweak just happens to sneak past Miri. Though I believe that the same UB exists and has existed for years in master. |
bcbbf46
to
90396a3
Compare
This is what I came up with. Miri happy, me happy. |
90396a3
to
c2c5f8a
Compare
It's even better when CI is happy too! |
Continuing from the users.rust-lang.org discussion, I suspect that In master, In this PR, this dereferencing to the root happens every iteration, regardless of whether a level needs to be popped. It's no surprise that Miri still keeps quiet about reading through the root, if it didn't complain about writing to the root. The only correct solution I see is to pop the level at the end of drain_filtering, so in the drop handler. We're navigating through handles, so we mostly don't care that the tree doesn't conform to its invariant yet. But it's still a little awkward. |
Also, the same discussion made me realize that the old system has one trick up its sleeve: by embedding root_ptr in the handle, and only letting it out by a consuming conversion (
I tried to restore most of that consume-handles-before-you-dereference-root_ptr safety with a wrapper around the NonNull's, but it's not bullet proof: if you don't consume the handle, the borrow checker will let you use it after dereferencing the root_ptr. But at least you can only deference root_ptr once, and you realize that it was wrong for drain_filter to do it every iteration. Not squishing because I suspect it's not yet all clean as a whistle. |
And lastly, I thought it was wise to keep the length reference next to the (faked) root reference, because the length reference is real and fully borrow-checked. Now I think this is useless: making sure the length is borrowed correctly does not prove anything about the root reference, and whenever the length needs updating, the root may need updating too. While it is (in theory) possible to update the root without even looking at length. So I joined them into a single pointer to the map. |
6317d8d
to
006983d
Compare
Squished everything except some that deserve their own PR |
Put back to draft because #74827 is a better version of the |
Perhaps mark this as not a draft? What happens if bors tries to merge/close this? EDIT: lol, I should have read the previous comment... Somebody should bors r- to take it out of the PR queue. |
Uh, I did not notice it's still S-waiting-on-bors. But surely bors would only merge the approved commit from long ago, not all the stuff I piled up since? Anyway, I'll merge the same change in already, just in case. |
006983d
to
3102c2e
Compare
Yeah I can take a look at this |
@Dylan-DPC No progress is to be expected, I have abandoned research on how to get rid of the S-waiting-on-author label. @RalfJung It would indeed have been great to know if anyone cares and what it would take to complete this. Apparently it's not the currently first commit, a separation of concerns and a slight performance gain. I've already written about the further commits, the horribly complicated leak amplification. One way to complete that is much more post-processing in DrainFilter's drop handler, but that seems more like procrastination than completion. |
@ssomers you seem frustrated by the review process here, for which I am sorry. I cannot speak for @Mark-Simulacrum, but for my part I found it hard to understand what your concrete goal was with this PR: when we were just done finalizing the "dormant ref" API, you pushed a lot more changes here that go well beyond the original scope of the PR (the PR title and description do not say anything about leak amplification... or maybe I still misunderstood how this PR relates to leak amplification). That's okay, this happens, but as a reviewer I see this as a signal that you are still working on it. (Though also, from a review perspective, small independent changes are much preferred over big PRs.) So I was basically waiting for you to say "okay this is good now from my side, I will stop adding more changes to this, please review". The label just reflects this; it usually gets changed when the author posts a comment like that. I am sorry if we did not communicate that properly. |
Well, "just" is a week, in my head multiplied by older PRs that didn't move either. That is most likely fine for reasonable contributors, but frustrating to me at the moment. The leak amplification theme came in because Mark spotted the problem with the drop handler I introduced. The 577a229 commit was a quick fix getting rid of the new part of the drop handler and sticking to the title, the later commits fixed the drop handler for good (probably). Since the later commits aren't reviewed at all, are complicated, and I don't think will be further exploited in the near future, I've put back the 577a229 commit. |
72c4750
to
577a229
Compare
577a229
to
2b54ab8
Compare
I think this is ready to go. I did want to check -- we resolved the leak amplification in a separate PR, right? I recall flagging an issue with it, but I think it was either not this PR or already resolved. It's a subtle issue so I worry my review may have missed it, as I did previously. |
Sorry about this, we are working on improving the Contributor Xperience in the rust community so this serves as good feedback for us and we can work on making this better. A few things to note: |
Ah, I wasn't aware some people are suggesting to use the bot for this. It's not the workflow I know but maybe I am old-school already. ;) FWIW, since you also expressed trouble interacting with the bot, here's the exact invocation you can use to do the label change:
The bot can be a bit picky about syntax and there's no auto-complete, so getting the command right is tricky... I copied it from the messages bors sends in case of a conflict, which recently were expanded to add that command. |
It's not what I understand is meant with "leak amplification", but in the end #75257 fixed the state corruption when using mem::forget on #74762, which is a split-off part of an initial version of this PR. Since then, and in the final version of this PR, the drop handler does nothing more than before, so there cannot be corruption and there is no leak at all. That said, as Ralf reminded us, the drop handler does exist. It needs to exist to make |
Except that this state corruption was lightweight, and occurred even without involving mem::forget, because I messed up the implementation of the drop handler and it never did any post-processing. |
@bors r+ |
📌 Commit 2b54ab8 has been approved by |
I've been avoiding these changes in rollups in case there's a perf impact, is there a reason not to worry about that or should they be rollup=never? |
@bors rollup=never We probably should. They're refactoring that's good even if it is (plausibly) a small perf hit -- benchmarking just BTree usually results in noise, and most of what we've seen so far I think has been just effects of different inlining and such, not much we can do about it. |
☀️ Test successful - checks-actions, checks-azure |
Since the introduction of
NodeRef
years ago, it also contained a mutable reference to the owner of the root node of the tree (somewhat disguised as *const). Its intent is to be used only when the rest of theNodeRef
is no longer needed. Moving this to where it's actually used, thought me 2 things:from_sorted_iter
(transplanted to BTreeMap: better distinguish the root holder from the root node #75329)reborrow_mut
, the other one being addressed in BTreeMap mutable iterators should not take any reference to visited nodes during iteration #73971.This does repeat the raw pointer code in a few places, but it could be bundled up with the length reference.
r? @Mark-Simulacrum