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

limit and clear cache obligations opportunistically #44269

Merged

Conversation

nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented Sep 2, 2017

Keeping all the obligations for every projection is wasteful of
memory and compilation time. We only really care about those
subobligations that may inform the result of the projection (i.e., may
help to resolve any inference variables that appear within).
Therefore, we can clear the subobligations from the cache that don't
potentially affect the result of the projection. On every cache hit,
we also take the opportunity to check if the type variables have been
resolved yet and, if so, clear out the pending obligations.

Fixes #43613.

r? @arielb1

NB -- not sure how to test for this. Probably we should add the #43613 test case to perf.

Keep **all** the obligations for every projection is wasteful of
memory and compilation time. We only really care about those
subobligations that may inform the result of the projection (i.e., may
help to resolve any inference variables that appear within).
Therefore, we can clear the subobligations from the cache that don't
potentially affect the result of the projection. On every cache hit,
we also take the opportunity to check if the type variables have been
resolved *yet* and, if so, clear out the pending obligations.

Fixes rust-lang#43613
@arielb1 arielb1 added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Sep 3, 2017
@arielb1
Copy link
Contributor

arielb1 commented Sep 3, 2017

Sure. We probably want to add the test case to perf-collector.

I think my real worry here soundness-wise is that we could look up and "confirm" a <T as Trait>::Ty = X projection while T: Trait does not hold. I think the way we are supposed to handle this today is to make sure T: Trait is always checked "beforehand" (say, as a part of a WF-checking pass).

Maybe just add an additional T: Trait subobligation (either to obligations, or when returning in opt_normalize_projection_ty)? That should be "deduplicated" more easily - we already have plenty of caches for that, and it will probably prevent some odd edge case.

We need to have a better model of soundness + caching.

@nikomatsakis
Copy link
Contributor Author

@arielb1

I think the argument for why that cannot happen is that project doesn't, generally, succeed, unless either:

  • we know "directly" that T: Trait would be satisfied (or, at least, it generates sub-obligations that are sufficient to show that T: Trait would be satisfied, which must themselves be proven of course) -- e.g., clearly when it builds on select, that is the case.
  • there is some where-clause that tells us the projection result which must be validated elsewhere.

This makes a sort of inductive argument. Are there cases you're thinking of that don't fall into these two categories?

In any case, I'm not quite sure what you're proposing regarding this "extra" T: Trait obligation -- are you saying that we should just uniformly add such an obligation for every cache hit? (In addition to keeping the obligations that this PR keeps, i.e., those that may inform the result?)

@nikomatsakis
Copy link
Contributor Author

We need to have a better model of soundness + caching.

I don't disagree; I still think we can move towards a more chalk-like model, where the "trait system impl" doesn't handle things like "traits and projections" directly, but rather just interprets goals that it doesn't understand as deeply. We can then uniformly insert caching here that would replace and subsume the existing patchwork of caching. It'd be nice to prototype this more directly in chalk -- right now the impl is intentionally kept "naive", but I think it'd be good to have a less naive, caching variant to show how it could work.

@arielb1 arielb1 added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Sep 5, 2017
@nikomatsakis
Copy link
Contributor Author

@arielb1 does that last commit look like what you had in mind? I tested it -- it still preserves the memory/performance benefits on the test case in question, at least:

    MB
22.70^                                             #
     |            :@::::::::::::::::@:::::::::::@::#::@::::::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     |            :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | ::::::@:@:::@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
     | :::: :@:@: :@::::: ::: ::::::@: : :: ::::@: #::@:: :::::::::::@:::::@::
   0 +----------------------------------------------------------------------->Gi
     0                                                                   67.21

/// may or may not be necessary -- in principle, all the obligations
/// that must be proven to show that `T: Trait` were also returned
/// when the cache was first populated. But there is a vague concern
/// that perhaps someone would not have proven those, but also not
Copy link
Contributor

Choose a reason for hiding this comment

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

My concern wasn't about snapshot misuse, it was more about cache(/other "concurrent" operation) pollution.

@nikomatsakis
Copy link
Contributor Author

@bors r=arielb1

@bors
Copy link
Contributor

bors commented Sep 7, 2017

📌 Commit c1dddce has been approved by arielb1

@nikomatsakis nikomatsakis added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Sep 7, 2017
@nikomatsakis
Copy link
Contributor Author

@bors p=1

I'm marking this as high priority because it fixes a P-high performance regression and because I would like to backport it.

@bors
Copy link
Contributor

bors commented Sep 8, 2017

⌛ Testing commit c1dddce with merge dee6d0f...

bors added a commit that referenced this pull request Sep 8, 2017
…ns, r=arielb1

limit and clear cache obligations opportunistically

Keeping **all** the obligations for every projection is wasteful of
memory and compilation time. We only really care about those
subobligations that may inform the result of the projection (i.e., may
help to resolve any inference variables that appear within).
Therefore, we can clear the subobligations from the cache that don't
potentially affect the result of the projection. On every cache hit,
we also take the opportunity to check if the type variables have been
resolved *yet* and, if so, clear out the pending obligations.

Fixes #43613.

r? @arielb1

NB -- not sure how to test for this. Probably we should add the #43613 test case to perf.
@bors
Copy link
Contributor

bors commented Sep 9, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: arielb1
Pushing dee6d0f to master...

@bors bors merged commit c1dddce into rust-lang:master Sep 9, 2017
@nikomatsakis
Copy link
Contributor Author

Marking as beta-accepted. Fairly targeted patch, and fixes a major regression. It is my PR though so it wouldn't hurt to have people check it out.

cc @rust-lang/compiler

@nikomatsakis nikomatsakis added the beta-accepted Accepted for backporting to the compiler in the beta channel. label Sep 28, 2017
@nikomatsakis
Copy link
Contributor Author

Backporting now.

This was referenced Sep 28, 2017
@alexcrichton alexcrichton removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Sep 28, 2017
bors added a commit that referenced this pull request Sep 28, 2017
Beta 20170928

Backports of:

- Allow unused extern crate again #44825
- macros: fix bug in collecting trait and impl items with derives. #44757
-  `--cap-lints allow` switches off `can_emit_warnings` #44627
-  Update the libc submodule #44116
- limit and clear cache obligations opportunistically #44269
- clear out projection subobligations after they are processed #43999
arielb1 added a commit to arielb1/rust that referenced this pull request Oct 6, 2017
We want to retain obligations that *contain* inference variables, not
obligations that *don't contain* them, in order to fix rust-lang#43132. Because
of surrounding changes to inference, the ICE doesn't occur in its
original case, but I believe it could still be made to occur on master.

Maybe I should try to write a new test case? Certainly not right now
(I'm mainly trying to get us a beta that we can ship) but maybe before
we land this PR on nightly?

This seems to cause a 10% performance regression in my imprecise
attempt to benchmark item-body checking for rust-lang#43613, but it's better to
be slow and right than fast and wrong. If we want to recover that, I
think we can change the constrained-type-parameter code to actually
give a list of projections that are important for resolving inference
variables and filter everything else out.
nikomatsakis pushed a commit to nikomatsakis/rust that referenced this pull request Oct 6, 2017
We want to retain obligations that *contain* inference variables, not
obligations that *don't contain* them, in order to fix rust-lang#43132. Because
of surrounding changes to inference, the ICE doesn't occur in its
original case, but I believe it could still be made to occur on master.

Maybe I should try to write a new test case? Certainly not right now
(I'm mainly trying to get us a beta that we can ship) but maybe before
we land this PR on nightly?

This seems to cause a 10% performance regression in my imprecise
attempt to benchmark item-body checking for rust-lang#43613, but it's better to
be slow and right than fast and wrong. If we want to recover that, I
think we can change the constrained-type-parameter code to actually
give a list of projections that are important for resolving inference
variables and filter everything else out.
bors added a commit that referenced this pull request Oct 6, 2017
fix logic error in #44269's `prune_cache_value_obligations`

We want to retain obligations that *contain* inference variables, not
obligations that *don't contain* them, in order to fix #43132. Because
of surrounding changes to inference, the ICE doesn't occur in its
original case, but I believe it could still be made to occur on master.

Maybe I should try to write a new test case? Certainly not right now
(I'm mainly trying to get us a beta that we can ship) but maybe before
we land this PR on nightly?

This seems to cause a 10% performance regression in my imprecise
attempt to benchmark item-body checking for #43613, but it's better to
be slow and right than fast and wrong. If we want to recover that, I
think we can change the constrained-type-parameter code to actually
give a list of projections that are important for resolving inference
variables and filter everything else out.
bors added a commit that referenced this pull request Oct 7, 2017
Beta 20170928

Backports of:

- Allow unused extern crate again #44825
- macros: fix bug in collecting trait and impl items with derives. #44757
-  `--cap-lints allow` switches off `can_emit_warnings` #44627
-  Update the libc submodule #44116
- limit and clear cache obligations opportunistically #44269
- clear out projection subobligations after they are processed #43999
-  fix logic error in #44269's `prune_cache_value_obligations` #45065
- REVERTS #43543: Cleanup some remains of `hr_lifetime_in_assoc_type` compatibility lint:
bors pushed a commit to rust-lang-ci/rust that referenced this pull request May 21, 2021
This effectively reverts rust-lang#43546 as it seems that it does affect performance more than the PR has anticipated. Follow-up changes from rust-lang#44269 are also reverted.

This also removes the deduplication code from rust-lang#48296 as duplications were primarily coming from rust-lang#43546 and after removing that code it probably doesn't worth paying the cost of using a hash map.
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. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. 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.

rustc runs out of memory when compiling trait heavy code
4 participants