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
Show file tree
Hide file tree
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
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Zoxc marked this conversation as resolved.
Show resolved Hide resolved
}

pub fn provide(providers: &mut Providers) {
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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(());
Expand Down
114 changes: 67 additions & 47 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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| {
Expand All @@ -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,
Expand All @@ -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", || {
Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
26 changes: 21 additions & 5 deletions compiler/rustc_middle/src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -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> {
Expand Down
17 changes: 14 additions & 3 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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");

Expand Down
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
Expand Down
Loading
Loading