-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Exhaustiveness: Improve complexity on some wide matches #118796
Conversation
This comment has been minimized.
This comment has been minimized.
41a1bf0
to
13a8e36
Compare
On #118437, this goes from "takes so long that the playground timeouts" to "compiles instantly". Compared to before the one-pass rewrite, my guess is that it's comparable in performance. Our benchmarks don't have a lot of variety on matches so it's hard to measure. The rewrite was more for code health than for performance honestly, the difference would only be noticeable for somewhat complex matches. Our benchmarks barely noticed. |
Let's see how this fares: @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
…, r=<try> Exhaustiveness: Improve performance on wide matches rust-lang#118437 revealed an exponential case in exhaustiveness checking. While [exponential cases are unavoidable](https://compilercrim.es/rust-np/), this one only showed up after my rust-lang#117611 rewrite of the algorithm. I remember anticipating a case like this and dismissing it as unrealistic, but here we are :'). The tricky match is as follows: ```rust match command { BaseCommand { field01: true, .. } => {} BaseCommand { field02: true, .. } => {} BaseCommand { field03: true, .. } => {} BaseCommand { field04: true, .. } => {} BaseCommand { field05: true, .. } => {} BaseCommand { field06: true, .. } => {} BaseCommand { field07: true, .. } => {} BaseCommand { field08: true, .. } => {} BaseCommand { field09: true, .. } => {} BaseCommand { field10: true, .. } => {} // ...20 more of the same _ => {} } ``` To fix this, this PR formalizes a concept of "relevancy" (naming is hard) that was already used to decide what patterns to report. Now we track it for every row, which in wide matches like the above can drastically cut on the number of cases we explore. After this fix, the above match is checked with linear-many cases instead of exponentially-many. Fixes rust-lang#118437 r? `@cjgillot`
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (4abe247): comparison URL. Overall result: ❌ regressions - ACTION NEEDEDBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @bors rollup=never Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 669.935s -> 669.415s (-0.08%) |
Indeed! You can try it here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1f9de10106c7eec6d18773c9804e614f . On stable is the pre-#117611 behavior; on nightly is the current exponential behavior. Between pre-#117611 and post-this-PR, the tradeoff is roughly: pre-#117611 can check some cases several times, which post-this-PR never does; conversely, there are cases that post-this-PR considers distinct but pre-#117611 does in one go. |
This comment was marked as off-topic.
This comment was marked as off-topic.
13a8e36
to
9298104
Compare
I'm going to pre-emptively nominate this for beta backport in case the review and merge make it to Dec, 21st. Ref. Zulip thread where T-infra announces that the beta cut will happen a bit earlier in this release cycle @rustbot label +beta-nominated |
//! exhaustiveness. This allows us to skip cases. | ||
//! | ||
//! When specializing, if there is a `Missing` case we call the other constructors "irrelevant". | ||
//! When there is no `Missing` case there are no irrelevant constructors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the example, the constructor North
is irrelevant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was poorly phrased, relevancy really depends on the rows. I reworked the explanation entirely
This comment was marked as outdated.
This comment was marked as outdated.
e62ff58
to
600f3ff
Compare
Thanks! |
☀️ Test successful - checks-actions |
1 similar comment
☀️ Test successful - checks-actions |
Finished benchmarking commit (1a086e4): comparison URL. Overall result: ❌ regressions - ACTION NEEDEDNext Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 671.86s -> 670.392s (-0.22%) |
This needs to be backported onto 1.76.0, i.e. the beta that just branched off (or is about to be). So there's no rush, I'll wait for the current stable/beta releases to finish being released so we don't get confused about where to backport it |
@Nadrieril thank you 🙂 I see the PR has been merged with some minuses in the perf. report. Do these results need a comment? Will they be triaged during the usual weekly perf. triage? |
Perf feels ok to me; it's a stress-test and I'm not surprised it was affected by this change |
Awesome, then I'll mark this as perf. triaged (I think this is the correct process, in case it's not please anyone feel free to jump in and correct me 🙂 ) @rustbot label -perf-regression +perf-regression-triaged |
@apiraino I think that normally we just apply the |
I seem to understand that someone will swoop in and backport this along with a bunch of other PRs at some point? Ping me if this doesn't backport cleanly. |
…mulacrum [beta] backport rollup This PR backports: - rust-lang#119544: Fix: Properly set vendor in i686-win7-windows-msvc target - rust-lang#118796: Exhaustiveness: Improve complexity on some wide matches - rust-lang#119546: Temporarily disable M1 runners on GitHub Actions - rust-lang#119584: [beta] Clippy (early) beta backport - rust-lang#119559: [beta-1.76] Update cargo And also: - Bumps stage0 to released stable. r? `@Mark-Simulacrum`
…mulacrum [beta] backport rollup This PR backports: - rust-lang#119544: Fix: Properly set vendor in i686-win7-windows-msvc target - rust-lang#118796: Exhaustiveness: Improve complexity on some wide matches - rust-lang#119546: Temporarily disable M1 runners on GitHub Actions - rust-lang#119584: [beta] Clippy (early) beta backport - rust-lang#119559: [beta-1.76] Update cargo And also: - Bumps stage0 to released stable. r? `@Mark-Simulacrum`
#118437 revealed an exponential case in exhaustiveness checking. While exponential cases are unavoidable, this one only showed up after my #117611 rewrite of the algorithm. I remember anticipating a case like this and dismissing it as unrealistic, but here we are :').
The tricky match is as follows:
To fix this, this PR formalizes a concept of "relevancy" (naming is hard) that was already used to decide what patterns to report. Now we track it for every row, which in wide matches like the above can drastically cut on the number of cases we explore. After this fix, the above match is checked with linear-many cases instead of exponentially-many.
Fixes #118437
r? @cjgillot