Skip to content

Commit 923bac4

Browse files
authored
Auto merge of #36025 - michaelwoerister:incr-comp-hash-spans, r=nikomatsakis
incr. comp.: Take spans into account for ICH This PR makes the ICH (incr. comp. hash) take spans into account when debuginfo is enabled. A side-effect of this is that the SVH (which is based on the ICHs of all items in the crate) becomes sensitive to the tiniest change in a code base if debuginfo is enabled. Since we are not trying to model ABI compatibility via the SVH anymore (this is done via the crate disambiguator now), this should be not be a problem. Fixes #33888. Fixes #32753.
2 parents 13c4e32 + 3057b7b commit 923bac4

File tree

19 files changed

+843
-145
lines changed

19 files changed

+843
-145
lines changed

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
913913
"dump MIR state at various points in translation"),
914914
dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
915915
"the directory the MIR is dumped into"),
916+
perf_stats: bool = (false, parse_bool, [UNTRACKED],
917+
"print some performance-related statistics"),
916918
}
917919

918920
pub fn default_lib_output() -> CrateType {

src/librustc/session/mod.rs

+33
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use session::search_paths::PathKind;
1818
use session::config::{DebugInfoLevel, PanicStrategy};
1919
use ty::tls;
2020
use util::nodemap::{NodeMap, FnvHashMap};
21+
use util::common::duration_to_secs_str;
2122
use mir::transform as mir_pass;
2223

2324
use syntax::ast::{NodeId, Name};
@@ -43,6 +44,7 @@ use std::env;
4344
use std::ffi::CString;
4445
use std::rc::Rc;
4546
use std::fmt;
47+
use std::time::Duration;
4648
use libc::c_int;
4749

4850
pub mod config;
@@ -105,9 +107,23 @@ pub struct Session {
105107

106108
incr_comp_session: RefCell<IncrCompSession>,
107109

110+
/// Some measurements that are being gathered during compilation.
111+
pub perf_stats: PerfStats,
112+
108113
next_node_id: Cell<ast::NodeId>,
109114
}
110115

116+
pub struct PerfStats {
117+
// The accumulated time needed for computing the SVH of the crate
118+
pub svh_time: Cell<Duration>,
119+
// The accumulated time spent on computing incr. comp. hashes
120+
pub incr_comp_hashes_time: Cell<Duration>,
121+
// The number of incr. comp. hash computations performed
122+
pub incr_comp_hashes_count: Cell<u64>,
123+
// The accumulated time spent on computing symbol hashes
124+
pub symbol_hash_time: Cell<Duration>,
125+
}
126+
111127
impl Session {
112128
pub fn local_crate_disambiguator(&self) -> token::InternedString {
113129
self.crate_disambiguator.borrow().clone()
@@ -411,6 +427,17 @@ impl Session {
411427
None
412428
}
413429
}
430+
431+
pub fn print_perf_stats(&self) {
432+
println!("Total time spent computing SVHs: {}",
433+
duration_to_secs_str(self.perf_stats.svh_time.get()));
434+
println!("Total time spent computing incr. comp. hashes: {}",
435+
duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
436+
println!("Total number of incr. comp. hashes computed: {}",
437+
self.perf_stats.incr_comp_hashes_count.get());
438+
println!("Total time spent computing symbol hashes: {}",
439+
duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
440+
}
414441
}
415442

416443
pub fn build_session(sopts: config::Options,
@@ -528,6 +555,12 @@ pub fn build_session_(sopts: config::Options,
528555
available_macros: RefCell::new(HashSet::new()),
529556
imported_macro_spans: RefCell::new(HashMap::new()),
530557
incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
558+
perf_stats: PerfStats {
559+
svh_time: Cell::new(Duration::from_secs(0)),
560+
incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
561+
incr_comp_hashes_count: Cell::new(0),
562+
symbol_hash_time: Cell::new(Duration::from_secs(0)),
563+
}
531564
};
532565

533566
init_llvm(&sess);

src/librustc/util/common.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::fmt::Debug;
1717
use std::hash::{Hash, BuildHasher};
1818
use std::iter::repeat;
1919
use std::path::Path;
20-
use std::time::Instant;
20+
use std::time::{Duration, Instant};
2121

2222
use hir;
2323
use hir::intravisit;
@@ -47,27 +47,44 @@ pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where
4747
let rv = f();
4848
let dur = start.elapsed();
4949

50-
// Hack up our own formatting for the duration to make it easier for scripts
51-
// to parse (always use the same number of decimal places and the same unit).
52-
const NANOS_PER_SEC: f64 = 1_000_000_000.0;
53-
let secs = dur.as_secs() as f64;
54-
let secs = secs + dur.subsec_nanos() as f64 / NANOS_PER_SEC;
55-
5650
let mem_string = match get_resident() {
5751
Some(n) => {
5852
let mb = n as f64 / 1_000_000.0;
5953
format!("; rss: {}MB", mb.round() as usize)
6054
}
6155
None => "".to_owned(),
6256
};
63-
println!("{}time: {:.3}{}\t{}", repeat(" ").take(old).collect::<String>(),
64-
secs, mem_string, what);
57+
println!("{}time: {}{}\t{}",
58+
repeat(" ").take(old).collect::<String>(),
59+
duration_to_secs_str(dur),
60+
mem_string,
61+
what);
6562

6663
DEPTH.with(|slot| slot.set(old));
6764

6865
rv
6966
}
7067

68+
// Hack up our own formatting for the duration to make it easier for scripts
69+
// to parse (always use the same number of decimal places and the same unit).
70+
pub fn duration_to_secs_str(dur: Duration) -> String {
71+
const NANOS_PER_SEC: f64 = 1_000_000_000.0;
72+
let secs = dur.as_secs() as f64 +
73+
dur.subsec_nanos() as f64 / NANOS_PER_SEC;
74+
75+
format!("{:.3}", secs)
76+
}
77+
78+
pub fn record_time<T, F>(accu: &Cell<Duration>, f: F) -> T where
79+
F: FnOnce() -> T,
80+
{
81+
let start = Instant::now();
82+
let rv = f();
83+
let duration = start.elapsed();
84+
accu.set(duration + accu.get());
85+
rv
86+
}
87+
7188
// Like std::macros::try!, but for Option<>.
7289
macro_rules! option_try(
7390
($e:expr) => (match $e { Some(e) => e, None => return None })

src/librustc_data_structures/fnv.rs

+6
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,9 @@ impl Hasher for FnvHasher {
5757
self.0
5858
}
5959
}
60+
61+
pub fn hash<T: Hash>(v: &T) -> u64 {
62+
let mut state = FnvHasher::default();
63+
v.hash(&mut state);
64+
state.finish()
65+
}

src/librustc_driver/driver.rs

+4
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ pub fn compile_input(sess: &Session,
235235
// any more, we can finalize it (which involves renaming it)
236236
rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
237237

238+
if sess.opts.debugging_opts.perf_stats {
239+
sess.print_perf_stats();
240+
}
241+
238242
controller_entry_point!(compilation_done,
239243
sess,
240244
CompileState::state_when_compilation_done(input, sess, outdir, output),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright 2016 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+
use rustc::ty::TyCtxt;
12+
use std::rc::Rc;
13+
use syntax::codemap::CodeMap;
14+
use syntax_pos::{BytePos, FileMap};
15+
16+
#[derive(Clone)]
17+
struct CacheEntry {
18+
time_stamp: usize,
19+
line_number: usize,
20+
line_start: BytePos,
21+
line_end: BytePos,
22+
file: Rc<FileMap>,
23+
}
24+
25+
pub struct CachingCodemapView<'tcx> {
26+
codemap: &'tcx CodeMap,
27+
line_cache: [CacheEntry; 3],
28+
time_stamp: usize,
29+
}
30+
31+
impl<'tcx> CachingCodemapView<'tcx> {
32+
pub fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> {
33+
let codemap = tcx.sess.codemap();
34+
let first_file = codemap.files.borrow()[0].clone();
35+
let entry = CacheEntry {
36+
time_stamp: 0,
37+
line_number: 0,
38+
line_start: BytePos(0),
39+
line_end: BytePos(0),
40+
file: first_file,
41+
};
42+
43+
CachingCodemapView {
44+
codemap: codemap,
45+
line_cache: [entry.clone(), entry.clone(), entry.clone()],
46+
time_stamp: 0,
47+
}
48+
}
49+
50+
pub fn codemap(&self) -> &'tcx CodeMap {
51+
self.codemap
52+
}
53+
54+
pub fn byte_pos_to_line_and_col(&mut self,
55+
pos: BytePos)
56+
-> Option<(Rc<FileMap>, usize, BytePos)> {
57+
self.time_stamp += 1;
58+
59+
// Check if the position is in one of the cached lines
60+
for cache_entry in self.line_cache.iter_mut() {
61+
if pos >= cache_entry.line_start && pos < cache_entry.line_end {
62+
cache_entry.time_stamp = self.time_stamp;
63+
return Some((cache_entry.file.clone(),
64+
cache_entry.line_number,
65+
pos - cache_entry.line_start));
66+
}
67+
}
68+
69+
// No cache hit ...
70+
let mut oldest = 0;
71+
for index in 1 .. self.line_cache.len() {
72+
if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp {
73+
oldest = index;
74+
}
75+
}
76+
77+
let cache_entry = &mut self.line_cache[oldest];
78+
79+
// If the entry doesn't point to the correct file, fix it up
80+
if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos {
81+
let file_valid;
82+
let files = self.codemap.files.borrow();
83+
84+
if files.len() > 0 {
85+
let file_index = self.codemap.lookup_filemap_idx(pos);
86+
let file = files[file_index].clone();
87+
88+
if pos >= file.start_pos && pos < file.end_pos {
89+
cache_entry.file = file;
90+
file_valid = true;
91+
} else {
92+
file_valid = false;
93+
}
94+
} else {
95+
file_valid = false;
96+
}
97+
98+
if !file_valid {
99+
return None;
100+
}
101+
}
102+
103+
let line_index = cache_entry.file.lookup_line(pos).unwrap();
104+
let line_bounds = cache_entry.file.line_bounds(line_index);
105+
106+
cache_entry.line_number = line_index + 1;
107+
cache_entry.line_start = line_bounds.0;
108+
cache_entry.line_end = line_bounds.1;
109+
cache_entry.time_stamp = self.time_stamp;
110+
111+
return Some((cache_entry.file.clone(),
112+
cache_entry.line_number,
113+
pos - cache_entry.line_start));
114+
}
115+
}

src/librustc_incremental/calculate_svh/mod.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,46 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
3535
use rustc::hir::intravisit as visit;
3636
use rustc::ty::TyCtxt;
3737
use rustc_data_structures::fnv::FnvHashMap;
38+
use rustc::util::common::record_time;
39+
use rustc::session::config::DebugInfoLevel::NoDebugInfo;
3840

3941
use self::def_path_hash::DefPathHashes;
4042
use self::svh_visitor::StrictVersionHashVisitor;
43+
use self::caching_codemap_view::CachingCodemapView;
4144

4245
mod def_path_hash;
4346
mod svh_visitor;
47+
mod caching_codemap_view;
4448

4549
pub type IncrementalHashesMap = FnvHashMap<DepNode<DefId>, u64>;
4650

4751
pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
4852
-> IncrementalHashesMap {
4953
let _ignore = tcx.dep_graph.in_ignore();
5054
let krate = tcx.map.krate();
51-
let mut visitor = HashItemsVisitor { tcx: tcx,
52-
hashes: FnvHashMap(),
53-
def_path_hashes: DefPathHashes::new(tcx) };
54-
visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate));
55-
krate.visit_all_items(&mut visitor);
56-
visitor.compute_crate_hash();
55+
let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo;
56+
let mut visitor = HashItemsVisitor {
57+
tcx: tcx,
58+
hashes: FnvHashMap(),
59+
def_path_hashes: DefPathHashes::new(tcx),
60+
codemap: CachingCodemapView::new(tcx),
61+
hash_spans: hash_spans,
62+
};
63+
record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
64+
visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX),
65+
|v| visit::walk_crate(v, krate));
66+
krate.visit_all_items(&mut visitor);
67+
});
68+
record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
5769
visitor.hashes
5870
}
5971

6072
struct HashItemsVisitor<'a, 'tcx: 'a> {
6173
tcx: TyCtxt<'a, 'tcx, 'tcx>,
6274
def_path_hashes: DefPathHashes<'a, 'tcx>,
75+
codemap: CachingCodemapView<'tcx>,
6376
hashes: IncrementalHashesMap,
77+
hash_spans: bool,
6478
}
6579

6680
impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
@@ -81,7 +95,9 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
8195
let mut state = SipHasher::new();
8296
walk_op(&mut StrictVersionHashVisitor::new(&mut state,
8397
self.tcx,
84-
&mut self.def_path_hashes));
98+
&mut self.def_path_hashes,
99+
&mut self.codemap,
100+
self.hash_spans));
85101
let item_hash = state.finish();
86102
self.hashes.insert(DepNode::Hir(def_id), item_hash);
87103
debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
@@ -117,9 +133,13 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
117133
item_hashes.hash(&mut crate_state);
118134
}
119135

120-
for attr in &krate.attrs {
121-
debug!("krate attr {:?}", attr);
122-
attr.meta().hash(&mut crate_state);
136+
{
137+
let mut visitor = StrictVersionHashVisitor::new(&mut crate_state,
138+
self.tcx,
139+
&mut self.def_path_hashes,
140+
&mut self.codemap,
141+
self.hash_spans);
142+
visitor.hash_attributes(&krate.attrs);
123143
}
124144

125145
let crate_hash = crate_state.finish();

0 commit comments

Comments
 (0)