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. Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
5b8cf49c51
commit
8371a036ea
7 changed files with 128 additions and 66 deletions
|
@ -66,7 +66,11 @@ fn emit_module(
|
||||||
let work_product = if backend_config.disable_incr_cache {
|
let work_product = if backend_config.disable_incr_cache {
|
||||||
None
|
None
|
||||||
} else {
|
} 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(
|
ModuleCodegenResult(
|
||||||
|
@ -82,7 +86,10 @@ fn reuse_workproduct_for_cgu(
|
||||||
) -> CompiledModule {
|
) -> CompiledModule {
|
||||||
let work_product = cgu.previous_work_product(tcx);
|
let work_product = cgu.previous_work_product(tcx);
|
||||||
let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
|
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) {
|
if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
|
||||||
tcx.sess.err(&format!(
|
tcx.sess.err(&format!(
|
||||||
"unable to copy {} to {}: {}",
|
"unable to copy {} to {}: {}",
|
||||||
|
|
|
@ -494,14 +494,20 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
|
||||||
let _timer = sess.timer("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) {
|
for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
|
||||||
if let Some(path) = &module.object {
|
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)) =
|
if let Some((id, product)) =
|
||||||
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, path)
|
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice())
|
||||||
{
|
{
|
||||||
work_products.insert(id, product);
|
work_products.insert(id, product);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
work_products
|
work_products
|
||||||
}
|
}
|
||||||
|
@ -856,29 +862,50 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
||||||
assert!(module_config.emit_obj != EmitObj::None);
|
assert!(module_config.emit_obj != EmitObj::None);
|
||||||
|
|
||||||
let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
|
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);
|
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!(
|
debug!(
|
||||||
"copying pre-existing module `{}` from {:?} to {}",
|
"copying pre-existing module `{}` from {:?} to {}",
|
||||||
module.name,
|
module.name,
|
||||||
source_file,
|
source_file,
|
||||||
obj_out.display()
|
output_path.display()
|
||||||
);
|
);
|
||||||
if let Err(err) = link_or_copy(&source_file, &obj_out) {
|
match link_or_copy(&source_file, &output_path) {
|
||||||
|
Ok(_) => Some(output_path),
|
||||||
|
Err(err) => {
|
||||||
let diag_handler = cgcx.create_diag_handler();
|
let diag_handler = cgcx.create_diag_handler();
|
||||||
diag_handler.err(&format!(
|
diag_handler.err(&format!(
|
||||||
"unable to copy {} to {}: {}",
|
"unable to copy {} to {}: {}",
|
||||||
source_file.display(),
|
source_file.display(),
|
||||||
obj_out.display(),
|
output_path.display(),
|
||||||
err
|
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"),
|
||||||
|
);
|
||||||
|
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 {
|
WorkItemResult::Compiled(CompiledModule {
|
||||||
name: module.name,
|
name: module.name,
|
||||||
kind: ModuleKind::Regular,
|
kind: ModuleKind::Regular,
|
||||||
object: Some(obj_out),
|
object,
|
||||||
dwarf_object: None,
|
dwarf_object,
|
||||||
bytecode: None,
|
bytecode: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,19 +161,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
|
||||||
Decodable::decode(&mut work_product_decoder);
|
Decodable::decode(&mut work_product_decoder);
|
||||||
|
|
||||||
for swp in work_products {
|
for swp in work_products {
|
||||||
let mut all_files_exist = true;
|
let all_files_exist = swp.work_product.saved_files.iter().all(|(_, path)| {
|
||||||
let path = in_incr_comp_dir_sess(sess, &swp.work_product.saved_file);
|
let exists = in_incr_comp_dir_sess(sess, path).exists();
|
||||||
if !path.exists() {
|
if !exists && sess.opts.debugging_opts.incremental_info {
|
||||||
all_files_exist = false;
|
eprintln!("incremental: could not find file for work product: {path}",);
|
||||||
|
|
||||||
if sess.opts.debugging_opts.incremental_info {
|
|
||||||
eprintln!(
|
|
||||||
"incremental: could not find file for work \
|
|
||||||
product: {}",
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
exists
|
||||||
|
});
|
||||||
|
|
||||||
if all_files_exist {
|
if all_files_exist {
|
||||||
debug!("reconcile_work_products: all files for {:?} exist", swp);
|
debug!("reconcile_work_products: all files for {:?} exist", swp);
|
||||||
|
|
|
@ -108,16 +108,17 @@ pub fn save_work_product_index(
|
||||||
for (id, wp) in previous_work_products.iter() {
|
for (id, wp) in previous_work_products.iter() {
|
||||||
if !new_work_products.contains_key(id) {
|
if !new_work_products.contains_key(id) {
|
||||||
work_product::delete_workproduct_files(sess, wp);
|
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:
|
// Check that we did not delete one of the current work-products:
|
||||||
debug_assert!({
|
debug_assert!({
|
||||||
new_work_products
|
new_work_products.iter().all(|(_, wp)| {
|
||||||
.iter()
|
wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
|
||||||
.map(|(_, wp)| in_incr_comp_dir_sess(sess, &wp.saved_file))
|
})
|
||||||
.all(|path| path.exists())
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
//! [work products]: WorkProduct
|
//! [work products]: WorkProduct
|
||||||
|
|
||||||
use crate::persist::fs::*;
|
use crate::persist::fs::*;
|
||||||
|
use rustc_data_structures::stable_map::FxHashMap;
|
||||||
use rustc_fs_util::link_or_copy;
|
use rustc_fs_util::link_or_copy;
|
||||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
@ -13,15 +14,19 @@ use std::path::Path;
|
||||||
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
cgu_name: &str,
|
cgu_name: &str,
|
||||||
path: &Path,
|
files: &[(&'static str, &Path)],
|
||||||
) -> Option<(WorkProductId, WorkProduct)> {
|
) -> Option<(WorkProductId, WorkProduct)> {
|
||||||
debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path);
|
debug!(?cgu_name, ?files);
|
||||||
sess.opts.incremental.as_ref()?;
|
sess.opts.incremental.as_ref()?;
|
||||||
|
|
||||||
let file_name = format!("{}.o", cgu_name);
|
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);
|
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) {
|
match link_or_copy(path, &path_in_incr_dir) {
|
||||||
Ok(_) => file_name,
|
Ok(_) => {
|
||||||
|
let _ = saved_files.insert(ext.to_string(), file_name);
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
sess.warn(&format!(
|
sess.warn(&format!(
|
||||||
"error copying object file `{}` to incremental directory as `{}`: {}",
|
"error copying object file `{}` to incremental directory as `{}`: {}",
|
||||||
|
@ -29,22 +34,21 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||||
path_in_incr_dir.display(),
|
path_in_incr_dir.display(),
|
||||||
err
|
err
|
||||||
));
|
));
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
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);
|
let work_product_id = WorkProductId::from_cgu_name(cgu_name);
|
||||||
Some((work_product_id, work_product))
|
Some((work_product_id, work_product))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes files for a given work product.
|
/// Removes files for a given work product.
|
||||||
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
|
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
|
||||||
let path = in_incr_comp_dir_sess(sess, &work_product.saved_file);
|
for (_, path) in &work_product.saved_files {
|
||||||
match std_fs::remove_file(&path) {
|
let path = in_incr_comp_dir_sess(sess, path);
|
||||||
Ok(()) => {}
|
if let Err(err) = std_fs::remove_file(&path) {
|
||||||
Err(err) => {
|
|
||||||
sess.warn(&format!(
|
sess.warn(&format!(
|
||||||
"file-system error deleting outdated file `{}`: {}",
|
"file-system error deleting outdated file `{}`: {}",
|
||||||
path.display(),
|
path.display(),
|
||||||
|
|
|
@ -886,8 +886,12 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||||
pub struct WorkProduct {
|
pub struct WorkProduct {
|
||||||
pub cgu_name: String,
|
pub cgu_name: String,
|
||||||
/// Saved file associated with this CGU.
|
/// Saved files associated with this CGU. In each key/value pair, the value is the path to the
|
||||||
pub saved_file: String,
|
/// 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.
|
// Index type for `DepNodeData`'s edges.
|
||||||
|
|
25
src/test/incremental/split_debuginfo_cached.rs
Normal file
25
src/test/incremental/split_debuginfo_cached.rs
Normal file
|
@ -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());
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue