Skip to content

Commit 2c0558f

Browse files
committed
Auto merge of #43345 - matthewhammer:master, r=nikomatsakis
Profile queries This PR implements the "profile queries" debugging feature described here: https://github.com/rust-lang-nursery/rust-forge/blob/master/profile-queries.md In particular, it implements the debugging flag `-Z profile-queries` FYI: This PR is my second attempt at pushing these changes. My original PR required a rebase; I have now done that rebase manually, after messing up with git's "interactive" rebase support. The original (now closed/cancelled) PR is this one: #43156 r? @nikomatsakis
2 parents af6298d + 43335ae commit 2c0558f

File tree

9 files changed

+782
-0
lines changed

9 files changed

+782
-0
lines changed

src/librustc/dep_graph/graph.rs

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashMap;
1212
use session::config::OutputType;
1313
use std::cell::{Ref, RefCell};
1414
use std::rc::Rc;
15+
use util::common::{ProfileQueriesMsg, profq_msg};
1516

1617
use super::dep_node::{DepNode, DepKind, WorkProductId};
1718
use super::query::DepGraphQuery;
@@ -118,7 +119,13 @@ impl DepGraph {
118119
{
119120
if let Some(ref data) = self.data {
120121
data.edges.borrow_mut().push_task(key);
122+
if cfg!(debug_assertions) {
123+
profq_msg(ProfileQueriesMsg::TaskBegin(key.clone()))
124+
};
121125
let result = task(cx, arg);
126+
if cfg!(debug_assertions) {
127+
profq_msg(ProfileQueriesMsg::TaskEnd)
128+
};
122129
let dep_node_index = data.edges.borrow_mut().pop_task(key);
123130
(result, dep_node_index)
124131
} else {

src/librustc/session/config.rs

+4
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
995995
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
996996
query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
997997
"enable queries of the dependency graph for regression testing"),
998+
profile_queries: bool = (false, parse_bool, [UNTRACKED],
999+
"trace and profile the queries of the incremental compilation framework"),
1000+
profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
1001+
"trace and profile the queries and keys of the incremental compilation framework"),
9981002
no_analysis: bool = (false, parse_bool, [UNTRACKED],
9991003
"parse and expand the source, but run no analysis"),
10001004
extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],

src/librustc/session/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,13 @@ impl Session {
389389
}
390390
pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose }
391391
pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes }
392+
pub fn profile_queries(&self) -> bool {
393+
self.opts.debugging_opts.profile_queries ||
394+
self.opts.debugging_opts.profile_queries_and_keys
395+
}
396+
pub fn profile_queries_and_keys(&self) -> bool {
397+
self.opts.debugging_opts.profile_queries_and_keys
398+
}
392399
pub fn count_llvm_insns(&self) -> bool {
393400
self.opts.debugging_opts.count_llvm_insns
394401
}

src/librustc/ty/maps.rs

+41
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use ty::steal::Steal;
2828
use ty::subst::Substs;
2929
use ty::fast_reject::SimplifiedType;
3030
use util::nodemap::{DefIdSet, NodeSet};
31+
use util::common::{profq_msg, ProfileQueriesMsg};
3132

3233
use rustc_data_structures::indexed_vec::IndexVec;
3334
use rustc_data_structures::fx::FxHashMap;
@@ -513,6 +514,29 @@ impl<'tcx> QueryDescription for queries::lint_levels<'tcx> {
513514
}
514515
}
515516

517+
// If enabled, send a message to the profile-queries thread
518+
macro_rules! profq_msg {
519+
($tcx:expr, $msg:expr) => {
520+
if cfg!(debug_assertions) {
521+
if $tcx.sess.profile_queries() {
522+
profq_msg($msg)
523+
}
524+
}
525+
}
526+
}
527+
528+
// If enabled, format a key using its debug string, which can be
529+
// expensive to compute (in terms of time).
530+
macro_rules! profq_key {
531+
($tcx:expr, $key:expr) => {
532+
if cfg!(debug_assertions) {
533+
if $tcx.sess.profile_queries_and_keys() {
534+
Some(format!("{:?}", $key))
535+
} else { None }
536+
} else { None }
537+
}
538+
}
539+
516540
macro_rules! define_maps {
517541
(<$tcx:tt>
518542
$($(#[$attr:meta])*
@@ -539,6 +563,12 @@ macro_rules! define_maps {
539563
$($(#[$attr])* $name($K)),*
540564
}
541565

566+
#[allow(bad_style)]
567+
#[derive(Clone, Debug, PartialEq, Eq)]
568+
pub enum QueryMsg {
569+
$($name(Option<String>)),*
570+
}
571+
542572
impl<$tcx> Query<$tcx> {
543573
pub fn describe(&self, tcx: TyCtxt) -> String {
544574
match *self {
@@ -581,10 +611,20 @@ macro_rules! define_maps {
581611
key,
582612
span);
583613

614+
profq_msg!(tcx,
615+
ProfileQueriesMsg::QueryBegin(
616+
span.clone(),
617+
QueryMsg::$name(profq_key!(tcx, key))
618+
)
619+
);
620+
584621
if let Some(&(ref result, dep_node_index)) = tcx.maps.$name.borrow().map.get(&key) {
585622
tcx.dep_graph.read_index(dep_node_index);
623+
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
586624
return Ok(f(result));
587625
}
626+
// else, we are going to run the provider:
627+
profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin);
588628

589629
// FIXME(eddyb) Get more valid Span's on queries.
590630
// def_span guard is necessary to prevent a recursive loop,
@@ -612,6 +652,7 @@ macro_rules! define_maps {
612652
tcx.dep_graph.with_task(dep_node, tcx, key, run_provider)
613653
}
614654
})?;
655+
profq_msg!(tcx, ProfileQueriesMsg::ProviderEnd);
615656

616657
tcx.dep_graph.read_index(dep_node_index);
617658

src/librustc/util/common.rs

+77
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ use std::iter::repeat;
1919
use std::path::Path;
2020
use std::time::{Duration, Instant};
2121

22+
use std::sync::mpsc::{Sender};
23+
use syntax_pos::{Span};
24+
use ty::maps::{QueryMsg};
25+
use dep_graph::{DepNode};
26+
2227
// The name of the associated type for `Fn` return types
2328
pub const FN_OUTPUT_NAME: &'static str = "Output";
2429

@@ -29,6 +34,72 @@ pub struct ErrorReported;
2934

3035
thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
3136

37+
/// Initialized for -Z profile-queries
38+
thread_local!(static PROFQ_CHAN: RefCell<Option<Sender<ProfileQueriesMsg>>> = RefCell::new(None));
39+
40+
/// Parameters to the `Dump` variant of type `ProfileQueriesMsg`.
41+
#[derive(Clone,Debug)]
42+
pub struct ProfQDumpParams {
43+
/// A base path for the files we will dump
44+
pub path:String,
45+
/// To ensure that the compiler waits for us to finish our dumps
46+
pub ack:Sender<()>,
47+
/// toggle dumping a log file with every `ProfileQueriesMsg`
48+
pub dump_profq_msg_log:bool,
49+
}
50+
51+
/// A sequence of these messages induce a trace of query-based incremental compilation.
52+
/// FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
53+
#[derive(Clone,Debug)]
54+
pub enum ProfileQueriesMsg {
55+
/// begin a timed pass
56+
TimeBegin(String),
57+
/// end a timed pass
58+
TimeEnd,
59+
/// begin a task (see dep_graph::graph::with_task)
60+
TaskBegin(DepNode),
61+
/// end a task
62+
TaskEnd,
63+
/// begin a new query
64+
QueryBegin(Span, QueryMsg),
65+
/// query is satisfied by using an already-known value for the given key
66+
CacheHit,
67+
/// query requires running a provider; providers may nest, permitting queries to nest.
68+
ProviderBegin,
69+
/// query is satisfied by a provider terminating with a value
70+
ProviderEnd,
71+
/// dump a record of the queries to the given path
72+
Dump(ProfQDumpParams),
73+
/// halt the profiling/monitoring background thread
74+
Halt
75+
}
76+
77+
/// If enabled, send a message to the profile-queries thread
78+
pub fn profq_msg(msg: ProfileQueriesMsg) {
79+
PROFQ_CHAN.with(|sender|{
80+
if let Some(s) = sender.borrow().as_ref() {
81+
s.send(msg).unwrap()
82+
} else {
83+
// Do nothing.
84+
//
85+
// FIXME(matthewhammer): Multi-threaded translation phase triggers the panic below.
86+
// From backtrace: rustc_trans::back::write::spawn_work::{{closure}}.
87+
//
88+
// panic!("no channel on which to send profq_msg: {:?}", msg)
89+
}
90+
})
91+
}
92+
93+
/// Set channel for profile queries channel
94+
pub fn profq_set_chan(s: Sender<ProfileQueriesMsg>) -> bool {
95+
PROFQ_CHAN.with(|chan|{
96+
if chan.borrow().is_none() {
97+
*chan.borrow_mut() = Some(s);
98+
true
99+
} else { false }
100+
})
101+
}
102+
32103
/// Read the current depth of `time()` calls. This is used to
33104
/// encourage indentation across threads.
34105
pub fn time_depth() -> usize {
@@ -53,9 +124,15 @@ pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where
53124
r
54125
});
55126

127+
if cfg!(debug_assertions) {
128+
profq_msg(ProfileQueriesMsg::TimeBegin(what.to_string()))
129+
};
56130
let start = Instant::now();
57131
let rv = f();
58132
let dur = start.elapsed();
133+
if cfg!(debug_assertions) {
134+
profq_msg(ProfileQueriesMsg::TimeEnd)
135+
};
59136

60137
print_time_passes_entry_internal(what, dur);
61138

src/librustc_driver/driver.rs

+14
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ use arena::DroplessArena;
6464

6565
use derive_registrar;
6666

67+
use profile;
68+
6769
pub fn compile_input(sess: &Session,
6870
cstore: &CStore,
6971
input: &Input,
@@ -105,6 +107,10 @@ pub fn compile_input(sess: &Session,
105107
sess.abort_if_errors();
106108
}
107109

110+
if sess.profile_queries() {
111+
profile::begin();
112+
}
113+
108114
// We need nested scopes here, because the intermediate results can keep
109115
// large chunks of memory alive and we want to free them as soon as
110116
// possible to keep the peak memory usage low
@@ -537,6 +543,10 @@ pub fn phase_1_parse_input<'a>(control: &CompileController,
537543
-> PResult<'a, ast::Crate> {
538544
sess.diagnostic().set_continue_after_error(control.continue_parse_after_error);
539545

546+
if sess.profile_queries() {
547+
profile::begin();
548+
}
549+
540550
let krate = time(sess.time_passes(), "parsing", || {
541551
match *input {
542552
Input::File(ref file) => {
@@ -1120,6 +1130,10 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
11201130
"translation",
11211131
move || trans::trans_crate(tcx, analysis, incremental_hashes_map, output_filenames));
11221132

1133+
if tcx.sess.profile_queries() {
1134+
profile::dump("profile_queries".to_string())
1135+
}
1136+
11231137
translation
11241138
}
11251139

src/librustc_driver/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ use syntax_pos::{DUMMY_SP, MultiSpan};
104104
#[cfg(test)]
105105
mod test;
106106

107+
pub mod profile;
107108
pub mod driver;
108109
pub mod pretty;
109110
pub mod target_features;

0 commit comments

Comments
 (0)