diff --git a/Cargo.lock b/Cargo.lock index 7cf10628b0058..815575bdc0630 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4133,6 +4133,7 @@ dependencies = [ "rustc_fs_util", "rustc_hir", "rustc_hir_pretty", + "rustc_incremental", "rustc_index", "rustc_macros", "rustc_middle", diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 2bc30fa7cb045..370e886c525fd 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -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"); diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index a163518fd1952..0edc1d18ecc7b 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -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" } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 90bc427a19aec..b0ec605a85fe5 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -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; @@ -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>, + // The path containing the metadata, to record as work product. + path: Option>, // We need to carry MaybeTempDir to avoid deleting the temporary // directory while accessing the Mmap. _temp_dir: Option, @@ -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] @@ -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 Encodable for EncodedMetadata { @@ -2365,17 +2383,53 @@ impl Decodable 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 = 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. @@ -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 = 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( diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 0c998a2cbb38b..0c757a390ca01 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -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. @@ -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; diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 0a8e6153817e1..781e3e442e64c 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -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, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8aa50d14faa61..e56f98291f1ef 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3364,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( diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9fbbcdc755691..55549cba737e6 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -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::>( is_anon!([$($modifiers)*]),