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

Issue 72408 nested closures exponential #72412

Merged

Conversation

VFLashM
Copy link
Contributor

@VFLashM VFLashM commented May 21, 2020

This fixes #72408.

Nested closures were resulting in exponential compilation time.

This PR is enhancing asymptotic complexity, but also increasing the constant, so I would love to see perf run results.

@rust-highfive
Copy link
Collaborator

r? @petrochenkov

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 21, 2020
@petrochenkov
Copy link
Contributor

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@petrochenkov petrochenkov added S-waiting-on-perf Status: Waiting on a perf run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 21, 2020
@bors
Copy link
Contributor

bors commented May 21, 2020

⌛ Trying commit b4285d523ea1fed9690327511b92de1af2505dab with merge 8b8aaee9a06074230619a80778720382df633985...

@bors
Copy link
Contributor

bors commented May 21, 2020

☀️ Try build successful - checks-azure
Build commit: 8b8aaee9a06074230619a80778720382df633985 (8b8aaee9a06074230619a80778720382df633985)

@rust-timer
Copy link
Collaborator

Queued 8b8aaee9a06074230619a80778720382df633985 with parent 82911b3, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking try commit 8b8aaee9a06074230619a80778720382df633985, comparison URL.

@petrochenkov
Copy link
Contributor

Pretty noticeable regression.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels May 21, 2020
@VFLashM
Copy link
Contributor Author

VFLashM commented May 21, 2020

Oh well, simple hashset didn't make it. I'll see what else I can do.

@jyn514
Copy link
Member

jyn514 commented May 22, 2020

You could try using a BTreeSet which has much lower constant factor and reasonable (log n) asymptomatic complexity.

@VFLashM
Copy link
Contributor Author

VFLashM commented May 22, 2020

Thanks for the hint, I'll check it out.

@VFLashM
Copy link
Contributor Author

VFLashM commented May 22, 2020

Some set benchmarks:

set_bench

Here MiniSet is a tiny custom small-storage-optimized set, using array for up to 64 elements and FxHashSet afterwards.

Edit: These graphs have current set size along x axis and cost of insert operation along y axis.

@VFLashM VFLashM force-pushed the issue-72408-nested-closures-exponential branch from b4285d5 to 59eaf07 Compare May 22, 2020 12:23
@VFLashM
Copy link
Contributor Author

VFLashM commented May 22, 2020

Let's have another perf run, shall we?

@VFLashM
Copy link
Contributor Author

VFLashM commented May 22, 2020

As for the benchmarks these graphs have current set size along x axis and cost of insert operation along y axis.

@rust-highfive
Copy link
Collaborator

The job mingw-check of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
##[section]Starting: Linux mingw-check
##[section]Starting: Initialize job
Agent name: 'Azure Pipelines 50'
Agent machine name: 'fv-az578'
Current agent version: '2.168.2'
##[group]Operating System
16.04.6
LTS
LTS
##[endgroup]
##[group]Virtual Environment
Environment: ubuntu-16.04
Version: 20200512.2
Included Software: https://github.com/actions/virtual-environments/blob/ubuntu16/20200512.2/images/linux/Ubuntu1604-README.md
##[endgroup]
Agent running as: 'vsts'
Prepare build directory.
Set build variables.
Download all required tasks.
Download all required tasks.
Downloading task: Bash (3.163.2)
Checking job knob settings.
   Knob: AgentToolsDirectory = /opt/hostedtoolcache Source: ${AGENT_TOOLSDIRECTORY} 
   Knob: AgentPerflog = /home/vsts/perflog Source: ${VSTS_AGENT_PERFLOG} 
Start tracking orphan processes.
##[section]Finishing: Initialize job
##[section]Starting: Configure Job Name
==============================================================================
---
========================== Starting Command Output ===========================
[command]/bin/bash --noprofile --norc /home/vsts/work/_temp/e1fe659e-a6c4-4020-9a3f-19f1a70dccc8.sh

##[section]Finishing: Disable git automatic line ending conversion
##[section]Starting: Checkout rust-lang/rust@refs/pull/72412/merge to s
Task         : Get sources
Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
Version      : 1.0.0
Author       : Microsoft
---
##[command]git remote add origin https://github.com/rust-lang/rust
##[command]git config gc.auto 0
##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
##[command]git config --get-all http.proxy
##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/72412/merge:refs/remotes/pull/72412/merge
---
 ---> 3adb0605cc65
Step 6/7 : ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ---> Using cache
 ---> 28dbc326cb7f
Step 7/7 : ENV SCRIPT python3 ../x.py test src/tools/expand-yaml-anchors &&            python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu &&            python3 ../x.py build --stage 0 src/tools/build-manifest &&            python3 ../x.py test --stage 0 src/tools/compiletest &&            python3 ../x.py test src/tools/tidy &&            python3 ../x.py doc --stage 0 src/libstd &&            /scripts/validate-toolstate.sh
 ---> 537a01811900
Successfully built 537a01811900
Successfully tagged rust-ci:latest
Built container sha256:537a018119009dc218456238dec90b5530050db1e2a1e166550c218003f6159d
---
    Checking rustc_feature v0.0.0 (/checkout/src/librustc_feature)
    Checking fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
    Checking rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
    Checking rustc_hir v0.0.0 (/checkout/src/librustc_hir)
    Checking rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
    Checking chalk-rust-ir v0.10.0
    Checking rustc_parse v0.0.0 (/checkout/src/librustc_parse)
    Checking rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
    Checking rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
configure: build.submodules     := False
configure: rust.channel         := nightly
configure: rust.dist-src        := False
configure: llvm.ccache          := sccache
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 
---
Hugepagesize:       2048 kB
DirectMap4k:      139200 kB
DirectMap2M:     5103616 kB
DirectMap1G:     4194304 kB
+ python3 ../x.py test src/tools/expand-yaml-anchors
Ensuring the YAML anchors in the GitHub Actions config were expanded
Ensuring the YAML anchors in the GitHub Actions config were expanded
Building stage0 tool expand-yaml-anchors (x86_64-unknown-linux-gnu)
   Compiling unicode-xid v0.2.0
   Compiling syn v1.0.11
   Compiling linked-hash-map v0.5.2
   Compiling lazy_static v1.4.0
   Compiling lazy_static v1.4.0
   Compiling yaml-rust v0.4.3
   Compiling quote v1.0.2
   Compiling thiserror-impl v1.0.5
   Compiling thiserror v1.0.5
   Compiling yaml-merge-keys v0.4.0
   Compiling expand-yaml-anchors v0.1.0 (/checkout/src/tools/expand-yaml-anchors)
Build completed successfully in 0:00:30
+ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu
    Finished dev [unoptimized] target(s) in 0.20s
Checking rustdoc artifacts (x86_64-unknown-linux-gnu -> i686-pc-windows-gnu)
---
    Checking rustc_feature v0.0.0 (/checkout/src/librustc_feature)
    Checking fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
    Checking rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
    Checking rustc_hir v0.0.0 (/checkout/src/librustc_hir)
    Checking rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
    Checking chalk-rust-ir v0.10.0
    Checking rustc_parse v0.0.0 (/checkout/src/librustc_parse)
    Checking rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
    Checking rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
skip untracked path cpu-usage.csv during rustfmt invocations
skip untracked path src/doc/book/ during rustfmt invocations
skip untracked path src/doc/rust-by-example/ during rustfmt invocations
skip untracked path src/llvm-project/ during rustfmt invocations
Diff in /checkout/src/librustc_middle/ty/outlives.rs at line 3:
 // RFC for reference.
 
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use crate::ty::walk::MiniSet;
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use smallvec::SmallVec;
 #[derive(Debug)]
 #[derive(Debug)]
Running `"/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/rustfmt" "--config-path" "/checkout" "--edition" "2018" "--unstable-features" "--skip-children" "--check" "/checkout/src/librustc_middle/ty/outlives.rs"` failed.
If you're running `tidy`, try again with `--bless`. Or, if you just want to format code, run `./x.py fmt` instead.
Build completed unsuccessfully in 0:00:42
== clock drift check ==
  local time: Fri May 22 12:45:37 UTC 2020
  network time: Fri, 22 May 2020 12:45:37 GMT
  network time: Fri, 22 May 2020 12:45:37 GMT
== end clock drift check ==

##[error]Bash exited with code '1'.
##[section]Finishing: Run build
##[section]Starting: Checkout rust-lang/rust@refs/pull/72412/merge to s
Task         : Get sources
Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
Version      : 1.0.0
Author       : Microsoft
Author       : Microsoft
Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
==============================================================================
Cleaning any cached credential from repository: rust-lang/rust (GitHub)
##[section]Finishing: Checkout rust-lang/rust@refs/pull/72412/merge to s
Cleaning up task key
Start cleaning up orphan processes.
Terminate orphan process: pid (3485) (python)
##[section]Finishing: Finalize Job

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @rust-lang/infra. (Feature Requests)

@petrochenkov
Copy link
Contributor

I suspect that any set will cause noticeable regressions if it's populated on every type walk, because many of the type walks are mostly empty otherwise.
@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented May 22, 2020

⌛ Trying commit 59eaf07 with merge 2cd0cee6ae0fd1184272092ef9b0fb318b249060...

@petrochenkov petrochenkov added S-waiting-on-perf Status: Waiting on a perf run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 22, 2020
@bors
Copy link
Contributor

bors commented May 22, 2020

☀️ Try build successful - checks-azure
Build commit: 2cd0cee6ae0fd1184272092ef9b0fb318b249060 (2cd0cee6ae0fd1184272092ef9b0fb318b249060)

@ecstatic-morse
Copy link
Contributor

ecstatic-morse commented Sep 21, 2020

Hi! This PR showed up in the weekly perf triage report. As expected, it resulted in a very large improvement in instruction counts on the newly added deeply-nested-closures benchmark, but caused slight regressions elsewhere, enough to show up in task clock measurements.

The slowdown is unfortunate, but it seems you did everything possible to mitigate it. Thanks!

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Sep 24, 2020
Move MiniSet to data_structures

remove the need for T to be copy from MiniSet as was done for MiniMap

MiniMap and MiniSet was added by rust-lang#72412

think that this can be used in rust-lang#68828
bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 24, 2020
Move MiniSet to data_structures

remove the need for T to be copy from MiniSet as was done for MiniMap

MiniMap and MiniSet was added by rust-lang#72412

think that this can be used in rust-lang#68828
@spastorino
Copy link
Member

discussed in T-compiler meeting, declined to backport.

@rustbot modify labels: -beta-nominated

@rustbot rustbot removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Sep 24, 2020
@kornelski
Copy link
Contributor

kornelski commented Oct 1, 2020

Is beta reverting the change that caused this problem in the first place? I would be very unhappy about this bug being left in both 1.46 and 1.47, since it has broken multiple projects for me.

@tmandry
Copy link
Member

tmandry commented Oct 3, 2020

@spastorino @pnkfelix @wesleywiser It's not true that the performance was always bad. There is code that worked fine up until the last stable release that now takes an unacceptably long time to compile. It was caused by another beta backport that happened just prior to a stable release, #75443.

@tmandry
Copy link
Member

tmandry commented Oct 3, 2020

The reason for the confusion is that these issues pre-existed the breakage. It is true that there was code with bad build performance that also required "opting in" by increasing the type length limit; this change fixed those preexisting issues as well.

Another fix for similar regressions is in #76928. It doesn't look like we've fixed all of them yet, see #75992.

@Mark-Simulacrum Mark-Simulacrum added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Oct 3, 2020
@Mark-Simulacrum
Copy link
Member

Taking a look at this PR, it looks like the fairly large diff is mostly due to: introduction of a small-size optimized Map structure and threading through references to it into various pieces of code. It seems like it should be fairly harmless to backport and we've not seen serious regressions in nightly (it landed 2 weeks ago) as a result, to my knowledge.

I am inclined to backport this to beta, personally. I am also inclined to backport #76928 which also looks like it mostly just adds some caching. @rust-lang/compiler -- given that this is indeed fixing regressions, even if the performance problem is pre-existing, is anyone opposed to a beta backport of this PR?

I will also be nominating #76928 shortly.

This was referenced Oct 3, 2020
bors added a commit to rust-lang-ci/rust that referenced this pull request Oct 3, 2020
…k-Simulacrum

[beta] backports

This backports a number of PRs to beta, not all of which have been approved (yet).

 * Switch to environment files to change the environment on GHA rust-lang#77418
 * cache types during normalization rust-lang#76928
 * Fixing memory exhaustion when formatting short code suggestion rust-lang#76598
 * Issue 72408 nested closures exponential rust-lang#72412

r? `@Mark-Simulacrum`
@Mark-Simulacrum Mark-Simulacrum modified the milestones: 1.48.0, 1.47.0 Oct 3, 2020
@Mark-Simulacrum Mark-Simulacrum added beta-accepted Accepted for backporting to the compiler in the beta channel. and removed beta-nominated Nominated for backporting to the compiler in the beta channel. labels Oct 8, 2020
@@ -1,4 +1,4 @@
error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Nil>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
Copy link

Choose a reason for hiding this comment

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

Apologies for the random drive-by comment, but aren't there too many >s? I was expecting this:

test::<Cons<Cons<Cons<Cons<Cons<...>>>>>>

Copy link
Contributor

Choose a reason for hiding this comment

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

Final truncation is based on number of characters (32 each side).

Copy link
Member

Choose a reason for hiding this comment

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

Maybe it should be smarter, though?

Copy link
Contributor

@kornelski kornelski Oct 8, 2020

Choose a reason for hiding this comment

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

It's tricky, because the part of the code that understands type's structure doesn't track its printed length. The part that truncates the text length doesn't understand the type.

bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 3, 2024
…=lcnr

Re-implement a type-size based limit

r? lcnr

This PR reintroduces the type length limit added in rust-lang#37789, which was accidentally made practically useless by the caching changes to `Ty::walk` in rust-lang#72412, which caused the `walk` function to no longer walk over identical elements.

Hitting this length limit is not fatal unless we are in codegen -- so it shouldn't affect passes like the mir inliner which creates potentially very large types (which we observed, for example, when the new trait solver compiles `itertools` in `--release` mode).

This also increases the type length limit from `1048576 == 2 ** 20` to `2 ** 24`, which covers all of the code that can be reached with craterbot-check. Individual crates can increase the length limit further if desired.

Perf regression is mild and I think we should accept it -- reinstating this limit is important for the new trait solver and to make sure we don't accidentally hit more type-size related regressions in the future.

Fixes rust-lang#125460
flip1995 pushed a commit to flip1995/rust that referenced this pull request Jul 11, 2024
…=lcnr

Re-implement a type-size based limit

r? lcnr

This PR reintroduces the type length limit added in rust-lang#37789, which was accidentally made practically useless by the caching changes to `Ty::walk` in rust-lang#72412, which caused the `walk` function to no longer walk over identical elements.

Hitting this length limit is not fatal unless we are in codegen -- so it shouldn't affect passes like the mir inliner which creates potentially very large types (which we observed, for example, when the new trait solver compiles `itertools` in `--release` mode).

This also increases the type length limit from `1048576 == 2 ** 20` to `2 ** 24`, which covers all of the code that can be reached with craterbot-check. Individual crates can increase the length limit further if desired.

Perf regression is mild and I think we should accept it -- reinstating this limit is important for the new trait solver and to make sure we don't accidentally hit more type-size related regressions in the future.

Fixes rust-lang#125460
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beta-accepted Accepted for backporting to the compiler in the beta channel. I-compiletime Issue: Problems and improvements with respect to compile times. 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. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Nested closures result in exponential compilation time increase