Skip to content

Commit 9ea3878

Browse files
committed
Auto merge of #45399 - alexcrichton:compress-parallel, r=michaelwoerister
rustc: Move bytecode compression into codegen This commit moves compression of the bytecode from the `link` module to the `write` module, namely allowing it to be (a) cached by incremental compilation and (b) produced in parallel. The parallelization may show up as some nice wins during normal compilation and the caching in incremental mode should be beneficial for incremental compiles! (no more need to recompress the entire crate's bitcode on all builds)
2 parents 4279e2b + 8197a0b commit 9ea3878

File tree

7 files changed

+193
-175
lines changed

7 files changed

+193
-175
lines changed

src/librustc/dep_graph/graph.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
1212
StableHashingContextProvider};
1313
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1414
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
15-
use session::config::OutputType;
1615
use std::cell::{Ref, RefCell};
1716
use std::env;
1817
use std::hash::Hash;
@@ -647,7 +646,14 @@ impl DepGraph {
647646
pub struct WorkProduct {
648647
pub cgu_name: String,
649648
/// Saved files associated with this CGU
650-
pub saved_files: Vec<(OutputType, String)>,
649+
pub saved_files: Vec<(WorkProductFileKind, String)>,
650+
}
651+
652+
#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)]
653+
pub enum WorkProductFileKind {
654+
Object,
655+
Bytecode,
656+
BytecodeCompressed,
651657
}
652658

653659
pub(super) struct CurrentDepGraph {

src/librustc/dep_graph/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ mod serialized;
2121
pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
2222
pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs};
2323
pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor};
24+
pub use self::graph::WorkProductFileKind;
2425
pub use self::prev::PreviousDepGraph;
2526
pub use self::query::DepGraphQuery;
2627
pub use self::safe::AssertDepGraphSafe;

src/librustc_incremental/persist/work_product.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,33 @@
1111
//! This module contains files for saving intermediate work-products.
1212
1313
use persist::fs::*;
14-
use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph};
14+
use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph, WorkProductFileKind};
1515
use rustc::session::Session;
16-
use rustc::session::config::OutputType;
1716
use rustc::util::fs::link_or_copy;
1817
use std::path::PathBuf;
1918
use std::fs as std_fs;
2019

2120
pub fn save_trans_partition(sess: &Session,
2221
dep_graph: &DepGraph,
2322
cgu_name: &str,
24-
files: &[(OutputType, PathBuf)]) {
23+
files: &[(WorkProductFileKind, PathBuf)]) {
2524
debug!("save_trans_partition({:?},{:?})",
2625
cgu_name,
2726
files);
2827
if sess.opts.incremental.is_none() {
29-
return;
28+
return
3029
}
3130
let work_product_id = WorkProductId::from_cgu_name(cgu_name);
3231

3332
let saved_files: Option<Vec<_>> =
3433
files.iter()
3534
.map(|&(kind, ref path)| {
36-
let file_name = format!("cgu-{}.{}", cgu_name, kind.extension());
35+
let extension = match kind {
36+
WorkProductFileKind::Object => "o",
37+
WorkProductFileKind::Bytecode => "bc",
38+
WorkProductFileKind::BytecodeCompressed => "bc-compressed",
39+
};
40+
let file_name = format!("cgu-{}.{}", cgu_name, extension);
3741
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
3842
match link_or_copy(path, &path_in_incr_dir) {
3943
Ok(_) => Some((kind, file_name)),

src/librustc_trans/back/link.rs

+45-93
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use super::archive::{ArchiveBuilder, ArchiveConfig};
12-
use super::bytecode::{self, RLIB_BYTECODE_EXTENSION};
12+
use super::bytecode::RLIB_BYTECODE_EXTENSION;
1313
use super::linker::Linker;
1414
use super::command::Command;
1515
use super::rpath::RPathConfig;
@@ -37,7 +37,7 @@ use std::env;
3737
use std::ffi::OsString;
3838
use std::fmt;
3939
use std::fs::{self, File};
40-
use std::io::{self, Read, Write, BufWriter};
40+
use std::io::{self, Write, BufWriter};
4141
use std::path::{Path, PathBuf};
4242
use std::process::{Output, Stdio};
4343
use std::str;
@@ -126,14 +126,6 @@ fn command_path(sess: &Session) -> OsString {
126126
env::join_paths(new_path).unwrap()
127127
}
128128

129-
fn metadata_obj(outputs: &OutputFilenames) -> PathBuf {
130-
outputs.temp_path(OutputType::Object, Some(METADATA_MODULE_NAME))
131-
}
132-
133-
fn allocator_obj(outputs: &OutputFilenames) -> PathBuf {
134-
outputs.temp_path(OutputType::Object, Some(ALLOCATOR_MODULE_NAME))
135-
}
136-
137129
pub fn remove(sess: &Session, path: &Path) {
138130
match fs::remove_file(path) {
139131
Ok(..) => {}
@@ -175,13 +167,23 @@ pub fn link_binary(sess: &Session,
175167
// Remove the temporary object file and metadata if we aren't saving temps
176168
if !sess.opts.cg.save_temps {
177169
if sess.opts.output_types.should_trans() {
178-
for obj in trans.modules.iter() {
179-
remove(sess, &obj.object);
170+
for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
171+
remove(sess, obj);
180172
}
181173
}
182-
remove(sess, &metadata_obj(outputs));
183-
if trans.allocator_module.is_some() {
184-
remove(sess, &allocator_obj(outputs));
174+
for obj in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
175+
remove(sess, obj);
176+
}
177+
if let Some(ref obj) = trans.metadata_module.object {
178+
remove(sess, obj);
179+
}
180+
if let Some(ref allocator) = trans.allocator_module {
181+
if let Some(ref obj) = allocator.object {
182+
remove(sess, obj);
183+
}
184+
if let Some(ref bc) = allocator.bytecode_compressed {
185+
remove(sess, bc);
186+
}
185187
}
186188
}
187189

@@ -256,8 +258,8 @@ fn link_binary_output(sess: &Session,
256258
crate_type: config::CrateType,
257259
outputs: &OutputFilenames,
258260
crate_name: &str) -> Vec<PathBuf> {
259-
for module in trans.modules.iter() {
260-
check_file_is_writeable(&module.object, sess);
261+
for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
262+
check_file_is_writeable(obj, sess);
261263
}
262264

263265
let tmpdir = match TempDir::new("rustc") {
@@ -280,20 +282,14 @@ fn link_binary_output(sess: &Session,
280282
link_rlib(sess,
281283
trans,
282284
RlibFlavor::Normal,
283-
outputs,
284285
&out_filename,
285286
tmpdir.path()).build();
286287
}
287288
config::CrateTypeStaticlib => {
288-
link_staticlib(sess,
289-
trans,
290-
outputs,
291-
&out_filename,
292-
tmpdir.path());
289+
link_staticlib(sess, trans, &out_filename, tmpdir.path());
293290
}
294291
_ => {
295-
link_natively(sess, crate_type, &out_filename,
296-
trans, outputs, tmpdir.path());
292+
link_natively(sess, crate_type, &out_filename, trans, tmpdir.path());
297293
}
298294
}
299295
out_filenames.push(out_filename);
@@ -349,14 +345,13 @@ enum RlibFlavor {
349345
fn link_rlib<'a>(sess: &'a Session,
350346
trans: &CrateTranslation,
351347
flavor: RlibFlavor,
352-
outputs: &OutputFilenames,
353348
out_filename: &Path,
354349
tmpdir: &Path) -> ArchiveBuilder<'a> {
355350
info!("preparing rlib to {:?}", out_filename);
356351
let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None));
357352

358-
for module in trans.modules.iter() {
359-
ab.add_file(&module.object);
353+
for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
354+
ab.add_file(obj);
360355
}
361356

362357
// Note that in this loop we are ignoring the value of `lib.cfg`. That is,
@@ -421,56 +416,9 @@ fn link_rlib<'a>(sess: &'a Session,
421416
ab.add_file(&metadata);
422417

423418
// For LTO purposes, the bytecode of this library is also inserted
424-
// into the archive. If codegen_units > 1, we insert each of the
425-
// bitcode files.
426-
for module in trans.modules.iter() {
427-
// Note that we make sure that the bytecode filename in the
428-
// archive is never exactly 16 bytes long by adding a 16 byte
429-
// extension to it. This is to work around a bug in LLDB that
430-
// would cause it to crash if the name of a file in an archive
431-
// was exactly 16 bytes.
432-
let bc_filename = module.object.with_extension("bc");
433-
let bc_encoded_filename = tmpdir.join({
434-
module.object.with_extension(RLIB_BYTECODE_EXTENSION).file_name().unwrap()
435-
});
436-
437-
let mut bc_data = Vec::new();
438-
match fs::File::open(&bc_filename).and_then(|mut f| {
439-
f.read_to_end(&mut bc_data)
440-
}) {
441-
Ok(..) => {}
442-
Err(e) => sess.fatal(&format!("failed to read bytecode: {}",
443-
e))
444-
}
445-
446-
let encoded = bytecode::encode(&module.llmod_id, &bc_data);
447-
448-
let mut bc_file_deflated = match fs::File::create(&bc_encoded_filename) {
449-
Ok(file) => file,
450-
Err(e) => {
451-
sess.fatal(&format!("failed to create compressed \
452-
bytecode file: {}", e))
453-
}
454-
};
455-
456-
match bc_file_deflated.write_all(&encoded) {
457-
Ok(()) => {}
458-
Err(e) => {
459-
sess.fatal(&format!("failed to write compressed \
460-
bytecode: {}", e));
461-
}
462-
};
463-
464-
ab.add_file(&bc_encoded_filename);
465-
466-
// See the bottom of back::write::run_passes for an explanation
467-
// of when we do and don't keep .#module-name#.bc files around.
468-
let user_wants_numbered_bitcode =
469-
sess.opts.output_types.contains_key(&OutputType::Bitcode) &&
470-
sess.codegen_units() > 1;
471-
if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
472-
remove(sess, &bc_filename);
473-
}
419+
// into the archive.
420+
for bytecode in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
421+
ab.add_file(bytecode);
474422
}
475423

476424
// After adding all files to the archive, we need to update the
@@ -482,8 +430,11 @@ fn link_rlib<'a>(sess: &'a Session,
482430
}
483431

484432
RlibFlavor::StaticlibBase => {
485-
if trans.allocator_module.is_some() {
486-
ab.add_file(&allocator_obj(outputs));
433+
let obj = trans.allocator_module
434+
.as_ref()
435+
.and_then(|m| m.object.as_ref());
436+
if let Some(obj) = obj {
437+
ab.add_file(obj);
487438
}
488439
}
489440
}
@@ -505,13 +456,11 @@ fn link_rlib<'a>(sess: &'a Session,
505456
// metadata file).
506457
fn link_staticlib(sess: &Session,
507458
trans: &CrateTranslation,
508-
outputs: &OutputFilenames,
509459
out_filename: &Path,
510460
tempdir: &Path) {
511461
let mut ab = link_rlib(sess,
512462
trans,
513463
RlibFlavor::StaticlibBase,
514-
outputs,
515464
out_filename,
516465
tempdir);
517466
let mut all_native_libs = vec![];
@@ -616,7 +565,6 @@ fn link_natively(sess: &Session,
616565
crate_type: config::CrateType,
617566
out_filename: &Path,
618567
trans: &CrateTranslation,
619-
outputs: &OutputFilenames,
620568
tmpdir: &Path) {
621569
info!("preparing {:?} to {:?}", crate_type, out_filename);
622570
let flavor = sess.linker_flavor();
@@ -656,7 +604,7 @@ fn link_natively(sess: &Session,
656604
{
657605
let mut linker = trans.linker_info.to_linker(cmd, &sess);
658606
link_args(&mut *linker, sess, crate_type, tmpdir,
659-
out_filename, outputs, trans);
607+
out_filename, trans);
660608
cmd = linker.finalize();
661609
}
662610
if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
@@ -878,7 +826,6 @@ fn link_args(cmd: &mut Linker,
878826
crate_type: config::CrateType,
879827
tmpdir: &Path,
880828
out_filename: &Path,
881-
outputs: &OutputFilenames,
882829
trans: &CrateTranslation) {
883830

884831
// The default library location, we need this to find the runtime.
@@ -889,8 +836,8 @@ fn link_args(cmd: &mut Linker,
889836
let t = &sess.target.target;
890837

891838
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
892-
for module in trans.modules.iter() {
893-
cmd.add_object(&module.object);
839+
for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
840+
cmd.add_object(obj);
894841
}
895842
cmd.output_filename(out_filename);
896843

@@ -913,11 +860,16 @@ fn link_args(cmd: &mut Linker,
913860
// object file, so we link that in here.
914861
if crate_type == config::CrateTypeDylib ||
915862
crate_type == config::CrateTypeProcMacro {
916-
cmd.add_object(&metadata_obj(outputs));
863+
if let Some(obj) = trans.metadata_module.object.as_ref() {
864+
cmd.add_object(obj);
865+
}
917866
}
918867

919-
if trans.allocator_module.is_some() {
920-
cmd.add_object(&allocator_obj(outputs));
868+
let obj = trans.allocator_module
869+
.as_ref()
870+
.and_then(|m| m.object.as_ref());
871+
if let Some(obj) = obj {
872+
cmd.add_object(obj);
921873
}
922874

923875
// Try to strip as much out of the generated object by removing unused
@@ -1185,9 +1137,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
11851137

11861138
for f in archive.src_files() {
11871139
if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
1188-
archive.remove_file(&f);
1189-
continue
1190-
}
1140+
archive.remove_file(&f);
1141+
continue
1142+
}
11911143
}
11921144

11931145
archive.build();

src/librustc_trans/back/lto.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,7 @@ fn thin_lto(diag_handler: &Handler,
343343
info!("local module: {} - {}", i, module.llmod_id);
344344
let llvm = module.llvm().expect("can't lto pretranslated module");
345345
let name = CString::new(module.llmod_id.clone()).unwrap();
346-
let buffer = llvm::LLVMRustThinLTOBufferCreate(llvm.llmod);
347-
let buffer = ThinBuffer(buffer);
346+
let buffer = ThinBuffer::new(llvm.llmod);
348347
thin_modules.push(llvm::ThinLTOModule {
349348
identifier: name.as_ptr(),
350349
data: buffer.data().as_ptr(),
@@ -499,13 +498,13 @@ unsafe impl Send for ModuleBuffer {}
499498
unsafe impl Sync for ModuleBuffer {}
500499

501500
impl ModuleBuffer {
502-
fn new(m: ModuleRef) -> ModuleBuffer {
501+
pub fn new(m: ModuleRef) -> ModuleBuffer {
503502
ModuleBuffer(unsafe {
504503
llvm::LLVMRustModuleBufferCreate(m)
505504
})
506505
}
507506

508-
fn data(&self) -> &[u8] {
507+
pub fn data(&self) -> &[u8] {
509508
unsafe {
510509
let ptr = llvm::LLVMRustModuleBufferPtr(self.0);
511510
let len = llvm::LLVMRustModuleBufferLen(self.0);
@@ -545,13 +544,20 @@ impl Drop for ThinData {
545544
}
546545
}
547546

548-
struct ThinBuffer(*mut llvm::ThinLTOBuffer);
547+
pub struct ThinBuffer(*mut llvm::ThinLTOBuffer);
549548

550549
unsafe impl Send for ThinBuffer {}
551550
unsafe impl Sync for ThinBuffer {}
552551

553552
impl ThinBuffer {
554-
fn data(&self) -> &[u8] {
553+
pub fn new(m: ModuleRef) -> ThinBuffer {
554+
unsafe {
555+
let buffer = llvm::LLVMRustThinLTOBufferCreate(m);
556+
ThinBuffer(buffer)
557+
}
558+
}
559+
560+
pub fn data(&self) -> &[u8] {
555561
unsafe {
556562
let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
557563
let len = llvm::LLVMRustThinLTOBufferLen(self.0);

0 commit comments

Comments
 (0)