Manage pending better in try_evaluate_obligations - #160418
Conversation
For extreme new-solver cases like `nacl-0.5.3` and `ijson-0.1.6` the loop in `try_evaluate_obligations` can be very inefficient. This commit makes a very simple capacity tweak to the `pending` vec to fix that. There are some other possible changes to this function to improve performance further but they are more complicated so I'm doing this easy one first.
|
Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Manage `pending` better in `try_evaluate_obligations`
|
|
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (f3c3930): comparison URL. Overall result: no relevant changes - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countThis perf run didn't have relevant results for this metric. Max RSS (memory usage)Results (primary 3.7%, secondary -0.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -0.4%, secondary -0.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 491.898s -> 487.335s (-0.93%) |
|
The instruction count results look neutral, but if we look at cycles for new-solver benchmarks it's a bit different: there's some green there, with the biggest reductions on wg-grammar (as expected). I also measured locally, including the extreme nacl-0.5.3 and ijson-0.1.6 and nvml-wrapper-sys examples (which show the effects much more). Instruction counts:
And cycles:
I think there's a genuine effect here on the extreme cases. |
|
Oh, and it makes sense for the cycle count improvements to exceed instruction count improvements. When building up the |
|
Also, when I measured with Cachegrind, nacl-0.5.3 went from 54.6 billion instructions to 41.5 billion instructions. Cachegrind is different to perf in that it counts each iteration of a REP instruction separately, which explains why the reduction is so much larger. |
| let pending = mem::take(&mut self.obligations.pending); | ||
| self.obligations.pending.reserve(pending.capacity()); | ||
|
|
||
| for (mut obligation, stalled_on) in pending { |
There was a problem hiding this comment.
could we rewrite this as a retain instead? i think that's what waffle's PR #158126 does?
There was a problem hiding this comment.
actually no, @WaffleLapkin's PR only does this in the trait solver internal loop, which I think is significantly less hot?
There was a problem hiding this comment.
Something like that. That's the "other possible changes" I mentioned in the PR description.


For extreme new-solver cases like
nacl-0.5.3andijson-0.1.6the loop intry_evaluate_obligationscan be very inefficient. This commit makes a very simple capacity tweak to thependingvec to fix that.There are some other possible changes to this function to improve performance further but they are more complicated so I'm doing this easy one first.
r? @lcnr