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

BTree: lighten the load on Miri #68781

Merged
merged 2 commits into from
Feb 17, 2020
Merged

Conversation

ssomers
Copy link
Contributor

@ssomers ssomers commented Feb 2, 2020

Reduce the amount of work Miri ploughs through in btree code, in particular on test_clone_from (which takes up 5 minutes on my machine).

r? @crgl

let size = 30;
#[cfg(miri)]
let size = 13;
Copy link
Member

Choose a reason for hiding this comment

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

I'm not really sure that testing 900 different variations of clone_from is buying us anything anyway, so maybe just go with 13 always?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree. 0, 1, 10, 11 and 12 are the only interesting sizes for size=30 (note that size itself isn't tested). Next stop would be 144 (3 levels, not all edges pointing to leaves).

Also, as an aside, by always adding greater elements on both sides, I think (am not quite sure) that some kinds of trees are ignored (as in right leaf bigger than left leaf or so). I am pretty sure that you can have an 11 element tree packed in a lonely root or spread over 2 levels, depending on whether you remove the 6th or 7th element from a 12 element tree. But it's hard to diagnose since tests can't tell the difference. So other test cases don't try to go there either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The same can be said about test_clone (possibly an inspiration for this or future tests): if we can clone a 12 element (2 level, 2 leaf) tree, surely we can handle every bigger 2 level tree... but can we handle bigger? Yes, we can, and Miri can handle it fine too. Just don't ask it to clone every size of tree in between.

@JohnTitor JohnTitor added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 3, 2020
@JohnTitor
Copy link
Member

r? @RalfJung

@@ -250,8 +250,7 @@ impl<K: Clone + Ord, V: Clone> BTreeClone for BTreeMap<K, V> {
// the BTree invariants are maintained at the end of the loop
while !siter.is_empty() {
if let Some((ok, ov)) = oiter.next() {
// SAFETY: This is safe because the `siter.front != siter.back` check
// ensures that `siter` is nonempty
// SAFETY: This is safe because `siter` is nonempty
Copy link
Member

Choose a reason for hiding this comment

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

Why is there a safety comment being changed in a PR that's labelled to be about tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's something I noticed that wasn't adapted in the history of the already merged change, related to most of the test tweaks. I can do that commit in a separate PR or forget about it.

Copy link
Member

Choose a reason for hiding this comment

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

I am not deeply familiar with the code, and unfortunately next_unchecked doesn't have a comment explaining its unsafe precondition. But the change makes sense to me, so we can keep it. Just please add a trailing . :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gladly, but to this one only or to all similar comments in the file?

Copy link
Member

Choose a reason for hiding this comment

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

Having a trailing . after a proper sentence is the recommended comment style in rustc (AFAIK...), but there's no need to increase the diff to port everything. Just, whatever you touch should follow the style.

OTOH if you want to add a few more trailing ., it's not like that's hard to review.^^

Copy link
Contributor Author

Choose a reason for hiding this comment

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

next_unchecked doesn't have a comment explaining its unsafe precondition

True. But when I work my way up from the recently documented underlying implementation, the precondition is unhelpful or convoluted. Calling Range::next_unchecked is safe if (besides another thing) whoever initialized the range instance, gave it "good" data. Or constructing a valid Range is an unsafe operation itself but I don't find information on marking constructors unsafe. So, short unhelpful comment coming in.

Copy link
Member

@RalfJung RalfJung Feb 16, 2020

Choose a reason for hiding this comment

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

Well I was trying to review the SAFETY comment and that is hard when the precondition is unclear. ;) But that is not your fault, and your PR doesn't make it worse, so I am still fine with the diff here.

Or constructing a valid Range is an unsafe operation itself but I don't find information on marking constructors unsafe.

There is no such thing; we make them private. A constructor can never by itself cause UB.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was adding comments on the next_unchecked touched here, because it seems a waste to keep the underlying documentation work hidden.

Range::next_unchecked is private too, but we still mark it unsafe (which I found surprising,). Okay, the constructor cannot cause UB itself, but there's an implicit "class invariant" on Range (and many others), i.e. front and back are leaf edges (that's in their type already), point into the same tree (duh...) and front is not right of back (obviously?). If we don't specify how the constructor should be used, can we silently assume that the class invariant is honoured in Range::next_unchecked?

Copy link
Member

Choose a reason for hiding this comment

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

Ideally, the invariant should be documented at the type, and everything acting on its fields directly should have SAFETY comments explaining why this preserves the invariant. For unsafe methods, well it's up to them whether they require the invariant to already hold or not.

But the code here isn't yet up to that kind of standard. Also if this becomes more documentation changes I would ask you to split the PR, because I don't feel comfortable to review those.

Copy link
Contributor Author

@ssomers ssomers Feb 16, 2020

Choose a reason for hiding this comment

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

Ideally, the invariant should be documented at the type

Where at the type? For a public type like Range, with private fields and safe public methods, the usual struct documentation seem a bad place to bother people with internal invariants. string/vec::from_raw_parts and vec::set_len also list invariants (actually, they are the only places in string and vec listing them), but these are unsafe methods. Finally I found in librustc/ty/free_region_map.rs a pub struct FreeRegionMap that features an invariant in the comments of a field.

@ssomers
Copy link
Contributor Author

ssomers commented Feb 16, 2020

So I mixed 3 themes here:

Which ones (if any) should I keep here?

@RalfJung
Copy link
Member

I'm fine keeping them all, I just asked for a few more comments explaining your choices.

@RalfJung
Copy link
Member

The PR LGTM now, except that it adds a few comments for which I cannot say if they are correct.

@RalfJung
Copy link
Member

All right, that also does it. Thanks for bearing with me!

@bors r+

@bors
Copy link
Contributor

bors commented Feb 16, 2020

📌 Commit da226dd has been approved by RalfJung

@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 Feb 16, 2020
@bors
Copy link
Contributor

bors commented Feb 17, 2020

⌛ Testing commit da226dd with merge 3c4590f...

bors added a commit that referenced this pull request Feb 17, 2020
BTree: lighten the load on Miri

Reduce the amount of work Miri ploughs through in btree code, in particular on `test_clone_from` (which takes up 5 minutes on my machine).

r? @crgl
@bors
Copy link
Contributor

bors commented Feb 17, 2020

☀️ Test successful - checks-azure
Approved by: RalfJung
Pushing 3c4590f to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Feb 17, 2020
@bors bors merged commit da226dd into rust-lang:master Feb 17, 2020
@ssomers ssomers deleted the btree_miri_relief branch February 17, 2020 08:46
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.

5 participants