Skip to content

Make metadata a workproduct and reuse it #114669

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

Open
wants to merge 6 commits 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

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4134,6 +4134,7 @@ dependencies = [
"rustc_fs_util",
"rustc_hir",
"rustc_hir_pretty",
"rustc_incremental",
"rustc_index",
"rustc_macros",
"rustc_middle",
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,8 +871,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
providers.analysis = analysis;
providers.hir_crate = rustc_ast_lowering::lower_to_hir;
providers.resolver_for_lowering_raw = resolver_for_lowering_raw;
providers.stripped_cfg_items =
|tcx, _| tcx.arena.alloc_from_iter(tcx.resolutions(()).stripped_cfg_items.steal());
providers.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..];
providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
providers.early_lint_checks = early_lint_checks;
providers.env_var_os = env_var_os;
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_interface/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,24 @@ impl Linker {
}

pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) {
let (codegen_results, work_products) = sess.time("finish_ongoing_codegen", || {
let (codegen_results, mut work_products) = sess.time("finish_ongoing_codegen", || {
codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames)
});
sess.timings.end_section(sess.dcx(), TimingSection::Codegen);

if sess.opts.incremental.is_some()
&& let Some(path) = self.metadata.path()
&& let Some((id, product)) =
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
sess,
"metadata",
&[("rmeta", path)],
&[],
)
{
work_products.insert(id, product);
}

sess.dcx().abort_if_errors();

let _timer = sess.timer("link");
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
Expand Down
117 changes: 84 additions & 33 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet};
use rustc_hir::definitions::DefPathData;
use rustc_hir_pretty::id_to_string;
use rustc_middle::dep_graph::WorkProductId;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::metadata_symbol_name;
use rustc_middle::mir::interpret;
Expand Down Expand Up @@ -2307,6 +2308,8 @@ pub struct EncodedMetadata {
// This is an optional stub metadata containing only the crate header.
// The header should be very small, so we load it directly into memory.
stub_metadata: Option<Vec<u8>>,
// The path containing the metadata, to record as work product.
path: Option<Box<Path>>,
// We need to carry MaybeTempDir to avoid deleting the temporary
// directory while accessing the Mmap.
_temp_dir: Option<MaybeTempDir>,
Expand All @@ -2322,14 +2325,24 @@ impl EncodedMetadata {
let file = std::fs::File::open(&path)?;
let file_metadata = file.metadata()?;
if file_metadata.len() == 0 {
return Ok(Self { full_metadata: None, stub_metadata: None, _temp_dir: None });
return Ok(Self {
full_metadata: None,
stub_metadata: None,
path: None,
_temp_dir: None,
});
}
let full_mmap = unsafe { Some(Mmap::map(file)?) };

let stub =
if let Some(stub_path) = stub_path { Some(std::fs::read(stub_path)?) } else { None };

Ok(Self { full_metadata: full_mmap, stub_metadata: stub, _temp_dir: temp_dir })
Ok(Self {
full_metadata: full_mmap,
stub_metadata: stub,
path: Some(path.into()),
_temp_dir: temp_dir,
})
}

#[inline]
Expand All @@ -2341,6 +2354,11 @@ impl EncodedMetadata {
pub fn stub_or_full(&self) -> &[u8] {
self.stub_metadata.as_deref().unwrap_or(self.full())
}

#[inline]
pub fn path(&self) -> Option<&Path> {
self.path.as_deref()
}
}

impl<S: Encoder> Encodable<S> for EncodedMetadata {
Expand All @@ -2365,17 +2383,53 @@ impl<D: Decoder> Decodable<D> for EncodedMetadata {
None
};

Self { full_metadata, stub_metadata: stub, _temp_dir: None }
Self { full_metadata, stub_metadata: stub, path: None, _temp_dir: None }
}
}

#[instrument(level = "trace", skip(tcx))]
pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) {
let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata");

// Since encoding metadata is not in a query, and nothing is cached,
// there's no need to do dep-graph tracking for any of it.
tcx.dep_graph.assert_ignored();

// Generate the metadata stub manually, as that is a small file compared to full metadata.
if let Some(ref_path) = ref_path {
let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata_stub");

with_encode_metadata_header(tcx, ref_path, |ecx| {
let header: LazyValue<CrateHeader> = ecx.lazy(CrateHeader {
name: tcx.crate_name(LOCAL_CRATE),
triple: tcx.sess.opts.target_triple.clone(),
hash: tcx.crate_hash(LOCAL_CRATE),
is_proc_macro_crate: false,
is_stub: true,
});
header.position.get()
})
}

let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata");

let dep_node = tcx.metadata_dep_node();

// If the metadata dep-node is green, try to reuse the saved work product.
if tcx.dep_graph.is_fully_enabled()
&& let work_product_id = WorkProductId::from_cgu_name("metadata")
&& let Some(work_product) = tcx.dep_graph.previous_work_product(&work_product_id)
&& tcx.try_mark_green(&dep_node)
{
let saved_path = &work_product.saved_files["rmeta"];
let incr_comp_session_dir = tcx.sess.incr_comp_session_dir_opt().unwrap();
let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, saved_path);
debug!("copying preexisting metadata from {source_file:?} to {path:?}");
match rustc_fs_util::link_or_copy(&source_file, path) {
Ok(_) => {}
Err(err) => tcx.dcx().emit_fatal(FailCreateFileEncoder { err }),
};
return;
};

if tcx.sess.threads() != 1 {
// Prefetch some queries used by metadata encoding.
// This is not necessary for correctness, but is only done for performance reasons.
Expand All @@ -2389,35 +2443,32 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) {
);
}

with_encode_metadata_header(tcx, path, |ecx| {
// Encode all the entries and extra information in the crate,
// culminating in the `CrateRoot` which points to all of it.
let root = ecx.encode_crate_root();

// Flush buffer to ensure backing file has the correct size.
ecx.opaque.flush();
// Record metadata size for self-profiling
tcx.prof.artifact_size(
"crate_metadata",
"crate_metadata",
ecx.opaque.file().metadata().unwrap().len(),
);

root.position.get()
});
// Perform metadata encoding inside a task, so the dep-graph can check if any encoded
// information changes, and maybe reuse the work product.
tcx.dep_graph.with_task(
dep_node,
tcx,
path,
|tcx, path| {
with_encode_metadata_header(tcx, path, |ecx| {
// Encode all the entries and extra information in the crate,
// culminating in the `CrateRoot` which points to all of it.
let root = ecx.encode_crate_root();

// Flush buffer to ensure backing file has the correct size.
ecx.opaque.flush();
// Record metadata size for self-profiling
tcx.prof.artifact_size(
"crate_metadata",
"crate_metadata",
ecx.opaque.file().metadata().unwrap().len(),
);

if let Some(ref_path) = ref_path {
with_encode_metadata_header(tcx, ref_path, |ecx| {
let header: LazyValue<CrateHeader> = ecx.lazy(CrateHeader {
name: tcx.crate_name(LOCAL_CRATE),
triple: tcx.sess.opts.target_triple.clone(),
hash: tcx.crate_hash(LOCAL_CRATE),
is_proc_macro_crate: false,
is_stub: true,
});
header.position.get()
});
}
root.position.get()
})
},
None,
);
}

fn with_encode_metadata_header(
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ rustc_with_all_queries!(define_dep_nodes![
[] fn TraitSelect() -> (),
[] fn CompileCodegenUnit() -> (),
[] fn CompileMonoItem() -> (),
[] fn Metadata() -> (),
]);

// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
Expand All @@ -115,6 +116,12 @@ pub(crate) fn make_compile_mono_item<'tcx>(
DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item)
}

// WARNING: `construct` is generic and does not know that `Metadata` takes `()`s as keys.
// Be very careful changing this type signature!
pub(crate) fn make_metadata(tcx: TyCtxt<'_>) -> DepNode {
DepNode::construct(tcx, dep_kinds::Metadata, &())
}

pub trait DepNodeExt: Sized {
fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::ty::{self, TyCtxt};
mod dep_node;

pub use dep_node::{DepKind, DepNode, DepNodeExt, dep_kinds, label_strs};
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item, make_metadata};
pub use rustc_query_system::dep_graph::debug::{DepNodeFilter, EdgeFilter};
pub use rustc_query_system::dep_graph::{
DepContext, DepGraphQuery, DepNodeIndex, Deps, SerializedDepGraph, SerializedDepNodeIndex,
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ rustc_queries! {
}

query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt {
no_hash
desc { "getting the resolver outputs" }
}

Expand Down
14 changes: 8 additions & 6 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2058,9 +2058,8 @@ impl<'tcx> TyCtxt<'tcx> {
}

pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> {
// Create a dependency to the red node to be sure we re-execute this when the amount of
// definitions change.
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
// Depend on the `analysis` query to ensure compilation if finished.
self.ensure_ok().analysis(());

let definitions = &self.untracked.definitions;
gen {
Expand All @@ -2080,9 +2079,8 @@ impl<'tcx> TyCtxt<'tcx> {
}

pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
// Create a dependency to the crate to be sure we re-execute this when the amount of
// definitions change.
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
// Depend on the `analysis` query to ensure compilation if finished.
self.ensure_ok().analysis(());

// Freeze definitions once we start iterating on them, to prevent adding new ones
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
Expand Down Expand Up @@ -3366,6 +3364,10 @@ impl<'tcx> TyCtxt<'tcx> {
self.resolver_for_lowering_raw(()).0
}

pub fn metadata_dep_node(self) -> crate::dep_graph::DepNode {
crate::dep_graph::make_metadata(self)
}

/// Given an `impl_id`, return the trait it implements.
/// Return `None` if this is an inherent impl.
pub fn impl_trait_ref(
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::unord::UnordMap;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::{Diag, ErrorGuaranteed};
use rustc_hir::LangItem;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
Expand Down Expand Up @@ -176,11 +176,11 @@ pub struct ResolverOutputs {
pub ast_lowering: ResolverAstLowering,
}

#[derive(Debug)]
#[derive(Debug, HashStable)]
pub struct ResolverGlobalCtxt {
pub visibilities_for_hashing: Vec<(LocalDefId, Visibility)>,
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
pub expn_that_defined: UnordMap<LocalDefId, ExpnId>,
pub effective_visibilities: EffectiveVisibilities,
pub extern_crate_map: UnordMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
Expand All @@ -196,8 +196,8 @@ pub struct ResolverGlobalCtxt {
pub confused_type_with_std_module: FxIndexMap<Span, Span>,
pub doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
pub doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>,
pub all_macro_rules: FxHashSet<Symbol>,
pub stripped_cfg_items: Steal<Vec<StrippedCfgItem>>,
pub all_macro_rules: UnordSet<Symbol>,
pub stripped_cfg_items: Vec<StrippedCfgItem>,
}

/// Resolutions that should only be used for lowering.
Expand Down Expand Up @@ -243,7 +243,7 @@ pub struct DelegationFnSig {
pub target_feature: bool,
}

#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, HashStable)]
pub struct MainDefinition {
pub res: Res<ast::NodeId>,
pub is_import: bool,
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_query_impl/src/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,17 @@ macro_rules! define_queries {
}
}

pub(crate) fn Metadata<'tcx>() -> DepKindStruct<'tcx> {
DepKindStruct {
is_anon: false,
is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
name: &"Metadata",
}
}

$(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> {
$crate::plumbing::query_callback::<query_impl::$name::QueryType<'tcx>>(
is_anon!([$($modifiers)*]),
Expand Down
Loading
Loading