Skip to content

Commit acd7f87

Browse files
authored
Rollup merge of #107718 - Zoxc:z-time, r=nnethercote
Add `-Z time-passes-format` to allow specifying a JSON output for `-Z time-passes` This adds back the `-Z time` option as that is useful for [my rustc benchmark tool](https://github.com/Zoxc/rcb), reverting #102725. It now uses nanoseconds and bytes as the units so it is renamed to `time-precise`.
2 parents aeabe34 + 6c57dda commit acd7f87

File tree

13 files changed

+107
-32
lines changed

13 files changed

+107
-32
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4523,6 +4523,7 @@ dependencies = [
45234523
"rustc_index",
45244524
"rustc_macros",
45254525
"rustc_serialize",
4526+
"serde_json",
45264527
"smallvec",
45274528
"stable_deref_trait",
45284529
"stacker",

compiler/rustc_codegen_llvm/src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -361,12 +361,12 @@ impl CodegenBackend for LlvmCodegenBackend {
361361
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
362362
.join(sess);
363363

364-
sess.time("llvm_dump_timing_file", || {
365-
if sess.opts.unstable_opts.llvm_time_trace {
364+
if sess.opts.unstable_opts.llvm_time_trace {
365+
sess.time("llvm_dump_timing_file", || {
366366
let file_name = outputs.with_extension("llvm_timings.json");
367367
llvm_util::time_trace_profiler_finish(&file_name);
368-
}
369-
});
368+
});
369+
}
370370

371371
Ok((codegen_results, work_products))
372372
}

compiler/rustc_codegen_ssa/src/base.rs

+1
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
786786
total_codegen_time,
787787
start_rss.unwrap(),
788788
end_rss,
789+
tcx.sess.opts.unstable_opts.time_passes_format,
789790
);
790791
}
791792

compiler/rustc_data_structures/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ rustc-hash = "1.1.0"
2121
rustc_index = { path = "../rustc_index", package = "rustc_index" }
2222
rustc_macros = { path = "../rustc_macros" }
2323
rustc_serialize = { path = "../rustc_serialize" }
24+
serde_json = "1.0.59"
2425
smallvec = { version = "1.8.1", features = [
2526
"const_generics",
2627
"union",

compiler/rustc_data_structures/src/graph/scc/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn test_three_sccs() {
5656
assert_eq!(sccs.scc(1), 0);
5757
assert_eq!(sccs.scc(2), 0);
5858
assert_eq!(sccs.scc(3), 2);
59-
assert_eq!(sccs.successors(0), &[]);
59+
assert_eq!(sccs.successors(0), &[] as &[usize]);
6060
assert_eq!(sccs.successors(1), &[0]);
6161
assert_eq!(sccs.successors(2), &[0]);
6262
}
@@ -113,7 +113,7 @@ fn test_find_state_2() {
113113
assert_eq!(sccs.scc(2), 0);
114114
assert_eq!(sccs.scc(3), 0);
115115
assert_eq!(sccs.scc(4), 0);
116-
assert_eq!(sccs.successors(0), &[]);
116+
assert_eq!(sccs.successors(0), &[] as &[usize]);
117117
}
118118

119119
#[test]
@@ -138,7 +138,7 @@ fn test_find_state_3() {
138138
assert_eq!(sccs.scc(3), 0);
139139
assert_eq!(sccs.scc(4), 0);
140140
assert_eq!(sccs.scc(5), 1);
141-
assert_eq!(sccs.successors(0), &[]);
141+
assert_eq!(sccs.successors(0), &[] as &[usize]);
142142
assert_eq!(sccs.successors(1), &[0]);
143143
}
144144

compiler/rustc_data_structures/src/graph/vec_graph/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ fn successors() {
2727
let graph = create_graph();
2828
assert_eq!(graph.successors(0), &[1]);
2929
assert_eq!(graph.successors(1), &[2, 3]);
30-
assert_eq!(graph.successors(2), &[]);
30+
assert_eq!(graph.successors(2), &[] as &[usize]);
3131
assert_eq!(graph.successors(3), &[4]);
32-
assert_eq!(graph.successors(4), &[]);
32+
assert_eq!(graph.successors(4), &[] as &[usize]);
3333
assert_eq!(graph.successors(5), &[1]);
34-
assert_eq!(graph.successors(6), &[]);
34+
assert_eq!(graph.successors(6), &[] as &[usize]);
3535
}
3636

3737
#[test]

compiler/rustc_data_structures/src/profiling.rs

+58-14
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ use std::time::{Duration, Instant};
9797
pub use measureme::EventId;
9898
use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
9999
use parking_lot::RwLock;
100+
use serde_json::json;
100101
use smallvec::SmallVec;
101102

102103
bitflags::bitflags! {
@@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
145146
/// Something that uniquely identifies a query invocation.
146147
pub struct QueryInvocationId(pub u32);
147148

149+
/// Which format to use for `-Z time-passes`
150+
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
151+
pub enum TimePassesFormat {
152+
/// Emit human readable text
153+
Text,
154+
/// Emit structured JSON
155+
Json,
156+
}
157+
148158
/// A reference to the SelfProfiler. It can be cloned and sent across thread
149159
/// boundaries at will.
150160
#[derive(Clone)]
@@ -158,14 +168,14 @@ pub struct SelfProfilerRef {
158168
// actually enabled.
159169
event_filter_mask: EventFilter,
160170

161-
// Print verbose generic activities to stderr?
162-
print_verbose_generic_activities: bool,
171+
// Print verbose generic activities to stderr.
172+
print_verbose_generic_activities: Option<TimePassesFormat>,
163173
}
164174

165175
impl SelfProfilerRef {
166176
pub fn new(
167177
profiler: Option<Arc<SelfProfiler>>,
168-
print_verbose_generic_activities: bool,
178+
print_verbose_generic_activities: Option<TimePassesFormat>,
169179
) -> SelfProfilerRef {
170180
// If there is no SelfProfiler then the filter mask is set to NONE,
171181
// ensuring that nothing ever tries to actually access it.
@@ -207,9 +217,10 @@ impl SelfProfilerRef {
207217
/// a measureme event, "verbose" generic activities also print a timing entry to
208218
/// stderr if the compiler is invoked with -Ztime-passes.
209219
pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> {
210-
let message = self.print_verbose_generic_activities.then(|| event_label.to_owned());
220+
let message_and_format =
221+
self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format));
211222

212-
VerboseTimingGuard::start(message, self.generic_activity(event_label))
223+
VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label))
213224
}
214225

215226
/// Like `verbose_generic_activity`, but with an extra arg.
@@ -221,11 +232,14 @@ impl SelfProfilerRef {
221232
where
222233
A: Borrow<str> + Into<String>,
223234
{
224-
let message = self
235+
let message_and_format = self
225236
.print_verbose_generic_activities
226-
.then(|| format!("{}({})", event_label, event_arg.borrow()));
237+
.map(|format| (format!("{}({})", event_label, event_arg.borrow()), format));
227238

228-
VerboseTimingGuard::start(message, self.generic_activity_with_arg(event_label, event_arg))
239+
VerboseTimingGuard::start(
240+
message_and_format,
241+
self.generic_activity_with_arg(event_label, event_arg),
242+
)
229243
}
230244

231245
/// Start profiling a generic activity. Profiling continues until the
@@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> {
703717
}
704718
}
705719

720+
struct VerboseInfo {
721+
start_time: Instant,
722+
start_rss: Option<usize>,
723+
message: String,
724+
format: TimePassesFormat,
725+
}
726+
706727
#[must_use]
707728
pub struct VerboseTimingGuard<'a> {
708-
start_and_message: Option<(Instant, Option<usize>, String)>,
729+
info: Option<VerboseInfo>,
709730
_guard: TimingGuard<'a>,
710731
}
711732

712733
impl<'a> VerboseTimingGuard<'a> {
713-
pub fn start(message: Option<String>, _guard: TimingGuard<'a>) -> Self {
734+
pub fn start(
735+
message_and_format: Option<(String, TimePassesFormat)>,
736+
_guard: TimingGuard<'a>,
737+
) -> Self {
714738
VerboseTimingGuard {
715739
_guard,
716-
start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)),
740+
info: message_and_format.map(|(message, format)| VerboseInfo {
741+
start_time: Instant::now(),
742+
start_rss: get_resident_set_size(),
743+
message,
744+
format,
745+
}),
717746
}
718747
}
719748

@@ -726,10 +755,10 @@ impl<'a> VerboseTimingGuard<'a> {
726755

727756
impl Drop for VerboseTimingGuard<'_> {
728757
fn drop(&mut self) {
729-
if let Some((start_time, start_rss, ref message)) = self.start_and_message {
758+
if let Some(info) = &self.info {
730759
let end_rss = get_resident_set_size();
731-
let dur = start_time.elapsed();
732-
print_time_passes_entry(message, dur, start_rss, end_rss);
760+
let dur = info.start_time.elapsed();
761+
print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format);
733762
}
734763
}
735764
}
@@ -739,7 +768,22 @@ pub fn print_time_passes_entry(
739768
dur: Duration,
740769
start_rss: Option<usize>,
741770
end_rss: Option<usize>,
771+
format: TimePassesFormat,
742772
) {
773+
match format {
774+
TimePassesFormat::Json => {
775+
let json = json!({
776+
"pass": what,
777+
"time": dur.as_secs_f64(),
778+
"rss_start": start_rss,
779+
"rss_end": end_rss,
780+
});
781+
eprintln!("time: {}", json.to_string());
782+
return;
783+
}
784+
TimePassesFormat::Text => (),
785+
}
786+
743787
// Print the pass if its duration is greater than 5 ms, or it changed the
744788
// measured RSS.
745789
let is_notable = || {

compiler/rustc_driver_impl/src/lib.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ pub extern crate rustc_plugin_impl as plugin;
2020

2121
use rustc_ast as ast;
2222
use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
23-
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
23+
use rustc_data_structures::profiling::{
24+
get_resident_set_size, print_time_passes_entry, TimePassesFormat,
25+
};
2426
use rustc_data_structures::sync::SeqCst;
2527
use rustc_errors::registry::{InvalidErrorCode, Registry};
2628
use rustc_errors::{
@@ -161,7 +163,7 @@ pub trait Callbacks {
161163

162164
#[derive(Default)]
163165
pub struct TimePassesCallbacks {
164-
time_passes: bool,
166+
time_passes: Option<TimePassesFormat>,
165167
}
166168

167169
impl Callbacks for TimePassesCallbacks {
@@ -171,7 +173,8 @@ impl Callbacks for TimePassesCallbacks {
171173
// If a --print=... option has been given, we don't print the "total"
172174
// time because it will mess up the --print output. See #64339.
173175
//
174-
self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes;
176+
self.time_passes = (config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes)
177+
.then(|| config.opts.unstable_opts.time_passes_format);
175178
config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
176179
}
177180
}
@@ -1354,9 +1357,9 @@ pub fn main() -> ! {
13541357
RunCompiler::new(&args, &mut callbacks).run()
13551358
});
13561359

1357-
if callbacks.time_passes {
1360+
if let Some(format) = callbacks.time_passes {
13581361
let end_rss = get_resident_set_size();
1359-
print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
1362+
print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss, format);
13601363
}
13611364

13621365
process::exit(exit_code)

compiler/rustc_hir_analysis/src/coherence/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
133133
check_impl(tcx, impl_def_id, trait_ref);
134134
check_object_overlap(tcx, impl_def_id, trait_ref);
135135

136-
tcx.sess.time("unsafety_checking", || unsafety::check_item(tcx, impl_def_id));
137-
tcx.sess.time("orphan_checking", || tcx.ensure().orphan_check_impl(impl_def_id));
136+
unsafety::check_item(tcx, impl_def_id);
137+
tcx.ensure().orphan_check_impl(impl_def_id);
138138
}
139139

140140
builtin::check_trait(tcx, def_id);

compiler/rustc_interface/src/tests.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use crate::interface::parse_cfgspecs;
33

44
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_data_structures::profiling::TimePassesFormat;
56
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
67
use rustc_session::config::rustc_optgroups;
78
use rustc_session::config::Input;
@@ -699,6 +700,7 @@ fn test_unstable_options_tracking_hash() {
699700
untracked!(threads, 99);
700701
untracked!(time_llvm_passes, true);
701702
untracked!(time_passes, true);
703+
untracked!(time_passes_format, TimePassesFormat::Json);
702704
untracked!(trace_macros, true);
703705
untracked!(track_diagnostics, true);
704706
untracked!(trim_diagnostic_paths, false);

compiler/rustc_session/src/options.rs

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::early_error;
44
use crate::lint;
55
use crate::search_paths::SearchPath;
66
use crate::utils::NativeLib;
7+
use rustc_data_structures::profiling::TimePassesFormat;
78
use rustc_errors::{LanguageIdentifier, TerminalUrl};
89
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
910
use rustc_target::spec::{
@@ -365,6 +366,7 @@ mod desc {
365366
pub const parse_number: &str = "a number";
366367
pub const parse_opt_number: &str = parse_number;
367368
pub const parse_threads: &str = parse_number;
369+
pub const parse_time_passes_format: &str = "`text` (default) or `json`";
368370
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
369371
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
370372
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
@@ -829,6 +831,21 @@ mod parse {
829831
true
830832
}
831833

834+
pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool {
835+
match v {
836+
None => true,
837+
Some("json") => {
838+
*slot = TimePassesFormat::Json;
839+
true
840+
}
841+
Some("text") => {
842+
*slot = TimePassesFormat::Text;
843+
true
844+
}
845+
Some(_) => false,
846+
}
847+
}
848+
832849
pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
833850
match v {
834851
None => true,
@@ -1709,6 +1726,8 @@ options! {
17091726
"measure time of each LLVM pass (default: no)"),
17101727
time_passes: bool = (false, parse_bool, [UNTRACKED],
17111728
"measure time of each rustc pass (default: no)"),
1729+
time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED],
1730+
"the format to use for -Z time-passes (`text` (default) or `json`)"),
17121731
tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
17131732
"sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
17141733
#[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]

compiler/rustc_session/src/session.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1453,7 +1453,10 @@ pub fn build_session(
14531453
CguReuseTracker::new_disabled()
14541454
};
14551455

1456-
let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes);
1456+
let prof = SelfProfilerRef::new(
1457+
self_profiler,
1458+
sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format),
1459+
);
14571460

14581461
let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
14591462
Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,

tests/rustdoc-ui/z-help.stdout

+1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@
183183
-Z threads=val -- use a thread pool with N threads
184184
-Z time-llvm-passes=val -- measure time of each LLVM pass (default: no)
185185
-Z time-passes=val -- measure time of each rustc pass (default: no)
186+
-Z time-passes-format=val -- the format to use for -Z time-passes (`text` (default) or `json`)
186187
-Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
187188
-Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
188189
-Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)

0 commit comments

Comments
 (0)