-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
cache param env canonicalization #117749
cache param env canonicalization #117749
Conversation
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
[perf] canonicalize param env only once Canonicalize ParamEnv only once and store it. Then whenever we try to canonicalize `ParamEnvAnd<'tcx, T>` we only have to canonicalize `T` and then merge the results. Prelimiary results show ~3-4% savings in diesel and serde benchmarks. r? `@ghost`
☀️ Try build successful - checks-actions |
1 similar comment
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (557c12e): comparison URL. Overall result: ✅ improvements - no 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. @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: 661.067s -> 661.537s (0.07%) |
b93a98e
to
bcbfbe6
Compare
another approach with a global cache |
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
[perf] canonicalize param env only once Canonicalize ParamEnv only once and store it. Then whenever we try to canonicalize `ParamEnvAnd<'tcx, T>` we only have to canonicalize `T` and then merge the results. Prelimiary results show ~3-4% savings in diesel and serde benchmarks. r? `@ghost`
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
This comment has been minimized.
This comment has been minimized.
MCVE: struct VarZeroVec<'a, F>(&'a (), F);
trait Yokeable<'a> {
type Output;
}
impl<'a> Yokeable<'a> for () {
type Output = VarZeroVec<'a, ()>;
}
fn transform_mut<'a, F>(f: F)
where
F: FnOnce(VarZeroVec<'a, ()>),
{
f(absurd::<<() as Yokeable<'a>>::Output>())
}
fn absurd<T>() -> T{ todo!() } |
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
[perf] canonicalize param env only once Canonicalize ParamEnv only once and store it. Then whenever we try to canonicalize `ParamEnvAnd<'tcx, T>` we only have to canonicalize `T` and then merge the results. Prelimiary results show ~3-4% savings in diesel and serde benchmarks. r? `@ghost`
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
r? @lcnr will look at this soon (hopefully) |
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.
some nits, then r=me, afaict CI was an unrelated issue
param_env, | ||
self, | ||
self.tcx, | ||
&CanonicalizeFreeRegionsOtherThanStatic, |
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.
This does not spark joy 😁 Does anything break if you change this to CanonicalizeFreeRegions
? I want to get away from canonicalizing static completely. iirc the last time I tried after #102472 there was still some failure in project or sth 🤔 would prefer for you (or me) to first try to also canonicalize 'static
again to check why it matters.
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.
Borrowck error in tests/ui/trivial-bounds/trivial-bounds-object.rs
ICE in tests/ui/nll/issue-61311-normalize.rs
and tests/ui/nll/issue-61320-normalize.rs
. MCVE:
pub trait HasProj {
type Proj;
}
impl<T: ?Sized> HasProj for T {
type Proj = ();
}
fn test()
where
dyn Send + 'static: HasProj,
<dyn Send + 'static as HasProj>::Proj: Clone,
{
// ICE: cannot prove `<dyn Send + 'static as HasProj>::Proj: Clone`
let _ = test;
}
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.
cc #118965. It is also the root cause behind the ICE.
ParamEnv is canonicalized in *queries input* rather than query response. In such case we don't "preserve universes" of canonical variable. This means that `universe_map` always has the default value, which is wasteful to store in the cache.
fixes a soundness regression described in the PR description.
This doesn't change behavior. It should prevent unintentional resolution of inference variables during canonicalization, which previously caused a soundness bug. See PR description for more.
ParamEnv's with inference variabels are invalid.
aace4f7
to
aa36c35
Compare
I turns out it is related. Rustdoc incorrectly uses ParamEnv's with inference variables in them. This causes an ICE during canonicalization in one of the @bors r=lcnr rollup=never |
☀️ Test successful - checks-actions |
Finished benchmarking commit (d23e1a6): comparison URL. Overall result: ✅ improvements - no action needed@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.
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: 673.665s -> 670.811s (-0.42%) |
cache param env canonicalization Canonicalize ParamEnv only once and store it. Then whenever we try to canonicalize `ParamEnvAnd<'tcx, T>` we only have to canonicalize `T` and then merge the results. Prelimiary results show ~3-4% savings in diesel and serde benchmarks. Best to review commits individually. Some commits have a short description. Initial implementation had a soundness bug (rust-lang/rust#117749 (comment)) due to cache invalidation: - When canonicalizing `Ty<'?0>` we first try to resolve region variables in the current InferCtxt which may have a constraint `?0 == 'static`. This means that we register `Ty<'?0> => Canonical<Ty<'static>>` in the cache, which is obviously incorrect in another inference context. - This is fixed by not doing region resolution when canonicalizing the query *input* (vs. response), which is the only place where ParamEnv is used, and then in a later commit we *statically* guard against any form of inference variable resolution of the cached canonical ParamEnv's. r? `@ghost`
cache param env canonicalization Canonicalize ParamEnv only once and store it. Then whenever we try to canonicalize `ParamEnvAnd<'tcx, T>` we only have to canonicalize `T` and then merge the results. Prelimiary results show ~3-4% savings in diesel and serde benchmarks. Best to review commits individually. Some commits have a short description. Initial implementation had a soundness bug (rust-lang/rust#117749 (comment)) due to cache invalidation: - When canonicalizing `Ty<'?0>` we first try to resolve region variables in the current InferCtxt which may have a constraint `?0 == 'static`. This means that we register `Ty<'?0> => Canonical<Ty<'static>>` in the cache, which is obviously incorrect in another inference context. - This is fixed by not doing region resolution when canonicalizing the query *input* (vs. response), which is the only place where ParamEnv is used, and then in a later commit we *statically* guard against any form of inference variable resolution of the cached canonical ParamEnv's. r? `@ghost`
cache param env canonicalization Canonicalize ParamEnv only once and store it. Then whenever we try to canonicalize `ParamEnvAnd<'tcx, T>` we only have to canonicalize `T` and then merge the results. Prelimiary results show ~3-4% savings in diesel and serde benchmarks. Best to review commits individually. Some commits have a short description. Initial implementation had a soundness bug (rust-lang/rust#117749 (comment)) due to cache invalidation: - When canonicalizing `Ty<'?0>` we first try to resolve region variables in the current InferCtxt which may have a constraint `?0 == 'static`. This means that we register `Ty<'?0> => Canonical<Ty<'static>>` in the cache, which is obviously incorrect in another inference context. - This is fixed by not doing region resolution when canonicalizing the query *input* (vs. response), which is the only place where ParamEnv is used, and then in a later commit we *statically* guard against any form of inference variable resolution of the cached canonical ParamEnv's. r? `@ghost`
Canonicalize ParamEnv only once and store it. Then whenever we try to canonicalize
ParamEnvAnd<'tcx, T>
we only have to canonicalizeT
and then merge the results.Prelimiary results show ~3-4% savings in diesel and serde benchmarks.
Best to review commits individually. Some commits have a short description.
Initial implementation had a soundness bug (#117749 (comment)) due to cache invalidation:
Ty<'?0>
we first try to resolve region variables in the current InferCtxt which may have a constraint?0 == 'static
. This means that we registerTy<'?0> => Canonical<Ty<'static>>
in the cache, which is obviously incorrect in another inference context.r? @ghost