Skip to content

Commit 58d4b8e

Browse files
committed
Modify trans to skip generating .o files
This checks the `previous_work_products` data from the dep-graph and tries to simply copy a `.o` file if possible. We also add new work-products into the dep-graph, and create edges to/from the dep-node for a work-product.
1 parent cca4804 commit 58d4b8e

File tree

14 files changed

+385
-98
lines changed

14 files changed

+385
-98
lines changed

src/librustc_incremental/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,6 @@ pub use assert_dep_graph::assert_dep_graph;
4141
pub use calculate_svh::SvhCalculate;
4242
pub use persist::load_dep_graph;
4343
pub use persist::save_dep_graph;
44+
pub use persist::save_trans_partition;
4445
pub use persist::save_work_products;
46+
pub use persist::in_incr_comp_dir;

src/librustc_incremental/persist/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ mod hash;
1919
mod load;
2020
mod save;
2121
mod util;
22+
mod work_product;
2223

2324
pub use self::load::load_dep_graph;
2425
pub use self::save::save_dep_graph;
2526
pub use self::save::save_work_products;
27+
pub use self::work_product::save_trans_partition;
28+
pub use self::util::in_incr_comp_dir;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! This module contains files for saving intermediate work-products.
12+
13+
use persist::util::*;
14+
use rustc::dep_graph::{WorkProduct, WorkProductId};
15+
use rustc::session::Session;
16+
use std::fs;
17+
use std::path::Path;
18+
use std::sync::Arc;
19+
20+
pub fn save_trans_partition(sess: &Session,
21+
partition_name: &str,
22+
partition_hash: u64,
23+
path_to_obj_file: &Path) {
24+
debug!("save_trans_partition({:?},{},{})",
25+
partition_name,
26+
partition_hash,
27+
path_to_obj_file.display());
28+
if sess.opts.incremental.is_none() {
29+
return;
30+
}
31+
let id = Arc::new(WorkProductId::PartitionObjectFile(partition_name.to_string()));
32+
let file_name = format!("cgu-{}", partition_name);
33+
let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap();
34+
35+
// try to delete the file if it already exists
36+
//
37+
// FIXME(#34955) we can be smarter here -- if we are re-using, no need to do anything
38+
if path_in_incr_dir.exists() {
39+
let _ = fs::remove_file(&path_in_incr_dir);
40+
}
41+
42+
match
43+
fs::hard_link(path_to_obj_file, &path_in_incr_dir)
44+
.or_else(|_| fs::copy(path_to_obj_file, &path_in_incr_dir).map(|_| ()))
45+
{
46+
Ok(_) => {
47+
let work_product = WorkProduct {
48+
input_hash: partition_hash,
49+
file_name: file_name,
50+
};
51+
sess.dep_graph.insert_work_product(&id, work_product);
52+
}
53+
Err(err) => {
54+
sess.warn(&format!("error copying object file `{}` \
55+
to incremental directory as `{}`: {}",
56+
path_to_obj_file.display(),
57+
path_in_incr_dir.display(),
58+
err));
59+
}
60+
}
61+
}

src/librustc_trans/back/write.rs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010

1111
use back::lto;
1212
use back::link::{get_linker, remove};
13+
use rustc_incremental::save_trans_partition;
1314
use session::config::{OutputFilenames, Passes, SomePasses, AllPasses};
1415
use session::Session;
1516
use session::config::{self, OutputType};
1617
use llvm;
1718
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
1819
use llvm::SMDiagnosticRef;
19-
use {CrateTranslation, ModuleTranslation};
20+
use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
2021
use util::common::time;
2122
use util::common::path2cstr;
2223
use errors::{self, Handler, Level, DiagnosticBuilder};
@@ -26,6 +27,7 @@ use syntax_pos::MultiSpan;
2627
use std::collections::HashMap;
2728
use std::ffi::{CStr, CString};
2829
use std::fs;
30+
use std::io;
2931
use std::path::{Path, PathBuf};
3032
use std::str;
3133
use std::sync::{Arc, Mutex};
@@ -422,10 +424,11 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
422424
// Unsafe due to LLVM calls.
423425
unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
424426
mtrans: ModuleTranslation,
427+
mllvm: ModuleLlvm,
425428
config: ModuleConfig,
426429
output_names: OutputFilenames) {
427-
let llmod = mtrans.llmod;
428-
let llcx = mtrans.llcx;
430+
let llmod = mllvm.llmod;
431+
let llcx = mllvm.llcx;
429432
let tm = config.tm;
430433

431434
// llcx doesn't outlive this function, so we can put this on the stack.
@@ -628,8 +631,14 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
628631
pub fn cleanup_llvm(trans: &CrateTranslation) {
629632
for module in trans.modules.iter() {
630633
unsafe {
631-
llvm::LLVMDisposeModule(module.llmod);
632-
llvm::LLVMContextDispose(module.llcx);
634+
match module.source {
635+
ModuleSource::Translated(llvm) => {
636+
llvm::LLVMDisposeModule(llvm.llmod);
637+
llvm::LLVMContextDispose(llvm.llcx);
638+
}
639+
ModuleSource::Preexisting(_) => {
640+
}
641+
}
633642
}
634643
}
635644
}
@@ -743,6 +752,13 @@ pub fn run_passes(sess: &Session,
743752
run_work_multithreaded(sess, work_items, num_workers);
744753
}
745754

755+
// If in incr. comp. mode, preserve the `.o` files for potential re-use
756+
for mtrans in trans.modules.iter() {
757+
let path_to_obj = crate_output.temp_path(OutputType::Object, Some(&mtrans.name));
758+
debug!("wrote module {:?} to {:?}", mtrans.name, path_to_obj);
759+
save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &path_to_obj);
760+
}
761+
746762
// All codegen is finished.
747763
unsafe {
748764
llvm::LLVMRustDisposeTargetMachine(tm);
@@ -913,13 +929,46 @@ fn build_work_item(sess: &Session,
913929
}
914930
}
915931

932+
fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<()> {
933+
let p = p.as_ref();
934+
let q = q.as_ref();
935+
if q.exists() {
936+
try!(fs::remove_file(&q));
937+
}
938+
fs::hard_link(p, q)
939+
.or_else(|_| fs::copy(p, q).map(|_| ()))
940+
}
941+
916942
fn execute_work_item(cgcx: &CodegenContext,
917943
work_item: WorkItem) {
918944
unsafe {
919-
optimize_and_codegen(cgcx,
920-
work_item.mtrans,
921-
work_item.config,
922-
work_item.output_names);
945+
match work_item.mtrans.source {
946+
ModuleSource::Translated(mllvm) => {
947+
debug!("llvm-optimizing {:?}", work_item.mtrans.name);
948+
optimize_and_codegen(cgcx,
949+
work_item.mtrans,
950+
mllvm,
951+
work_item.config,
952+
work_item.output_names);
953+
}
954+
ModuleSource::Preexisting(ref buf) => {
955+
let obj_out = work_item.output_names.temp_path(OutputType::Object,
956+
Some(&work_item.mtrans.name));
957+
debug!("copying pre-existing module `{}` from {} to {}",
958+
work_item.mtrans.name,
959+
buf.display(),
960+
obj_out.display());
961+
match link_or_copy(buf, &obj_out) {
962+
Ok(()) => { }
963+
Err(err) => {
964+
cgcx.handler.err(&format!("unable to copy {} to {}: {}",
965+
buf.display(),
966+
obj_out.display(),
967+
err));
968+
}
969+
}
970+
}
971+
}
923972
}
924973
}
925974

0 commit comments

Comments
 (0)