Uh oh!
There was an error while loading. Please reload this page.
Make region inference use a dirty list - #47766
Conversation
nikomatsakis
left a comment
There was a problem hiding this comment.
Looks great. Left a small suggestion.
There was a problem hiding this comment.
Nit: I think the dirty list ought to be either refs to constraints or indices of constraints. Since you used indices for the dependency-map, let's go with those. (It'll also avoid any borrowing issues.)
So something like:
letmut dirty_list:Vec<_> = (0..self.containts.len()).collect();There was a problem hiding this comment.
whileletSome(constraint_index) = dirty_list.pop(){let constraint = &self.constraints[constraint_index];
...}There was a problem hiding this comment.
Now this can be
ifletSome(constraint_deps) = dependency_map.get(&constraint.sup){
dirty_list.extend(constraint_deps);}Not that it matters much, but generally invoking extend is better than for loop that calls push. This is because sometimes the iterator knows how long it will be, which lets dirty_list reallocate its backing array more efficiently.
Finally, you could simplify this further, like so:
dirty_list.extend(
dependency_map.get(&constraint.sup).unwrap_or(&vec![]));but I'm not sure that's really clearer (arguably less so). The key here is that creating an empty vector (i.e., vec![]) is basically free -- it's just some null values, no allocation or anything. In the case where I have a "map to vec", I often do this style, under the idea that a missing entry is equivalent to an empty vector. But either way really.
b1ed025 to
50280eaComparespastorino
commented
Jan 26, 2018
@nikomatsakis applied all the requested changes |
leonardo-m
commented
Jan 26, 2018
Have you run Clippy on your changes? |
nikomatsakis
commented
Jan 26, 2018
@leonardo-m why would we do that? is there some specific lint you are imagining? fwiw, we don't usually run clippy on the compiler. |
nikomatsakis
left a comment
There was a problem hiding this comment.
looking great! left 2 comments -- one is a nit, but also it's probably worth adding a bit vec to avoid duplicates as we discussed.
There was a problem hiding this comment.
this could be &self.constraints[constraint_idx] -- no reason to copy the value out
There was a problem hiding this comment.
as you said, it might be nice to have a bitvec storing what is already present in the dirty_list, which you would then have to clear each time we pop something out of the dirty list.
50280ea to
6b01707Comparespastorino
commented
Jan 26, 2018
@nikomatsakis ready! |
leonardo-m
commented
Jan 26, 2018
I didn't know that Clippy is not used on the compiler. Clippy gives lot of false positives, but some advice is good, so perhaps you should use Clippy...
I think Clippy often suggests to replace or_insert with or_insert_with |
nikomatsakis
commented
Jan 27, 2018
Ah. This case is better left as |
There was a problem hiding this comment.
you can change this to:
if dirty_bit_vec.insert(*dep_idx){
dirty_list.push(*dep_idx);}and save a bit of execution time.
There was a problem hiding this comment.
Nit: I'd usually write for &dep_idx in ... just so you don't need the *dep_idx below
There was a problem hiding this comment.
Maybe a comment here would be nice, actually. You could steal the stuff I wrote in the issue description (i.e., the example). But something like this would suffice:
Builds up a map from each region variable X to a vector with the indices of constraints that need to be re-evaluated when X changes. These are constraints like Y: X @ P -- so if X changed, we may need to grow Y.
6b01707 to
da545ceCompareI suspect the lines would be long for tidy.
nikomatsakis
left a comment
There was a problem hiding this comment.
Since I know you just stepped out, I might make these changes :)
| ); | ||
| let dependency_map = self.build_dependency_map(); | ||
| let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect(); | ||
| let mut dirty_bit_vec = BitVector::new(dirty_list.len()); |
There was a problem hiding this comment.
Nit: this starts as all zeroes, but we really want it to start as all ones I suppose. But it won't be wrong this way, just mildly less efficient. Actually, we could "invert the sense" of the vector, and have it store a 1 if the thing is not present....call it clean_bit_vec...
| debug!("propagate_constraints: --------------------"); | ||
| while let Some(constraint_idx) = dirty_list.pop() { | ||
| dirty_bit_vec.remove(constraint_idx); |
There was a problem hiding this comment.
...in that case, this would be clean_bit_vec.insert(constraint_idx);...
| debug!("propagate_constraints:sup={:?}", constraint.sup); | ||
| changed = true; | ||
| for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) { | ||
| if dirty_bit_vec.insert(dep_idx) { |
There was a problem hiding this comment.
...and this would be if clean_bit_vec.remove(dep_idx) {
Otherwise the vector is initially out of sync
nikomatsakis
commented
Jan 27, 2018
My measurements here locally using the testcase from #47267:
So this looks like a solid win for NLL to me! :) These are averages of 6 runs. The results were fairly stable but jumped around some. The test case is kind of small. So take them with a grain of salt. Here is a gist with my full measurements in case you are curious, each one is labeled with the SHA1 commit hash and whether it had NLL enabled or disabled. |
nikomatsakis
commented
Jan 27, 2018
@bors r+ |
bors
commented
Jan 27, 2018
📌 Commit 205eba8 has been approved by |
leonardo-m
commented
Jan 27, 2018
The next Nightly I'll test this with a much larger amount of code. |
nikomatsakis
commented
Jan 27, 2018
@leonardo-m if you have a test, I can run it now. |
bors
commented
Jan 27, 2018
⌛ Testing commit 205eba8 with merge 4349bc51453d0c74495589c8036622a9b1a05726... |
bors
commented
Jan 27, 2018
💔 Test failed - status-appveyor |
kennytm
commented
Jan 28, 2018
bors
commented
Jan 29, 2018
⌛ Testing commit 205eba8 with merge b7d4de9edf202b3a9cd889bf038ee663aecaf573... |
bors
commented
Jan 29, 2018
💔 Test failed - status-travis |
kennytm
commented
Jan 29, 2018
bors
commented
Jan 29, 2018
Make region inference use a dirty list r? @nikomatsakis
bors
commented
Jan 29, 2018
☀️ Test successful - status-appveyor, status-travis |
r? @nikomatsakis