Skip to content

Commit 9310a5e

Browse files
committed
Auto merge of #114669 - cjgillot:metadata-wp, r=<try>
Make metadata a workproduct and reuse it This PR aims to skip the generation of metadata by reusing the infrastructure that already exists for compiled codegen-units, namely "workproducts". This can yield substantial gains (~10%) when we can demonstrate that metadata does not change between an incremental session and the next. This is the case if the crate is unchanged, or if all the changes are in upstream crates and have no effect on it. This latter case is most interesting, as it arises regularly for users with several crates in their workspace. TODO: - [ ] Materialize the fact that metadata encoding relies on the relative order of definitions; - [ ] Refactor the handling of doc links.
2 parents c16823d + 9742c49 commit 9310a5e

File tree

11 files changed

+110
-34
lines changed

11 files changed

+110
-34
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4067,6 +4067,7 @@ dependencies = [
40674067
"rustc_fs_util",
40684068
"rustc_hir",
40694069
"rustc_hir_pretty",
4070+
"rustc_incremental",
40704071
"rustc_index",
40714072
"rustc_macros",
40724073
"rustc_middle",

compiler/rustc_codegen_cranelift/src/driver/aot.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,21 @@ impl OngoingCodegen {
5656
backend_config: &BackendConfig,
5757
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
5858
let mut work_products = FxIndexMap::default();
59+
60+
if !backend_config.disable_incr_cache {
61+
if let Some(path) = self.metadata.path() {
62+
if let Some((id, product)) =
63+
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
64+
sess,
65+
"metadata",
66+
&[("rmeta", path)],
67+
)
68+
{
69+
work_products.insert(id, product);
70+
}
71+
}
72+
}
73+
5974
let mut modules = vec![];
6075

6176
for module_codegen in self.modules {

compiler/rustc_codegen_ssa/src/back/write.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
507507

508508
fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
509509
sess: &Session,
510+
metadata: &EncodedMetadata,
510511
compiled_modules: &CompiledModules,
511512
) -> FxIndexMap<WorkProductId, WorkProduct> {
512513
let mut work_products = FxIndexMap::default();
@@ -517,6 +518,14 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
517518

518519
let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
519520

521+
if let Some(path) = metadata.path() {
522+
if let Some((id, product)) =
523+
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, "metadata", &[("rmeta", path)])
524+
{
525+
work_products.insert(id, product);
526+
}
527+
}
528+
520529
for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
521530
let mut files = Vec::new();
522531
if let Some(object_file_path) = &module.object {
@@ -1973,8 +1982,11 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
19731982

19741983
sess.abort_if_errors();
19751984

1976-
let work_products =
1977-
copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, &compiled_modules);
1985+
let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(
1986+
sess,
1987+
&self.metadata,
1988+
&compiled_modules,
1989+
);
19781990
produce_final_output_artifacts(sess, &compiled_modules, &self.output_filenames);
19791991

19801992
// FIXME: time_llvm_passes support - does this use a global context or

compiler/rustc_metadata/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
2121
rustc_fs_util = { path = "../rustc_fs_util" }
2222
rustc_hir = { path = "../rustc_hir" }
2323
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
24+
rustc_incremental = { path = "../rustc_incremental" }
2425
rustc_target = { path = "../rustc_target" }
2526
rustc_index = { path = "../rustc_index" }
2627
rustc_macros = { path = "../rustc_macros" }

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14681468
let table = tcx.associated_types_for_impl_traits_in_associated_fn(def_id);
14691469
record_defaulted_array!(self.tables.associated_types_for_impl_traits_in_associated_fn[def_id] <- table);
14701470
}
1471+
if let DefKind::Mod = tcx.def_kind(def_id) {
1472+
record!(self.tables.doc_link_resolutions[def_id] <- tcx.doc_link_resolutions(def_id));
1473+
record_array!(self.tables.doc_link_traits_in_scope[def_id] <- tcx.doc_link_traits_in_scope(def_id));
1474+
}
14711475
}
14721476

14731477
let inherent_impls = tcx.with_stable_hashing_context(|hcx| {
@@ -1479,14 +1483,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14791483
def_id.index
14801484
}));
14811485
}
1482-
1483-
for (def_id, res_map) in &tcx.resolutions(()).doc_link_resolutions {
1484-
record!(self.tables.doc_link_resolutions[def_id.to_def_id()] <- res_map);
1485-
}
1486-
1487-
for (def_id, traits) in &tcx.resolutions(()).doc_link_traits_in_scope {
1488-
record_array!(self.tables.doc_link_traits_in_scope[def_id.to_def_id()] <- traits);
1489-
}
14901486
}
14911487

14921488
#[instrument(level = "trace", skip(self))]
@@ -2126,6 +2122,8 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
21262122
pub struct EncodedMetadata {
21272123
// The declaration order matters because `mmap` should be dropped before `_temp_dir`.
21282124
mmap: Option<Mmap>,
2125+
// The path containing the metadata, to record as work product.
2126+
path: Option<Box<Path>>,
21292127
// We need to carry MaybeTempDir to avoid deleting the temporary
21302128
// directory while accessing the Mmap.
21312129
_temp_dir: Option<MaybeTempDir>,
@@ -2137,16 +2135,21 @@ impl EncodedMetadata {
21372135
let file = std::fs::File::open(&path)?;
21382136
let file_metadata = file.metadata()?;
21392137
if file_metadata.len() == 0 {
2140-
return Ok(Self { mmap: None, _temp_dir: None });
2138+
return Ok(Self { mmap: None, path: None, _temp_dir: None });
21412139
}
21422140
let mmap = unsafe { Some(Mmap::map(file)?) };
2143-
Ok(Self { mmap, _temp_dir: temp_dir })
2141+
Ok(Self { mmap, path: Some(path.into()), _temp_dir: temp_dir })
21442142
}
21452143

21462144
#[inline]
21472145
pub fn raw_data(&self) -> &[u8] {
21482146
self.mmap.as_deref().unwrap_or_default()
21492147
}
2148+
2149+
#[inline]
2150+
pub fn path(&self) -> Option<&Path> {
2151+
self.path.as_deref()
2152+
}
21502153
}
21512154

21522155
impl<S: Encoder> Encodable<S> for EncodedMetadata {
@@ -2170,19 +2173,40 @@ impl<D: Decoder> Decodable<D> for EncodedMetadata {
21702173
None
21712174
};
21722175

2173-
Self { mmap, _temp_dir: None }
2176+
Self { mmap, path: None, _temp_dir: None }
21742177
}
21752178
}
21762179

2180+
#[instrument(level = "trace", skip(tcx))]
21772181
pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
2182+
let dep_node = tcx.metadata_dep_node();
2183+
2184+
if tcx.dep_graph.is_fully_enabled()
2185+
&& let work_product_id = &rustc_middle::dep_graph::WorkProductId::from_cgu_name("metadata")
2186+
&& let Some(work_product) = tcx.dep_graph.previous_work_product(work_product_id)
2187+
&& tcx.try_mark_green(&dep_node)
2188+
{
2189+
let saved_path = &work_product.saved_files["rmeta"];
2190+
let incr_comp_session_dir = tcx.sess.incr_comp_session_dir_opt().unwrap();
2191+
let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, saved_path);
2192+
debug!("copying preexisting metadata from {source_file:?} to {path:?}");
2193+
match rustc_fs_util::link_or_copy(&source_file, path) {
2194+
Ok(_) => {}
2195+
Err(err) => {
2196+
tcx.sess.emit_fatal(FailCreateFileEncoder { err });
2197+
}
2198+
};
2199+
return;
2200+
};
2201+
21782202
let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata");
21792203

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

21842208
join(
2185-
|| encode_metadata_impl(tcx, path),
2209+
|| tcx.dep_graph.with_task(dep_node, tcx, path, encode_metadata_impl, None),
21862210
|| {
21872211
if tcx.sess.threads() == 1 {
21882212
return;

compiler/rustc_middle/src/dep_graph/dep_node.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ rustc_query_append!(define_dep_nodes![
140140
[] fn TraitSelect() -> (),
141141
[] fn CompileCodegenUnit() -> (),
142142
[] fn CompileMonoItem() -> (),
143+
[] fn Metadata() -> (),
143144
]);
144145

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

161+
// WARNING: `construct` is generic and does not know that `Metadata` takes `()`s as keys.
162+
// Be very careful changing this type signature!
163+
pub(crate) fn make_metadata(tcx: TyCtxt<'_>) -> DepNode {
164+
DepNode::construct(tcx, dep_kinds::Metadata, &())
165+
}
166+
160167
pub trait DepNodeExt: Sized {
161168
/// Extracts the DefId corresponding to this DepNode. This will work
162169
/// if two conditions are met:

compiler/rustc_middle/src/dep_graph/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub use rustc_query_system::dep_graph::{
1414
};
1515

1616
pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt};
17-
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
17+
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item, make_metadata};
1818

1919
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepsType>;
2020

compiler/rustc_middle/src/query/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,16 @@ rustc_queries! {
132132
desc { "getting the resolver for lowering" }
133133
}
134134

135+
/// Named module children from all kinds of items, including imports.
136+
/// In addition to regular items this list also includes struct and variant constructors, and
137+
/// items inside `extern {}` blocks because all of them introduce names into parent module.
138+
///
139+
/// Module here is understood in name resolution sense - it can be a `mod` item,
140+
/// or a crate root, or an enum, or a trait.
141+
query module_children_local(key: LocalDefId) -> &'tcx [ModChild] {
142+
desc { |tcx| "module exports for `{}`", tcx.def_path_str(key) }
143+
}
144+
135145
/// Return the span for a definition.
136146
/// Contrary to `def_span` below, this query returns the full absolute span of the definition.
137147
/// This span is meant for dep-tracking rather than diagnostics. It should not be used outside

compiler/rustc_middle/src/ty/context.rs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::arena::Arena;
88
use crate::dep_graph::{DepGraph, DepKindStruct};
99
use crate::infer::canonical::CanonicalVarInfo;
1010
use crate::lint::struct_lint_level;
11-
use crate::metadata::ModChild;
1211
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
1312
use crate::middle::resolve_bound_vars;
1413
use crate::middle::stability;
@@ -955,9 +954,8 @@ impl<'tcx> TyCtxtAt<'tcx> {
955954

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

962960
let definitions = &self.untracked.definitions;
963961
std::iter::from_generator(|| {
@@ -977,9 +975,8 @@ impl<'tcx> TyCtxt<'tcx> {
977975
}
978976

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

984981
// Freeze definitions once we start iterating on them, to prevent adding new ones
985982
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
@@ -2137,17 +2134,8 @@ impl<'tcx> TyCtxt<'tcx> {
21372134
self.opt_rpitit_info(def_id).is_some()
21382135
}
21392136

2140-
/// Named module children from all kinds of items, including imports.
2141-
/// In addition to regular items this list also includes struct and variant constructors, and
2142-
/// items inside `extern {}` blocks because all of them introduce names into parent module.
2143-
///
2144-
/// Module here is understood in name resolution sense - it can be a `mod` item,
2145-
/// or a crate root, or an enum, or a trait.
2146-
///
2147-
/// This is not a query, making it a query causes perf regressions
2148-
/// (probably due to hashing spans in `ModChild`ren).
2149-
pub fn module_children_local(self, def_id: LocalDefId) -> &'tcx [ModChild] {
2150-
self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..])
2137+
pub fn metadata_dep_node(self) -> crate::dep_graph::DepNode {
2138+
crate::dep_graph::make_metadata(self)
21512139
}
21522140
}
21532141

@@ -2167,6 +2155,8 @@ pub struct DeducedParamAttrs {
21672155
}
21682156

21692157
pub fn provide(providers: &mut Providers) {
2158+
providers.module_children_local =
2159+
|tcx, def_id| tcx.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..]);
21702160
providers.maybe_unused_trait_imports =
21712161
|tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
21722162
providers.names_imported_by_glob_use = |tcx, id| {

compiler/rustc_query_impl/src/plumbing.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,17 @@ macro_rules! define_queries {
792792
}
793793
}
794794

795+
pub fn Metadata<'tcx>() -> DepKindStruct<'tcx> {
796+
DepKindStruct {
797+
is_anon: false,
798+
is_eval_always: false,
799+
fingerprint_style: FingerprintStyle::Unit,
800+
force_from_dep_node: None,
801+
try_load_from_on_disk_cache: None,
802+
name: &"Metadata",
803+
}
804+
}
805+
795806
$(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> {
796807
$crate::plumbing::query_callback::<query_impl::$name::QueryType<'tcx>>(
797808
is_anon!([$($modifiers)*]),

compiler/rustc_resolve/src/late.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1360,13 +1360,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
13601360
}
13611361

13621362
fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
1363-
if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) {
1363+
let def_id = self.r.local_def_id(id);
1364+
if let Some(module) = self.r.get_module(def_id.to_def_id()) {
13641365
// Move down in the graph.
13651366
let orig_module = replace(&mut self.parent_scope.module, module);
13661367
self.with_rib(ValueNS, RibKind::Module(module), |this| {
13671368
this.with_rib(TypeNS, RibKind::Module(module), |this| {
13681369
let ret = f(this);
13691370
this.parent_scope.module = orig_module;
1371+
this.r.doc_link_resolutions.entry(def_id).or_default();
1372+
this.r.doc_link_traits_in_scope.entry(def_id).or_default();
13701373
ret
13711374
})
13721375
})
@@ -4561,5 +4564,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
45614564
for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
45624565
self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
45634566
}
4567+
self.doc_link_resolutions.entry(CRATE_DEF_ID).or_default();
4568+
self.doc_link_traits_in_scope.entry(CRATE_DEF_ID).or_default();
45644569
}
45654570
}

0 commit comments

Comments
 (0)