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

Increase parallelism in various locations #115003

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -1973,10 +1973,11 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {

fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
let items = tcx.hir_module_items(module);
let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
let mut res = items.try_par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
res = res.and(items.try_par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
res = res.and(items.try_par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
res =
res.and(items.try_par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
if module == LocalModDefId::CRATE_DEF_ID {
super::entry::check_for_entry_fn(tcx);
}
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ mod type_of;
// Main entry point

fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
tcx.hir().par_visit_item_likes_in_module(module_def_id, || CollectItemTypesVisitor { tcx });
}

pub fn provide(providers: &mut Providers) {
12 changes: 9 additions & 3 deletions compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
@@ -98,6 +98,7 @@ mod outlives;
pub mod structured_errors;
mod variance;

use rustc_data_structures::sync::par_for_each_in;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::middle;
@@ -163,7 +164,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
// this ensures that later parts of type checking can assume that items
// have valid types and not error
tcx.sess.time("type_collecting", || {
tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module))
// Run dependencies of type collecting before entering the loop
tcx.ensure_with_value().inferred_outlives_crate(());

let _prof_timer = tcx.sess.timer("type_collecting_loop");
tcx.hir().par_for_each_module(|module| tcx.ensure().collect_mod_item_types(module));
});

if tcx.features().rustc_attrs {
@@ -175,9 +180,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
let res =
tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));

for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
par_for_each_in(tcx.all_local_trait_impls(()), |(trait_def_id, _)| {
let _ = tcx.ensure().coherent_trait(trait_def_id);
}
});

// these queries are executed for side-effects (error reporting):
let _ = tcx.ensure().crate_inherent_impls(());
let _ = tcx.ensure().crate_inherent_impls_overlap_check(());
114 changes: 67 additions & 47 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
@@ -702,14 +702,28 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
CStore::from_tcx(tcx).report_unused_deps(tcx);
},
{
// Prefetch this as it is used later by the loop below
// to prevent multiple threads from blocking on it.
tcx.ensure_with_value().get_lang_items(());

let _timer = tcx.sess.timer("misc_module_passes");
tcx.hir().par_for_each_module(|module| {
tcx.ensure().check_mod_loops(module);
tcx.ensure().check_mod_attrs(module);
tcx.ensure().check_mod_naked_functions(module);
tcx.ensure().check_mod_unstable_api_usage(module);
tcx.ensure().check_mod_const_bodies(module);
});
},
{
// Prefetch this as it is used later by the loop below
// to prevent multiple threads from blocking on it.
tcx.ensure_with_value().stability_index(());

let _timer = tcx.sess.timer("check_unstable_api_usage");
tcx.hir().par_for_each_module(|module| {
tcx.ensure().check_mod_unstable_api_usage(module);
});
},
{
sess.time("unused_lib_feature_checking", || {
rustc_passes::stability::check_unused_or_stable_features(tcx)
@@ -729,32 +743,48 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
// passes are timed inside typeck
rustc_hir_analysis::check_crate(tcx)?;

sess.time("MIR_borrow_checking", || {
tcx.hir().par_body_owners(|def_id| {
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure().check_unsafety(def_id);
tcx.ensure().mir_borrowck(def_id)
});
});

sess.time("MIR_effect_checking", || {
for def_id in tcx.hir().body_owners() {
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
}
tcx.ensure().has_ffi_unwind_calls(def_id);

// If we need to codegen, ensure that we emit all errors from
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering
// them later during codegen.
if tcx.sess.opts.output_types.should_codegen()
|| tcx.hir().body_const_context(def_id).is_some()
sess.time("misc_checking_2", || {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you explain why putting those in parallel is interesting?

parallel!(
{
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
tcx.ensure().unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id()));
// Prefetch this as it is used later by lint checking and privacy checking.
tcx.ensure_with_value().effective_visibilities(());
},
{
sess.time("MIR_borrow_checking", || {
tcx.hir().par_body_owners(|def_id| {
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure().check_unsafety(def_id);
tcx.ensure().mir_borrowck(def_id)
});
});
},
{
sess.time("MIR_effect_checking", || {
for def_id in tcx.hir().body_owners() {
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
}
tcx.ensure().has_ffi_unwind_calls(def_id);

// If we need to codegen, ensure that we emit all errors from
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering
// them later during codegen.
if tcx.sess.opts.output_types.should_codegen()
|| tcx.hir().body_const_context(def_id).is_some()
{
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
tcx.ensure()
.unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id()));
}
}
});
},
{
sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));
}
}
)
});

tcx.hir().par_body_owners(|def_id| {
@@ -764,9 +794,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
}
});

sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));

// Avoid overwhelming user with errors if borrow checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids a
// lot of annoying errors in the ui tests (basically,
@@ -782,25 +809,18 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
sess.time("misc_checking_3", || {
Copy link
Contributor

Choose a reason for hiding this comment

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

Likewise.

parallel!(
{
tcx.ensure().effective_visibilities(());

parallel!(
{
tcx.ensure().check_private_in_public(());
},
{
tcx.hir()
.par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
},
{
sess.time("lint_checking", || {
rustc_lint::check_crate(tcx);
});
},
{
tcx.ensure().clashing_extern_declarations(());
}
);
tcx.ensure().check_private_in_public(());
},
{
tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
},
{
sess.time("lint_checking", || {
rustc_lint::check_crate(tcx);
});
},
{
tcx.ensure().clashing_extern_declarations(());
},
{
sess.time("privacy_checking_modules", || {
34 changes: 34 additions & 0 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
@@ -501,6 +501,40 @@ impl<'hir> Map<'hir> {
V::Result::output()
}

/// A parallel version of `visit_item_likes_in_module`.
pub fn par_visit_item_likes_in_module<V>(
&self,
module: LocalModDefId,
make_visitor: impl Fn() -> V + DynSync,
) where
V: Visitor<'hir>,
{
let module = self.tcx.hir_module_items(module);

parallel!(
{
module.par_items(|id| {
make_visitor().visit_item(self.item(id));
});
},
{
module.par_trait_items(|id| {
make_visitor().visit_trait_item(self.trait_item(id));
});
},
{
module.par_impl_items(|id| {
make_visitor().visit_impl_item(self.impl_item(id));
});
},
{
module.par_foreign_items(|id| {
make_visitor().visit_foreign_item(self.foreign_item(id));
});
}
);
}

pub fn for_each_module(self, mut f: impl FnMut(LocalModDefId)) {
let crate_items = self.tcx.hir_crate_items(());
for module in crate_items.submodules.iter() {
26 changes: 21 additions & 5 deletions compiler/rustc_middle/src/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ pub mod place;

use crate::query::Providers;
use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync};
use rustc_data_structures::sync::{par_for_each_in, try_par_for_each_in, DynSend, DynSync};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::*;
@@ -56,33 +56,49 @@ impl ModuleItems {
self.owners().map(|id| id.def_id)
}

pub fn par_items(
pub fn try_par_items(
&self,
f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.items[..], |&id| f(id))
}

pub fn par_trait_items(
pub fn try_par_trait_items(
&self,
f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.trait_items[..], |&id| f(id))
}

pub fn par_impl_items(
pub fn try_par_impl_items(
&self,
f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.impl_items[..], |&id| f(id))
}

pub fn par_foreign_items(
pub fn try_par_foreign_items(
&self,
f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.foreign_items[..], |&id| f(id))
}

pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) {
par_for_each_in(&self.items[..], |&id| f(id))
}

pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) {
par_for_each_in(&self.trait_items[..], |&id| f(id))
}

pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) {
par_for_each_in(&self.impl_items[..], |&id| f(id))
}

pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) {
par_for_each_in(&self.foreign_items[..], |&id| f(id))
}
}

impl<'tcx> TyCtxt<'tcx> {
17 changes: 14 additions & 3 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
@@ -165,7 +165,7 @@
//! regardless of whether it is actually needed or not.

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{par_for_each_in, MTLock, MTLockRef};
use rustc_data_structures::sync::{join, par_for_each_in, MTLock, MTLockRef};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
@@ -260,8 +260,19 @@ pub fn collect_crate_mono_items(
) -> (FxHashSet<MonoItem<'_>>, UsageMap<'_>) {
let _prof_timer = tcx.prof.generic_activity("monomorphization_collector");

let roots =
tcx.sess.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode));
let (roots, _) = join(
|| {
tcx.sess
.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode))
},
|| {
if tcx.sess.opts.share_generics() {
// Prefetch upstream_monomorphizations as it's very likely to be used in
// code generation later and this is decent spot to compute it.
tcx.ensure().upstream_monomorphizations(());
}
},
);

debug!("building mono item graph, beginning at roots");

Original file line number Diff line number Diff line change
@@ -1,42 +1,32 @@
error[E0391]: cycle detected when computing predicates of `Foo`
error[E0391]: cycle detected when computing the inferred outlives predicates for items in this crate
|
note: ...which requires computing type of `Foo::bar`...
--> $DIR/cycle-iat-inside-of-adt.rs:8:5
|
LL | bar: Self::Bar,
| ^^^^^^^^^^^^^^
note: ...which requires computing normalized predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
|
note: ...which requires computing predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
note: ...which requires computing inferred outlives predicates of `Foo`...
note: ...which requires computing predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
= note: ...which requires computing the inferred outlives predicates for items in this crate...
note: ...which requires computing type of `Foo::bar`...
--> $DIR/cycle-iat-inside-of-adt.rs:8:5
|
LL | bar: Self::Bar,
| ^^^^^^^^^^^^^^
note: ...which requires computing normalized predicates of `Foo`...
note: ...which requires computing inferred outlives predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
= note: ...which again requires computing predicates of `Foo`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/cycle-iat-inside-of-adt.rs:3:1
|
LL | / #![feature(inherent_associated_types)]
LL | | #![allow(incomplete_features)]
LL | | // FIXME(inherent_associated_types): This should pass.
LL | |
... |
LL | |
LL | | fn main() {}
| |____________^
= note: ...which again requires computing the inferred outlives predicates for items in this crate, completing the cycle
= note: cycle used when running analysis passes on this crate
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 1 previous error
Loading
Loading