Computing crate_hash from metadata encoding instead of HIR (implements #94878) #154724
Computing crate_hash from metadata encoding instead of HIR (implements #94878) #154724Daniel-B-Smith wants to merge 2 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
24c04d5 to
c826667
Compare
This comment has been minimized.
This comment has been minimized.
c826667 to
1fe48e6
Compare
This comment has been minimized.
This comment has been minimized.
43a7704 to
338aba3
Compare
This comment has been minimized.
This comment has been minimized.
0ddcd96 to
d27cca5
Compare
This comment has been minimized.
This comment has been minimized.
1e5f269 to
4171895
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
4171895 to
bb57d62
Compare
This comment has been minimized.
This comment has been minimized.
bb57d62 to
1ad9d87
Compare
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Computing crate_hash from metadata encoding instead of HIR (implements #94878) (very draft)
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (d83f021): comparison URL. Overall result: ✅ improvements - no action neededBenchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary -0.5%, secondary 0.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -4.1%, secondary -2.7%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 501.88s -> 497.481s (-0.88%) |
ac45cf7 to
eb78386
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
r? @mu001999 rustbot has assigned @mu001999. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
r? @cjgillot |
| extra_filename: tcx.sess.opts.cg.extra_filename.clone(), | ||
| stable_crate_id: tcx.stable_crate_id(LOCAL_CRATE), | ||
| required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE), | ||
| panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, | ||
| edition: tcx.sess.edition(), | ||
| has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), | ||
| has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), | ||
| has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), | ||
| has_default_lib_allocator: find_attr!(attrs, DefaultLibAllocator), | ||
| externally_implementable_items, | ||
| proc_macro_data, | ||
| debugger_visualizers, | ||
| compiler_builtins: find_attr!(attrs, CompilerBuiltins), | ||
| needs_allocator: find_attr!(attrs, NeedsAllocator), | ||
| needs_panic_runtime: find_attr!(attrs, NeedsPanicRuntime), | ||
| no_builtins: find_attr!(attrs, NoBuiltins), | ||
| panic_runtime: find_attr!(attrs, PanicRuntime), | ||
| profiler_runtime: find_attr!(attrs, ProfilerRuntime), | ||
| symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(), | ||
|
|
||
| crate_deps, | ||
| dylib_dependency_formats, | ||
| lib_features, | ||
| stability_implications, | ||
| lang_items, | ||
| diagnostic_items, | ||
| lang_items_missing, | ||
| stripped_cfg_items, | ||
| native_libraries, | ||
| foreign_modules, | ||
| source_map, | ||
| target_modifiers, | ||
| denied_partial_mitigations, | ||
| traits, | ||
| impls, | ||
| incoherent_impls, | ||
| exportable_items, | ||
| stable_order_of_exportable_impls, | ||
| exported_non_generic_symbols, | ||
| exported_generic_symbols, | ||
| interpret_alloc_index, | ||
| tables, | ||
| syntax_contexts, | ||
| expn_data, | ||
| expn_hashes, | ||
| def_path_hash_map, | ||
| specialization_enabled_in: tcx.specialization_enabled_in(LOCAL_CRATE), |
There was a problem hiding this comment.
How do we include all these in the hash?
There was a problem hiding this comment.
I believe almost all of these fields are covered either directly (all of the Lazy* fields) or indirectly (via the HIR hash or the dep tracking hash). is_stub isn't covered, but that's not related to the contents of the crate.
It would be annoyingly verbose, but it's completely straightforward to just add hashes for all of these fields. That might allow for removing the dependency on the HIR hash and/or the dep tracking hash. The change will probably be a small performance hit either way.
| .encode_enabled_denied_partial_mitigations()); | ||
|
|
||
| let hash = Svh::new(self.opaque.hash()); | ||
| tcx.untracked().local_crate_hash.set(hash).expect("local_crate_hash set twice"); |
There was a problem hiding this comment.
Can we make crate_hash feedable instead?
There was a problem hiding this comment.
We can make it feedable if we get rid of the crate_hash dependency in the !tcx.needs_metadata() case. See my response on map.rs for more detailed discussion of that.
| name: tcx.crate_name(LOCAL_CRATE), | ||
| triple: tcx.sess.opts.target_triple.clone(), | ||
| hash: tcx.crate_hash(LOCAL_CRATE), | ||
| hash, |
There was a problem hiding this comment.
Is this the best position to put the hash? Should we put it close to the header, after the start position? This would let us finish encoding everything and make partial decoding easier.
There was a problem hiding this comment.
I don't have a strong opinion. Everything encoded is already in the hash as finish() is called immediately after this function:
rust/compiler/rustc_metadata/src/rmeta/encoder.rs
Line 2552 in 8c1d720
rust/compiler/rustc_metadata/src/rmeta/encoder.rs
Line 2490 in 8c1d720
The partial decoding win would be nice, but my preference would be to punt the metadata format change to a follow up PR regardless.
There was a problem hiding this comment.
This probably deserves a better file name.
There was a problem hiding this comment.
How about file_encoder.rs?
I also want to flag that we could alternatively change the shared FileEncoder interface instead of forking.
| @@ -1,5 +1,6 @@ | |||
| // tidy-alphabetical-start | |||
| #![allow(internal_features)] | |||
| #![feature(core_intrinsics)] | |||
There was a problem hiding this comment.
There was a problem hiding this comment.
opaque.rs line 164
| .local_crate_hash | ||
| .get() | ||
| .expect("crate_hash(LOCAL_CRATE) called before metadata encoding") | ||
| } else { |
There was a problem hiding this comment.
When does this happen?
There was a problem hiding this comment.
It's needed in the case where incremental compilation is enabled but metadata is not (
rust/compiler/rustc_middle/src/ty/context.rs
Line 1117 in b5e038d
I tried forcing metadata generation whenever incremental compilation is enabled. It was both a large performance regression and exposed some edge cases where the library could be emitted but metadata encoding was not able to succeed.
| @@ -1122,78 +1122,30 @@ impl<'tcx> pprust_hir::PpAnn for TyCtxt<'tcx> { | |||
| } | |||
|
|
|||
| pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { | |||
There was a problem hiding this comment.
When is this implementation called? Could we get rid of it?
There was a problem hiding this comment.
This is the implementation of the crate_hash query which is used for the stub metadata header and for finalizing a session (
|
If this needs an extra pair of eyes, feel free to assign me after cjgillot reviews. |
|
Is there any ordering dependency between this PR and #155871? |
|
These are independent. The one getting in later will have to do a bit of merge conflict resolution, but nothing too bad. |
This comment has been minimized.
This comment has been minimized.
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
View all comments
This PR converts the crate_hash/SVH to depend on metadata instead of HIR whenever metadata is needed. A trimmed down crate_hash is kept for dylib/binary cases where metadata is not present. It is believed that the metadata will be a more sound way to track dependency changes.
Related to #94878
The metadata hash is calculated on the raw bytes before flush because hashing the elements incrementally turned out to be too expensive.
The change to the HIR hash is potentially safe even without the metadata crate_hash change. Without that change, this PR is a performance regression. I am bundling them because I believe the HIR hash change is more likely to be safe in light of the HIR hash being less load bearing on the SVH.
The dylib/binary crate_hash removes components that I believe are not relevant to those cases. Analysis:
The comment says: "Hash visibility information since it does not appear in HIR." Visibilities only matter to external users of the crate (i.e. consumers of metadata). Without metadata, visibility differences are not observable, so this contributes nothing for incremental correctness.
The comment says: "that content is exported into crate metadata, so any changes to it need to be reflected in the crate hash." Without metadata, there is nothing to export, so this is purely metadata-motivated. The visualizer file path is already covered by HIR (the attribute) and the content is loaded later only if metadata is being written.
These exist solely so that the crate-hash reflects remapped source paths that get embedded into metadata (the comment explicitly says "If we included the full mapping in the SVH, we could only have reproducible builds…"). The remapping itself is already captured via dep_tracking_hash, so for incremental this is redundant.
This PR currently forks
FileEncoderinstead of changing the API of a widely used type. It would not be hard to add aFnMutstrategy on flush instead of the fork. Since that would be an unpleasant merge conflict risk, I would request help to get it in quickly. If we stick with the fork, I'll make sure to port the tests. The first commit is solely the file copy, so that the diff is clean in the second commit.DO NOT SUBMIT: Incremental compilation testing is ongoing and a way to revert the hash is necessary.