Skip to content

Commit a6db623

Browse files
Add some infrastructure for timing things where time_passes can't be used.
1 parent 86dde9b commit a6db623

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
@@ -909,6 +909,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
909909
"dump MIR state at various points in translation"),
910910
dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
911911
"the directory the MIR is dumped into"),
912+
perf_stats: bool = (false, parse_bool, [UNTRACKED],
913+
"print some performance-related statistics"),
912914
}
913915

914916
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};
@@ -42,6 +43,7 @@ use std::env;
4243
use std::ffi::CString;
4344
use std::rc::Rc;
4445
use std::fmt;
46+
use std::time::Duration;
4547
use libc::c_int;
4648

4749
pub mod config;
@@ -101,9 +103,23 @@ pub struct Session {
101103
/// macro name and defintion span in the source crate.
102104
pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>,
103105

106+
/// Some measurements that are being gathered during compilation.
107+
pub perf_stats: PerfStats,
108+
104109
next_node_id: Cell<ast::NodeId>,
105110
}
106111

112+
pub struct PerfStats {
113+
// The accumulated time needed for computing the SVH of the crate
114+
pub svh_time: Cell<Duration>,
115+
// The accumulated time spent on computing incr. comp. hashes
116+
pub incr_comp_hashes_time: Cell<Duration>,
117+
// The number of incr. comp. hash computations performed
118+
pub incr_comp_hashes_count: Cell<u64>,
119+
// The accumulated time spent on computing symbol hashes
120+
pub symbol_hash_time: Cell<Duration>,
121+
}
122+
107123
impl Session {
108124
pub fn local_crate_disambiguator(&self) -> token::InternedString {
109125
self.crate_disambiguator.borrow().clone()
@@ -331,6 +347,17 @@ impl Session {
331347
&self.opts.search_paths,
332348
kind)
333349
}
350+
351+
pub fn print_perf_stats(&self) {
352+
println!("Total time spent computing SVHs: {}",
353+
duration_to_secs_str(self.perf_stats.svh_time.get()));
354+
println!("Total time spent computing incr. comp. hashes: {}",
355+
duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
356+
println!("Total number of incr. comp. hashes computed: {}",
357+
self.perf_stats.incr_comp_hashes_count.get());
358+
println!("Total time spent computing symbol hashes: {}",
359+
duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
360+
}
334361
}
335362

336363
pub fn build_session(sopts: config::Options,
@@ -446,6 +473,12 @@ pub fn build_session_(sopts: config::Options,
446473
injected_panic_runtime: Cell::new(None),
447474
available_macros: RefCell::new(HashSet::new()),
448475
imported_macro_spans: RefCell::new(HashMap::new()),
476+
perf_stats: PerfStats {
477+
svh_time: Cell::new(Duration::from_secs(0)),
478+
incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
479+
incr_comp_hashes_count: Cell::new(0),
480+
symbol_hash_time: Cell::new(Duration::from_secs(0)),
481+
}
449482
};
450483

451484
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
@@ -229,6 +229,10 @@ pub fn compile_input(sess: &Session,
229229

230230
phase_6_link_output(sess, &trans, &outputs);
231231

232+
if sess.opts.debugging_opts.perf_stats {
233+
sess.print_perf_stats();
234+
}
235+
232236
controller_entry_point!(compilation_done,
233237
sess,
234238
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)