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
Make create_def a side effect instead of marking the entire query as always red #115613
base: master
Are you sure you want to change the base?
Conversation
Another tricky case:
We wouldn't want to create 2 definitions where we only ask for one. |
Huh... why does that happen? Shouldn't we already be getting weird diagnostics in that case? |
This happens if we don't have the result of |
More precisely: the first call is |
The logic is the fallback case in |
Thanks. I really need to dig into |
I did some testing and a code dive, and I don't think that's what's happening.
|
|
yay, with this hint I was able to produce an example that actually exhibits an issue
oh wait... I even have this issue without doing any other changes to rustc. So it's not even ensure related yet |
☔ The latest upstream changes (presumably #115920) made this pull request unmergeable. Please resolve the merge conflicts. |
The difficulty is to know when to skip creating the DefId and reuse the one created by side-effect replay. What about adding a new variant |
Thanks! I was thinking about doing
but didn't know how. I'll investigate the |
6f8f71c
to
a7f29ee
Compare
☔ The latest upstream changes (presumably #120486) made this pull request unmergeable. Please resolve the merge conflicts. |
6d6b1eb
to
6831868
Compare
@cjgillot I implemented replaying, and that fixes the issues I was able to coax out of incremental tests, could you have a look? I'll keep working on it and adding more tests, but I think I could benefit from a review @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
cycles and wall time are unaffected, only instructions go up across the board. 🤔 maybe I need to move some logic into separate inline(never) functions |
example cachegrind diff
I guess it's just more expensive to track this info than to depend on the forever red node. Maybe we can avoid doing this work for queries like the resolver query, which is guaranteed to be rerun from scratch every time anyway? |
Ensure nested allocations in statics do not get deduplicated This PR generates new `DefId`s for nested allocations in static items and feeds all the right queries to make the compiler believe these are regular `static` items. I chose this design, because all other designs are fragile and make the compiler horribly complex for such a niche use case. At present this wrecks incremental compilation performance *in case nested allocations exist* (because any query creating a `DefId` will be recomputed and never loaded from the cache). This will be resolved later in rust-lang#115613 . All other statics are unaffected by this change and will not have performance implications (heh, famous last words) This PR contains various smaller refactorings that can be pulled out into separate PRs. It is best reviewed commit-by-commit. The last commit is where the actual magic happens. r? `@RalfJung` on the const interner and engine changes
Ensure nested allocations in statics do not get deduplicated This PR generates new `DefId`s for nested allocations in static items and feeds all the right queries to make the compiler believe these are regular `static` items. I chose this design, because all other designs are fragile and make the compiler horribly complex for such a niche use case. At present this wrecks incremental compilation performance *in case nested allocations exist* (because any query creating a `DefId` will be recomputed and never loaded from the cache). This will be resolved later in rust-lang#115613 . All other statics are unaffected by this change and will not have performance implications (heh, famous last words) This PR contains various smaller refactorings that can be pulled out into separate PRs. It is best reviewed commit-by-commit. The last commit is where the actual magic happens. r? `@RalfJung` on the const interner and engine changes fixes rust-lang#79738
Ensure nested allocations in statics do not get deduplicated This PR generates new `DefId`s for nested allocations in static items and feeds all the right queries to make the compiler believe these are regular `static` items. I chose this design, because all other designs are fragile and make the compiler horribly complex for such a niche use case. At present this wrecks incremental compilation performance *in case nested allocations exist* (because any query creating a `DefId` will be recomputed and never loaded from the cache). This will be resolved later in rust-lang#115613 . All other statics are unaffected by this change and will not have performance regressions (heh, famous last words) This PR contains various smaller refactorings that can be pulled out into separate PRs. It is best reviewed commit-by-commit. The last commit is where the actual magic happens. r? `@RalfJung` on the const interner and engine changes fixes rust-lang#79738
…lfJung,nnethercote Ensure nested allocations in statics neither get deduplicated nor duplicated This PR generates new `DefId`s for nested allocations in static items and feeds all the right queries to make the compiler believe these are regular `static` items. I chose this design, because all other designs are fragile and make the compiler horribly complex for such a niche use case. At present this wrecks incremental compilation performance *in case nested allocations exist* (because any query creating a `DefId` will be recomputed and never loaded from the cache). This will be resolved later in rust-lang#115613 . All other statics are unaffected by this change and will not have performance regressions (heh, famous last words) This PR contains various smaller refactorings that can be pulled out into separate PRs. It is best reviewed commit-by-commit. The last commit is where the actual magic happens. r? `@RalfJung` on the const interner and engine changes fixes rust-lang#79738
6831868
to
64ad441
Compare
Some changes occurred in src/tools/compiletest cc @jieyouxu |
64ad441
to
4b84717
Compare
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
Make create_def a side effect instead of marking the entire query as always red Before this PR: * query A creates def id D * query A is marked as depending on the always-red node, meaning it will always get re-run * in the next run of rustc: query A is not loaded from the incremental cache, but rerun After this PR: * query A creates def id D * query system registers this a side effect (just like we collect diagnostics to re-emit them without running a query) * in the next run of rustc: query A is loaded from the incremental cache and its side effect is run (thus re-creating def id D without running query A) r? `@cjgillot` TODO: * [ ] need to make feeding queries a side effect, too? At least ones that aren't written to disk? * [ ] need to re-feed the `def_span` query * [ ] many more tests
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (7ecf2bd): 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: 670.226s -> 673.047s (0.42%) |
Ok, that cut the perf regression in half on primary tests (though same number of regressions). I did some cachegrind runs, and it looks like all of the regression is now in writing the additional info to the incremental caches |
@rustbot ready I see no more avenues for improvements |
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.
Sorry for the very slow review...
Corner case that I'm not sure how is handled. Consider a query Q
(non eval-always) with this execution: we call tcx.ensure().Q()
, and then tcx.Q()
. Q
itself creates DefId
s.
IIUC, the replay will happen as so:
- ensure(Q) -> try_mark_green(Q) -> green -> replay side effects -> create some definitions.
- get(Q) -> graph in place -> replay -> Q.compute -> how do we skip re-creating the same definitions ?
@@ -1723,6 +1723,7 @@ rustc_queries! { | |||
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } | |||
separate_provide_extern | |||
feedable | |||
cache_on_disk_if { def_id.is_local() } |
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.
Should this be benchmarked and landed separately?
@@ -1150,9 +1151,31 @@ impl<'tcx> TyCtxt<'tcx> { | |||
|
|||
// This function modifies `self.definitions` using a side-effect. | |||
// We need to ensure that these side effects are re-run by the incr. comp. engine. |
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.
Drive-by: could you update the comment before the call to create_def
? Some parts are not accurate any more.
[created_def_ids.load(std::sync::atomic::Ordering::Relaxed)]; | ||
created_def_ids.fetch_add(1, std::sync::atomic::Ordering::Relaxed); |
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.
Should this use a single call to fetch_add
and use its result?
/// Side effects from the previous run made available to | ||
/// queries when they are reexecuted because their result was not | ||
/// available in the cache. The query removes entries from the | ||
/// side effect table. The table must be empty |
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 comment is not completely consistent with the code. The last sentence is unfinished, did you mean to change it?
assert_eq!(created_def_ids.into_inner(), prev_side_effects.definitions.len()); | ||
// We already checked at `DefId` creation time, that the created `DefId`s have the same parent and `DefPathData` | ||
// as the cached ones. |
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.
assert_eq!(created_def_ids.into_inner(), prev_side_effects.definitions.len()); | |
// We already checked at `DefId` creation time, that the created `DefId`s have the same parent and `DefPathData` | |
// as the cached ones. | |
// We want to verify that the `DefId`s created by the call to `query.compute` are consistent with | |
// those from the previous compilation. We already checked at `DefId` creation time, that the | |
// created `DefId`s have the same parent and `DefPathData` as the cached ones. | |
// We check here that we have not missed any. | |
assert_eq!(created_def_ids.into_inner(), prev_side_effects.definitions.len()); |
Before this PR:
After this PR:
r? @cjgillot
TODO:
def_span
query