Skip to content

Commit dd65cb2

Browse files
Add some infrastructure for timing things where time_passes can't be used.
1 parent b2799a5 commit dd65cb2

File tree

5 files changed

+93
-34
lines changed

5 files changed

+93
-34
lines changed

src/librustc/session/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
908908
"dump MIR state at various points in translation"),
909909
dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
910910
"the directory the MIR is dumped into"),
911+
perf_stats: bool = (false, parse_bool, [UNTRACKED],
912+
"print some performance-related statistics"),
911913
}
912914

913915
pub fn default_lib_output() -> CrateType {

src/librustc/session/mod.rs

Lines changed: 33 additions & 0 deletions
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;
@@ -104,9 +106,23 @@ pub struct Session {
104106

105107
incr_comp_session: RefCell<IncrCompSession>,
106108

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

115+
pub struct PerfStats {
116+
// The accumulated time needed for computing the SVH of the crate
117+
pub svh_time: Cell<Duration>,
118+
// The accumulated time spent on computing incr. comp. hashes
119+
pub incr_comp_hashes_time: Cell<Duration>,
120+
// The number of incr. comp. hash computations performed
121+
pub incr_comp_hashes_count: Cell<u64>,
122+
// The accumulated time spent on computing symbol hashes
123+
pub symbol_hash_time: Cell<Duration>,
124+
}
125+
110126
impl Session {
111127
pub fn local_crate_disambiguator(&self) -> token::InternedString {
112128
self.crate_disambiguator.borrow().clone()
@@ -404,6 +420,17 @@ impl Session {
404420
None
405421
}
406422
}
423+
424+
pub fn print_perf_stats(&self) {
425+
println!("Total time spent computing SVHs: {}",
426+
duration_to_secs_str(self.perf_stats.svh_time.get()));
427+
println!("Total time spent computing incr. comp. hashes: {}",
428+
duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
429+
println!("Total number of incr. comp. hashes computed: {}",
430+
self.perf_stats.incr_comp_hashes_count.get());
431+
println!("Total time spent computing symbol hashes: {}",
432+
duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
433+
}
407434
}
408435

409436
pub fn build_session(sopts: config::Options,
@@ -520,6 +547,12 @@ pub fn build_session_(sopts: config::Options,
520547
available_macros: RefCell::new(HashSet::new()),
521548
imported_macro_spans: RefCell::new(HashMap::new()),
522549
incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
550+
perf_stats: PerfStats {
551+
svh_time: Cell::new(Duration::from_secs(0)),
552+
incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
553+
incr_comp_hashes_count: Cell::new(0),
554+
symbol_hash_time: Cell::new(Duration::from_secs(0)),
555+
}
523556
};
524557

525558
init_llvm(&sess);

src/librustc/util/common.rs

Lines changed: 26 additions & 9 deletions
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_driver/driver.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ pub fn compile_input(sess: &Session,
233233
// any more, we can finalize it (which involves renaming it)
234234
rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
235235

236+
if sess.opts.debugging_opts.perf_stats {
237+
sess.print_perf_stats();
238+
}
239+
236240
controller_entry_point!(compilation_done,
237241
sess,
238242
CompileState::state_when_compilation_done(input, sess, outdir, output),

src/librustc_trans/back/symbol_names.rs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ use rustc::ty::{Ty, TyCtxt, TypeFoldable};
108108
use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
109109
use rustc::ty::subst::Substs;
110110
use rustc::hir::map::definitions::{DefPath, DefPathData};
111+
use rustc::util::common::record_time;
111112

112113
use syntax::attr;
113114
use syntax::parse::token::{self, InternedString};
@@ -138,33 +139,35 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
138139

139140
let tcx = scx.tcx();
140141

141-
let mut hash_state = scx.symbol_hasher().borrow_mut();
142-
143-
hash_state.reset();
144-
145-
// the main symbol name is not necessarily unique; hash in the
146-
// compiler's internal def-path, guaranteeing each symbol has a
147-
// truly unique path
148-
hash_state.input_str(&def_path.to_string(tcx));
149-
150-
// Include the main item-type. Note that, in this case, the
151-
// assertions about `needs_subst` may not hold, but this item-type
152-
// ought to be the same for every reference anyway.
153-
assert!(!item_type.has_erasable_regions());
154-
let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string);
155-
hash_state.input(&encoded_item_type[..]);
156-
157-
// also include any type parameters (for generic items)
158-
if let Some(substs) = substs {
159-
for t in substs.types() {
160-
assert!(!t.has_erasable_regions());
161-
assert!(!t.needs_subst());
162-
let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
163-
hash_state.input(&encoded_type[..]);
142+
return record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
143+
let mut hash_state = scx.symbol_hasher().borrow_mut();
144+
145+
hash_state.reset();
146+
147+
// the main symbol name is not necessarily unique; hash in the
148+
// compiler's internal def-path, guaranteeing each symbol has a
149+
// truly unique path
150+
hash_state.input_str(&def_path.to_string(tcx));
151+
152+
// Include the main item-type. Note that, in this case, the
153+
// assertions about `needs_subst` may not hold, but this item-type
154+
// ought to be the same for every reference anyway.
155+
assert!(!item_type.has_erasable_regions());
156+
let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string);
157+
hash_state.input(&encoded_item_type[..]);
158+
159+
// also include any type parameters (for generic items)
160+
if let Some(substs) = substs {
161+
for t in substs.types() {
162+
assert!(!t.has_erasable_regions());
163+
assert!(!t.needs_subst());
164+
let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
165+
hash_state.input(&encoded_type[..]);
166+
}
164167
}
165-
}
166168

167-
return format!("h{}", truncated_hash_result(&mut *hash_state));
169+
format!("h{}", truncated_hash_result(&mut *hash_state))
170+
});
168171

169172
fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
170173
let output = symbol_hasher.result_bytes();

0 commit comments

Comments
 (0)