Skip to content

Commit

Permalink
Rollup merge of #98901 - davidtwco:split-dwarf-incr-workproduct, r=mi…
Browse files Browse the repository at this point in the history
…chaelwoerister

incr: cache dwarf objects in work products

Cache DWARF objects alongside object files in work products when those exist so that DWARF object files are available for thorin in packed mode in incremental scenarios.

r? ``@michaelwoerister``
  • Loading branch information
Dylan-DPC committed Jul 7, 2022
2 parents 43ef6d0 + e106523 commit 66e47df
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 80 deletions.
11 changes: 9 additions & 2 deletions compiler/rustc_codegen_cranelift/src/driver/aot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ fn emit_module(
let work_product = if backend_config.disable_incr_cache {
None
} else {
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(tcx.sess, &name, &tmp_file)
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
tcx.sess,
&name,
&[("o", &tmp_file)],
)
};

ModuleCodegenResult(
Expand All @@ -82,7 +86,10 @@ fn reuse_workproduct_for_cgu(
) -> CompiledModule {
let work_product = cgu.previous_work_product(tcx);
let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &work_product.saved_file);
let source_file = rustc_incremental::in_incr_comp_dir_sess(
&tcx.sess,
&work_product.saved_files.get("o").expect("no saved object file in work product"),
);
if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
tcx.sess.err(&format!(
"unable to copy {} to {}: {}",
Expand Down
33 changes: 19 additions & 14 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,23 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
return;
}

let remove_temps_from_module = |module: &CompiledModule| {
if let Some(ref obj) = module.object {
ensure_removed(sess.diagnostic(), obj);
}
};
let maybe_remove_temps_from_module =
|preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| {
if !preserve_objects {
if let Some(ref obj) = module.object {
ensure_removed(sess.diagnostic(), obj);
}
}

if !preserve_dwarf_objects {
if let Some(ref dwo_obj) = module.dwarf_object {
ensure_removed(sess.diagnostic(), dwo_obj);
}
}
};

let remove_temps_from_module =
|module: &CompiledModule| maybe_remove_temps_from_module(false, false, module);

// Otherwise, always remove the metadata and allocator module temporaries.
if let Some(ref metadata_module) = codegen_results.metadata_module {
Expand All @@ -177,15 +189,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
debug!(?preserve_objects, ?preserve_dwarf_objects);

for module in &codegen_results.modules {
if !preserve_objects {
remove_temps_from_module(module);
}

if !preserve_dwarf_objects {
if let Some(ref obj) = module.dwarf_object {
ensure_removed(sess.diagnostic(), obj);
}
}
maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module);
}
});

Expand Down Expand Up @@ -649,6 +653,7 @@ fn link_dwarf_object<'a>(
sess.struct_err("linking dwarf objects with thorin failed")
.note(&format!("{:?}", e))
.emit();
sess.abort_if_errors();
}
}
}
Expand Down
75 changes: 51 additions & 24 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,12 +494,18 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");

for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
if let Some(path) = &module.object {
if let Some((id, product)) =
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, path)
{
work_products.insert(id, product);
}
let mut files = Vec::new();
if let Some(object_file_path) = &module.object {
files.push(("o", object_file_path.as_path()));
}
if let Some(dwarf_object_file_path) = &module.dwarf_object {
files.push(("dwo", dwarf_object_file_path.as_path()));
}

if let Some((id, product)) =
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice())
{
work_products.insert(id, product);
}
}

Expand Down Expand Up @@ -856,29 +862,50 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
assert!(module_config.emit_obj != EmitObj::None);

let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name));
let source_file = in_incr_comp_dir(&incr_comp_session_dir, &module.source.saved_file);
debug!(
"copying pre-existing module `{}` from {:?} to {}",
module.name,
source_file,
obj_out.display()

let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| {
let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path);
debug!(
"copying pre-existing module `{}` from {:?} to {}",
module.name,
source_file,
output_path.display()
);
match link_or_copy(&source_file, &output_path) {
Ok(_) => Some(output_path),
Err(err) => {
let diag_handler = cgcx.create_diag_handler();
diag_handler.err(&format!(
"unable to copy {} to {}: {}",
source_file.display(),
output_path.display(),
err
));
None
}
}
};

let object = load_from_incr_comp_dir(
cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)),
&module.source.saved_files.get("o").expect("no saved object file in work product"),
);
if let Err(err) = link_or_copy(&source_file, &obj_out) {
let diag_handler = cgcx.create_diag_handler();
diag_handler.err(&format!(
"unable to copy {} to {}: {}",
source_file.display(),
obj_out.display(),
err
));
}
let dwarf_object =
module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| {
let dwarf_obj_out = cgcx
.output_filenames
.split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, Some(&module.name))
.expect(
"saved dwarf object in work product but `split_dwarf_path` returned `None`",
);
load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file)
});

WorkItemResult::Compiled(CompiledModule {
name: module.name,
kind: ModuleKind::Regular,
object: Some(obj_out),
dwarf_object: None,
object,
dwarf_object,
bytecode: None,
})
}
Expand Down
18 changes: 6 additions & 12 deletions compiler/rustc_incremental/src/persist/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,19 +161,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
Decodable::decode(&mut work_product_decoder);

for swp in work_products {
let mut all_files_exist = true;
let path = in_incr_comp_dir_sess(sess, &swp.work_product.saved_file);
if !path.exists() {
all_files_exist = false;

if sess.opts.debugging_opts.incremental_info {
eprintln!(
"incremental: could not find file for work \
product: {}",
path.display()
);
let all_files_exist = swp.work_product.saved_files.iter().all(|(_, path)| {
let exists = in_incr_comp_dir_sess(sess, path).exists();
if !exists && sess.opts.debugging_opts.incremental_info {
eprintln!("incremental: could not find file for work product: {path}",);
}
}
exists
});

if all_files_exist {
debug!("reconcile_work_products: all files for {:?} exist", swp);
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_incremental/src/persist/save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,17 @@ pub fn save_work_product_index(
for (id, wp) in previous_work_products.iter() {
if !new_work_products.contains_key(id) {
work_product::delete_workproduct_files(sess, wp);
debug_assert!(!in_incr_comp_dir_sess(sess, &wp.saved_file).exists());
debug_assert!(
!wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
);
}
}

// Check that we did not delete one of the current work-products:
debug_assert!({
new_work_products
.iter()
.map(|(_, wp)| in_incr_comp_dir_sess(sess, &wp.saved_file))
.all(|path| path.exists())
new_work_products.iter().all(|(_, wp)| {
wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
})
});
}

Expand Down
46 changes: 25 additions & 21 deletions compiler/rustc_incremental/src/persist/work_product.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! [work products]: WorkProduct

use crate::persist::fs::*;
use rustc_data_structures::stable_map::FxHashMap;
use rustc_fs_util::link_or_copy;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_session::Session;
Expand All @@ -13,38 +14,41 @@ use std::path::Path;
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
sess: &Session,
cgu_name: &str,
path: &Path,
files: &[(&'static str, &Path)],
) -> Option<(WorkProductId, WorkProduct)> {
debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path);
debug!(?cgu_name, ?files);
sess.opts.incremental.as_ref()?;

let file_name = format!("{}.o", cgu_name);
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
let saved_file = match link_or_copy(path, &path_in_incr_dir) {
Ok(_) => file_name,
Err(err) => {
sess.warn(&format!(
"error copying object file `{}` to incremental directory as `{}`: {}",
path.display(),
path_in_incr_dir.display(),
err
));
return None;
let mut saved_files = FxHashMap::default();
for (ext, path) in files {
let file_name = format!("{cgu_name}.{ext}");
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
match link_or_copy(path, &path_in_incr_dir) {
Ok(_) => {
let _ = saved_files.insert(ext.to_string(), file_name);
}
Err(err) => {
sess.warn(&format!(
"error copying object file `{}` to incremental directory as `{}`: {}",
path.display(),
path_in_incr_dir.display(),
err
));
}
}
};

let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file };
}

let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_files };
debug!(?work_product);
let work_product_id = WorkProductId::from_cgu_name(cgu_name);
Some((work_product_id, work_product))
}

/// Removes files for a given work product.
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
let path = in_incr_comp_dir_sess(sess, &work_product.saved_file);
match std_fs::remove_file(&path) {
Ok(()) => {}
Err(err) => {
for (_, path) in &work_product.saved_files {
let path = in_incr_comp_dir_sess(sess, path);
if let Err(err) = std_fs::remove_file(&path) {
sess.warn(&format!(
"file-system error deleting outdated file `{}`: {}",
path.display(),
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_query_system/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,12 @@ impl<K: DepKind> DepGraph<K> {
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct WorkProduct {
pub cgu_name: String,
/// Saved file associated with this CGU.
pub saved_file: String,
/// Saved files associated with this CGU. In each key/value pair, the value is the path to the
/// saved file and the key is some identifier for the type of file being saved.
///
/// By convention, file extensions are currently used as identifiers, i.e. the key "o" maps to
/// the object file's path, and "dwo" to the dwarf object file's path.
pub saved_files: FxHashMap<String, String>,
}

// Index type for `DepNodeData`'s edges.
Expand Down
25 changes: 25 additions & 0 deletions src/test/incremental/split_debuginfo_cached.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Check that compiling with packed Split DWARF twice succeeds. This should confirm that DWARF
// objects are cached as work products and available to the incremental compilation for `thorin` to
// pack into a DWARF package.

// ignore-tidy-linelength
// only-x86_64-unknown-linux-gnu
// revisions:rpass1 rpass2

// [rpass1]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
// [rpass2]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split

#![feature(rustc_attrs)]
// For `rpass2`, nothing has changed so everything should re-used.
#![rustc_partition_reused(module = "split_debuginfo_cached", cfg = "rpass2")]
#![rustc_partition_reused(module = "split_debuginfo_cached-another_module", cfg = "rpass2")]

mod another_module {
pub fn foo() -> &'static str {
"hello world"
}
}

pub fn main() {
println!("{}", another_module::foo());
}

0 comments on commit 66e47df

Please sign in to comment.