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

fix non_blanket_impls iteration order #89016

Merged
merged 3 commits into from
Sep 23, 2021
Merged

Conversation

lcnr
Copy link
Contributor

@lcnr lcnr commented Sep 16, 2021

We sometimes iterate over all non_blanket_impls, not sure if this is observable outside
of error messages (i.e. as incremental bugs). This should fix the underlying issue of #86986.

second attempt of #88718

r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 16, 2021
@lcnr
Copy link
Contributor Author

lcnr commented Sep 16, 2021

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Sep 16, 2021
@bors
Copy link
Contributor

bors commented Sep 16, 2021

⌛ Trying commit 92bbb2f7811fe8c9b6148b38597960a601f768ee with merge 91bb5f03171b819eba4a4463ce46e49de79a7e3b...

@bors
Copy link
Contributor

bors commented Sep 16, 2021

☀️ Try build successful - checks-actions
Build commit: 91bb5f03171b819eba4a4463ce46e49de79a7e3b (91bb5f03171b819eba4a4463ce46e49de79a7e3b)

1 similar comment
@bors
Copy link
Contributor

bors commented Sep 16, 2021

☀️ Try build successful - checks-actions
Build commit: 91bb5f03171b819eba4a4463ce46e49de79a7e3b (91bb5f03171b819eba4a4463ce46e49de79a7e3b)

@rust-timer
Copy link
Collaborator

Queued 91bb5f03171b819eba4a4463ce46e49de79a7e3b with parent 2b5ddf3, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (91bb5f03171b819eba4a4463ce46e49de79a7e3b): comparison url.

Summary: This change led to moderate relevant mixed results 🤷 in compiler performance.

  • Moderate improvement in instruction counts (up to -1.8% on full builds of inflate)
  • Moderate regression in instruction counts (up to 1.8% on full builds of externs)

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Benchmarking 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 led to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: +S-waiting-on-review -S-waiting-on-perf +perf-regression

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Sep 16, 2021
pub struct TraitImpls {
blanket_impls: Vec<DefId>,
/// Impls indexed by their simplified self type, for fast lookup.
non_blanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
non_blanket_impls: FxIndexMap<fast_reject::SimplifiedType, Vec<DefId>>,
Copy link
Member

Choose a reason for hiding this comment

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

Hm, is this enough?

It looks like insertion into non_blanket_impls happens in a loop which is a result of tcx.crates(()) which isn't stable across compilation sessions I'd expect (though I could be wrong).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way crates(()) is computed, it looks like it is always (1..=num_crates).map(CrateNum) (0 is reserved for the current crate and does not have any data) and it I would assume the crates get added to the CStore in a deterministic order.

We do have stable_crate_id which orders crates independently of their cnum. I could be that CrateNums are not deterministically assigned to their actual crate data, though it seems quite buggy to me if this doesn't invalidate query caches in that case. e.g. trait_impls_of_provider just uses the order of crates(()) which influences the way winnowing works for example.

A bit out of my depth here, maybe @rust-lang/wg-incr-comp can help and clarify here 😅 ❤️

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, we probably do end up with an ordering that is mostly stable from run to run (presuming no shifts in code or other sources), and I think incremental will track the query fine. My guess is that we could avoid marking the trait query as red if the crate load order changes (e.g., because the first code using that crate is moved?) if this used a stable crate ID, but it may not be worth it. Ultimately this PR does seem like it makes things strictly better here :)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that crate ordering is indeed deterministic, since it isn't something that we discover dynamically? But indeed I bet @michaelwoerister or @petrochenkov would be certain.

Copy link
Contributor

Choose a reason for hiding this comment

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

Crate are assigned their CrateNum in the order in which they are required by the resolver. As the resolver is not incremental, this order is deterministic but not stable. On the other hand, it is not obvious at all.
Incremental computes a hash for crates(()) based on their order in the vector and their stable_crate_id. We could make it independent on the order of crates by having the crates query sort its result by increasing stable_crate_id.

Copy link
Member

Choose a reason for hiding this comment

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

I think that parts of the code might rely on tcx.crates(()) being sorted by CrateNum, for better or worse. I would not recommend trying to change that as part of this PR.

crates.sort();

for &cnum in crates.iter() {
for &cnum in tcx.crates(()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

are these changes just "cleanup" or is there some substantive change in the order in which things are done here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

just cleanup, the only change of behavior is the second commit here.

crates(()) already returns the cnums in order, so the code i deleted in the other commits should just be noops

@nikomatsakis
Copy link
Contributor

r=me, but I'm going to make this

r? @michaelwoerister

since the primary question seems to have to do with incremental.

.map(|cnum| {
if tcx.dep_kind(CrateNum::new(cnum)) == CrateDepKind::Explicit {
let mut ret = tcx.crates(()).iter()
.map(|&cnum| {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to skip the leading CrateNum(0)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤷 CrateNum(0) is the local crate so I don't think we need to do any linking for that.

I think that explicitly dealing with the local crate and only iterating over all external ones is probably better than specialcasing the first item of the crates iter. But that's a fairly uninformed opinion

Copy link
Member

Choose a reason for hiding this comment

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

I don't understand how that code works in the first place? last_crate is tcx.crates(()).len() and then it creates a CrateNum(last_crate)? That should not be a valid CrateNum, right?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, tcx.crates(()) only returns upstream CrateNums. That is far from obvious. I think the query should be renamed to upstream_crate_nums or something. The same goes for CStore::crates_untracked. Would you be up for doing that, @lcnr? (but maybe in a separate PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

extern_crates maybe? 🤔 though i prefer doing that in a separate PR, want to merge this as it is blocking some further work

Copy link
Member

Choose a reason for hiding this comment

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

I've personally always used the term "upstream" (e.g. see

query upstream_monomorphizations(_: ()) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
). "Extern" often refers to something non-Rust. Although extern crate foo suggests otherwise :).

Anyway, I'm fine with doing this in another PR. You can r=me on this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

upstream is also fine 😆 was thinking of extern crate something ^^

@rust-log-analyzer

This comment has been minimized.

@michaelwoerister
Copy link
Member

I'll take a look tomorrow.

}

blanket_impls.hash_stable(hcx, hasher);
}
Copy link
Member

Choose a reason for hiding this comment

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

This actually looks like it is unsound, right @Aaron1011 & @cjgillot? If the order is observable, we must not "stabilize" it via sorting.

@michaelwoerister
Copy link
Member

This looks good to me. If anything it makes the code more correct (see #89016 (comment)).

I would also recommend renaming the crates query to upstream_crate_nums (since it does not include LOCAL_CRATE) and document that its result is expected to be sorted by the numerical CrateNum value.

@lcnr
Copy link
Contributor Author

lcnr commented Sep 23, 2021

@bors r=nikomatsakis,michaelwoerister rollup=never

@bors
Copy link
Contributor

bors commented Sep 23, 2021

📌 Commit 01bcddb has been approved by nikomatsakis,michaelwoerister

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 23, 2021
@bors
Copy link
Contributor

bors commented Sep 23, 2021

⌛ Testing commit 01bcddb with merge bf64232...

@bors
Copy link
Contributor

bors commented Sep 23, 2021

☀️ Test successful - checks-actions
Approved by: nikomatsakis,michaelwoerister
Pushing bf64232 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Sep 23, 2021
@bors bors merged commit bf64232 into rust-lang:master Sep 23, 2021
@rustbot rustbot added this to the 1.57.0 milestone Sep 23, 2021
@rust-highfive
Copy link
Collaborator

📣 Toolstate changed by #89016!

Tested on commit bf64232.
Direct link to PR: #89016

🎉 rls on linux: test-fail → test-pass (cc @Xanewok).

rust-highfive added a commit to rust-lang-nursery/rust-toolstate that referenced this pull request Sep 23, 2021
Tested on commit rust-lang/rust@bf64232.
Direct link to PR: <rust-lang/rust#89016>

🎉 rls on linux: test-fail → test-pass (cc @Xanewok).
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (bf64232): comparison url.

Summary: This change led to large relevant mixed results 🤷 in compiler performance.

  • Large improvement in instruction counts (up to -2.6% on full builds of keccak)
  • Moderate regression in instruction counts (up to 2.8% on incr-full builds of ctfe-stress-4)

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Next Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please open an issue or create a new PR that fixes the regressions, add a comment linking to the newly created issue or PR, and then add the perf-regression-triaged label to this PR.

@rustbot label: +perf-regression

@lcnr lcnr mentioned this pull request Sep 24, 2021
@lcnr lcnr deleted the non_blanket_impls branch September 24, 2021 19:40
@rylev
Copy link
Member

rylev commented Sep 28, 2021

The improvements outweigh the regressions with the only regressions being in historically noisy benchmarks. As such I'm going to mark this as triaged.

@rustbot label +perf-regression-triaged

@rustbot rustbot added the perf-regression-triaged The performance regression has been triaged. label Sep 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. perf-regression-triaged The performance regression has been triaged. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.