Skip to content

Commit 1e3c45a

Browse files
committed
Auto merge of #51657 - wesleywiser:wip_profiling, r=eddyb
Implement a self profiler This is a work in progress implementation of #50780. I'd love feedback on the overall structure and code as well as some specific things: - [The query categorization mechanism](https://github.com/rust-lang/rust/compare/master...wesleywiser:wip_profiling?expand=1#diff-19e0a69c10eff31eb2d16805e79f3437R101). This works but looks kind of ugly to me. Perhaps there's a better way? - [The profiler assumes only one activity can run at a time](https://github.com/rust-lang/rust/compare/master...wesleywiser:wip_profiling?expand=1#diff-f8a403b2d88d873e4b27c097c614a236R177). This is obviously incompatible with the ongoing parallel queries. - [The output code is just a bunch of `format!()`s](https://github.com/rust-lang/rust/compare/master...wesleywiser:wip_profiling?expand=1#diff-f8a403b2d88d873e4b27c097c614a236R91). Is there a better way to generate markdown or json in the compiler? - [The query categorizations are likely wrong](https://github.com/rust-lang/rust/compare/master...wesleywiser:wip_profiling?expand=1#diff-19e0a69c10eff31eb2d16805e79f3437R101). I've marked what seemed obvious to me but I'm sure I got a lot of them wrong. The overhead currently seems very low. Running `perf` on a sample compilation with profiling enabled reveals: ![image](https://user-images.githubusercontent.com/831192/41657821-9775efec-7462-11e8-9e5e-47ec94105d9d.png)
2 parents 40e4b6e + 2d3a0a9 commit 1e3c45a

File tree

11 files changed

+332
-1
lines changed

11 files changed

+332
-1
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ pub mod util {
165165
pub mod nodemap;
166166
pub mod fs;
167167
pub mod time_graph;
168+
pub mod profiling;
168169
}
169170

170171
// A private module so that macro-expanded idents like

src/librustc/session/config.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub enum Sanitizer {
6565
Thread,
6666
}
6767

68-
#[derive(Clone, Copy, PartialEq, Hash)]
68+
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
6969
pub enum OptLevel {
7070
No, // -O0
7171
Less, // -O1
@@ -1367,6 +1367,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
13671367
"disables the 'leak check' for subtyping; unsound, but useful for tests"),
13681368
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
13691369
"inject the given attribute in the crate"),
1370+
self_profile: bool = (false, parse_bool, [UNTRACKED],
1371+
"run the self profiler"),
1372+
profile_json: bool = (false, parse_bool, [UNTRACKED],
1373+
"output a json file with profiler results"),
13701374
}
13711375

13721376
pub fn default_lib_output() -> CrateType {

src/librustc/session/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use syntax::parse::ParseSess;
4040
use syntax::{ast, codemap};
4141
use syntax::feature_gate::AttributeType;
4242
use syntax_pos::{MultiSpan, Span};
43+
use util::profiling::SelfProfiler;
4344

4445
use rustc_target::spec::{LinkerFlavor, PanicStrategy};
4546
use rustc_target::spec::{Target, TargetTriple};
@@ -133,6 +134,9 @@ pub struct Session {
133134
/// Used by -Z profile-queries in util::common
134135
pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>,
135136

137+
/// Used by -Z self-profile
138+
pub self_profiling: Lock<SelfProfiler>,
139+
136140
/// Some measurements that are being gathered during compilation.
137141
pub perf_stats: PerfStats,
138142

@@ -825,6 +829,21 @@ impl Session {
825829
}
826830
}
827831

832+
pub fn profiler<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) {
833+
let mut profiler = self.self_profiling.borrow_mut();
834+
f(&mut profiler);
835+
}
836+
837+
pub fn print_profiler_results(&self) {
838+
let mut profiler = self.self_profiling.borrow_mut();
839+
profiler.print_results(&self.opts);
840+
}
841+
842+
pub fn save_json_results(&self) {
843+
let profiler = self.self_profiling.borrow();
844+
profiler.save_results(&self.opts);
845+
}
846+
828847
pub fn print_perf_stats(&self) {
829848
println!(
830849
"Total time spent computing symbol hashes: {}",
@@ -1125,6 +1144,7 @@ pub fn build_session_(
11251144
imported_macro_spans: OneThread::new(RefCell::new(HashMap::new())),
11261145
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
11271146
ignored_attr_names: ich::compute_ignored_attr_names(),
1147+
self_profiling: Lock::new(SelfProfiler::new()),
11281148
profile_channel: Lock::new(None),
11291149
perf_stats: PerfStats {
11301150
symbol_hash_time: Lock::new(Duration::from_secs(0)),

src/librustc/ty/query/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use ty::subst::Substs;
2121
use ty::query::queries;
2222
use ty::query::Query;
2323
use ty::query::QueryCache;
24+
use util::profiling::ProfileCategory;
2425

2526
use std::hash::Hash;
2627
use std::fmt::Debug;
@@ -33,6 +34,7 @@ use ich::StableHashingContext;
3334

3435
pub trait QueryConfig<'tcx> {
3536
const NAME: &'static str;
37+
const CATEGORY: ProfileCategory;
3638

3739
type Key: Eq + Hash + Clone + Debug;
3840
type Value: Clone + for<'a> HashStable<StableHashingContext<'a>>;

src/librustc/ty/query/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use ty::steal::Steal;
4646
use ty::subst::Substs;
4747
use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
4848
use util::common::{ErrorReported};
49+
use util::profiling::ProfileCategory::*;
4950

5051
use rustc_data_structures::indexed_set::IdxSetBuf;
5152
use rustc_target::spec::PanicStrategy;

src/librustc/ty/query/plumbing.rs

+29
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
118118
let mut lock = cache.borrow_mut();
119119
if let Some(value) = lock.results.get(key) {
120120
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
121+
tcx.sess.profiler(|p| {
122+
p.record_query(Q::CATEGORY);
123+
p.record_query_hit(Q::CATEGORY);
124+
});
125+
121126
let result = Ok((value.value.clone(), value.index));
122127
return TryGetJob::JobCompleted(result);
123128
}
@@ -358,10 +363,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
358363
)
359364
);
360365

366+
self.sess.profiler(|p| p.record_query(Q::CATEGORY));
367+
361368
let job = match JobOwner::try_get(self, span, &key) {
362369
TryGetJob::NotYetStarted(job) => job,
363370
TryGetJob::JobCompleted(result) => {
364371
return result.map(|(v, index)| {
372+
self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY));
365373
self.dep_graph.read_index(index);
366374
v
367375
})
@@ -379,13 +387,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
379387

380388
if dep_node.kind.is_anon() {
381389
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
390+
self.sess.profiler(|p| p.start_activity(Q::CATEGORY));
382391

383392
let res = job.start(self, |tcx| {
384393
tcx.dep_graph.with_anon_task(dep_node.kind, || {
385394
Q::compute(tcx.global_tcx(), key)
386395
})
387396
});
388397

398+
self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
389399
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
390400
let ((result, dep_node_index), diagnostics) = res;
391401

@@ -402,6 +412,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
402412
if !dep_node.kind.is_input() {
403413
if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) {
404414
profq_msg!(self, ProfileQueriesMsg::CacheHit);
415+
self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY));
416+
405417
return self.load_from_disk_and_cache_in_memory::<Q>(key,
406418
job,
407419
dep_node_index,
@@ -523,6 +535,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
523535
key, dep_node);
524536

525537
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
538+
self.sess.profiler(|p| {
539+
p.start_activity(Q::CATEGORY);
540+
p.record_query(Q::CATEGORY);
541+
});
542+
526543
let res = job.start(self, |tcx| {
527544
if dep_node.kind.is_eval_always() {
528545
tcx.dep_graph.with_eval_always_task(dep_node,
@@ -536,6 +553,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
536553
Q::compute)
537554
}
538555
});
556+
557+
self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
539558
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
540559

541560
let ((result, dep_node_index), diagnostics) = res;
@@ -574,7 +593,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
574593
// DepNodeIndex. We must invoke the query itself. The performance cost
575594
// this introduces should be negligible as we'll immediately hit the
576595
// in-memory cache, or another query down the line will.
596+
597+
self.sess.profiler(|p| {
598+
p.start_activity(Q::CATEGORY);
599+
p.record_query(Q::CATEGORY);
600+
});
601+
577602
let _ = self.get_query::<Q>(DUMMY_SP, key);
603+
604+
self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
578605
}
579606
}
580607

@@ -655,6 +682,7 @@ macro_rules! define_queries_inner {
655682
rustc_data_structures::stable_hasher::StableHasher,
656683
ich::StableHashingContext
657684
};
685+
use util::profiling::ProfileCategory;
658686

659687
define_queries_struct! {
660688
tcx: $tcx,
@@ -768,6 +796,7 @@ macro_rules! define_queries_inner {
768796
type Value = $V;
769797

770798
const NAME: &'static str = stringify!($name);
799+
const CATEGORY: ProfileCategory = $category;
771800
}
772801

773802
impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> {

0 commit comments

Comments
 (0)