Skip to content

Commit c5fe2a2

Browse files
committed
Add support for -Zself-profile to collector profile.
It produces output for `summarize`, `flamegraph`, and `crox`.
1 parent c2e35ab commit c5fe2a2

File tree

4 files changed

+85
-7
lines changed

4 files changed

+85
-7
lines changed

collector/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,18 @@ RUST_LOG=info ./target/release/collector --output-repo $OUTPUT_DIR \
214214

215215
All the parts of this command are the same as for the `bench_local` subcommand,
216216
except that `$PROFILER` is one of the following.
217+
- `self-profile`: Profile with rustc's `-Zself-profile`.
218+
- **Purpose**. This gives multiple high-level views of compiler performance,
219+
in both tabular and graphical form.
220+
- **Slowdown**. Minimal.
221+
- **Output**. Raw output is written to a directory with a `Zsp` prefix.
222+
The files in that directory can be processed with various
223+
[`measureme`](https://github.com/rust-lang/measureme/) tools.
224+
Human-readable output from `summarize` is written to a file with a
225+
`summarize` prefix. Output from `flamegraph`, viewable with a web browser,
226+
is written to a file with a `flamegraph` prefix. Output from `crox`,
227+
viewable with Chromium's profiler, is written to a file with a `crox`
228+
prefix.
217229
- `time-passes`: Profile with rustc's `-Ztime-passes`.
218230
- **Purpose**. This gives a high-level indication of compiler performance by
219231
showing how long each compilation pass takes.

collector/src/bin/rustc-fake.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ fn main() {
9090
}
9191
}
9292

93+
"self-profile" => {
94+
let mut cmd = Command::new(&rustc);
95+
cmd.arg("-Zself-profile=Zsp").args(&args);
96+
97+
assert!(cmd.status().expect("failed to spawn").success());
98+
}
99+
93100
"time-passes" => {
94101
let mut cmd = Command::new(&rustc);
95102
cmd.arg("-Ztime-passes").args(&args);

collector/src/bin/rustc-perf-collector/execute.rs

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub struct Benchmark {
7474
pub enum Profiler {
7575
PerfStat,
7676
PerfStatSelfProfile,
77+
SelfProfile,
7778
TimePasses,
7879
PerfRecord,
7980
OProfile,
@@ -99,6 +100,7 @@ impl Profiler {
99100
// is rejected because it can't be used with the `profiler`
100101
// subcommand. (It's used with `bench_local` instead.)
101102
"perf-stat" => Err(FromNameError::PerfStat),
103+
"self-profile" => Ok(Profiler::SelfProfile),
102104
"time-passes" => Ok(Profiler::TimePasses),
103105
"perf-record" => Ok(Profiler::PerfRecord),
104106
"oprofile" => Ok(Profiler::OProfile),
@@ -115,6 +117,7 @@ impl Profiler {
115117
match self {
116118
Profiler::PerfStat => "perf-stat",
117119
Profiler::PerfStatSelfProfile => "perf-stat-self-profile",
120+
Profiler::SelfProfile => "self-profile",
118121
Profiler::TimePasses => "time-passes",
119122
Profiler::PerfRecord => "perf-record",
120123
Profiler::OProfile => "oprofile",
@@ -500,6 +503,66 @@ impl<'a> Processor for ProfileProcessor<'a> {
500503
panic!("unexpected profiler");
501504
}
502505

506+
// -Zself-profile produces (via rustc-fake) a data directory called
507+
// 'Zsp' containing three files with names of the form
508+
// `$BENCHMARK-$PID.{events,string_data,string_index}`. We copy it
509+
// from the temp dir to the output dir, renaming the files within
510+
// as `Zsp.{events,string_data,string_index}` in the process, then
511+
// post-process them with `summarize`, `flamegraph`, and `crox` to
512+
// produce several data files in the output dir.
513+
Profiler::SelfProfile => {
514+
let tmp_zsp_dir = filepath(data.cwd.as_ref(), "Zsp");
515+
let zsp_dir = filepath(self.output_dir, &out_file("Zsp"));
516+
let zsp_files_prefix = filepath(&zsp_dir, "Zsp");
517+
let summarize_file = filepath(self.output_dir, &out_file("summarize"));
518+
let flamegraph_file = filepath(self.output_dir, &out_file("flamegraph"));
519+
let crox_file = filepath(self.output_dir, &out_file("crox"));
520+
521+
// Move the directory.
522+
if zsp_dir.exists() {
523+
fs::remove_dir_all(&zsp_dir)?;
524+
}
525+
fs::rename(&tmp_zsp_dir, &zsp_dir)?;
526+
527+
// Rename the data files.
528+
for entry in fs::read_dir(&zsp_dir).unwrap() {
529+
let filename = entry.unwrap().file_name();
530+
let filename_str = filename.to_str().unwrap();
531+
let path = filepath(&zsp_dir, filename_str);
532+
if filename_str.ends_with(".events") {
533+
fs::rename(path, filepath(&zsp_dir, "Zsp.events"))?;
534+
} else if filename_str.ends_with(".string_data") {
535+
fs::rename(path, filepath(&zsp_dir, "Zsp.string_data"))?;
536+
} else if filename_str.ends_with(".string_index") {
537+
fs::rename(path, filepath(&zsp_dir, "Zsp.string_index"))?;
538+
} else {
539+
panic!("unexpected file {:?}", path);
540+
}
541+
}
542+
543+
// Run `summarize`.
544+
let mut summarize_cmd = Command::new("summarize");
545+
summarize_cmd
546+
.arg("summarize")
547+
.arg(&zsp_files_prefix);
548+
let output = summarize_cmd.output()?;
549+
fs::write(&summarize_file, &output.stdout)?;
550+
551+
// Run `flamegraph`.
552+
let mut flamegraph_cmd = Command::new("flamegraph");
553+
flamegraph_cmd.arg(&zsp_files_prefix);
554+
flamegraph_cmd.status()?;
555+
fs::write(&summarize_file, &output.stdout)?;
556+
fs::rename("rustc.svg", flamegraph_file)?;
557+
558+
// Run `crox`.
559+
let mut crox_cmd = Command::new("crox");
560+
crox_cmd.arg(&zsp_files_prefix);
561+
crox_cmd.status()?;
562+
fs::write(&summarize_file, &output.stdout)?;
563+
fs::rename("chrome_profiler.json", crox_file)?;
564+
}
565+
503566
// -Ztime-passes writes its output to stdout. We copy that output
504567
// into a file in the output dir.
505568
Profiler::TimePasses => {
@@ -528,7 +591,7 @@ impl<'a> Processor for ProfileProcessor<'a> {
528591
let oprep_file = filepath(self.output_dir, &out_file("oprep"));
529592
let opann_file = filepath(self.output_dir, &out_file("opann"));
530593

531-
// Remove the directory if it exists.
594+
// Move the directory.
532595
if opout_dir.exists() {
533596
fs::remove_dir_all(&opout_dir)?;
534597
}
@@ -547,7 +610,6 @@ impl<'a> Processor for ProfileProcessor<'a> {
547610
.arg("0.5")
548611
.arg(&session_dir_arg);
549612
let output = op_report_cmd.output()?;
550-
551613
fs::write(oprep_file, &output.stdout)?;
552614

553615
let mut op_annotate_cmd = Command::new("opannotate");
@@ -558,7 +620,6 @@ impl<'a> Processor for ProfileProcessor<'a> {
558620
.arg("0.5")
559621
.arg(&session_dir_arg);
560622
let output = op_annotate_cmd.output()?;
561-
562623
fs::write(opann_file, &output.stdout)?;
563624
}
564625

@@ -579,7 +640,6 @@ impl<'a> Processor for ProfileProcessor<'a> {
579640
.arg("--show-percs=yes")
580641
.arg(&cgout_file);
581642
let output = cg_annotate_cmd.output()?;
582-
583643
fs::write(cgann_file, &output.stdout)?;
584644
}
585645

@@ -600,7 +660,6 @@ impl<'a> Processor for ProfileProcessor<'a> {
600660
.arg("--show-percs=yes")
601661
.arg(&clgout_file);
602662
let output = clg_annotate_cmd.output()?;
603-
604663
fs::write(clgann_file, &output.stdout)?;
605664
}
606665

collector/src/bin/rustc-perf-collector/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,8 @@ fn main_result() -> anyhow::Result<i32> {
446446
"One or more (comma-separated) of: 'Clean',\n\
447447
'BaseIncr', 'CleanIncr', 'PatchedIncrs', 'All'")
448448
(@arg PROFILER: +required +takes_value
449-
"One of: 'time-passes', 'perf-record', 'cachegrind',\n\
450-
'callgrind', ''dhat', 'massif', 'eprintln'")
449+
"One of: 'self-profile', 'time-passes', 'perf-record',\n\
450+
'cachegrind', 'callgrind', ''dhat', 'massif', 'eprintln'")
451451
(@arg ID: +required +takes_value "Identifier to associate benchmark results with")
452452
)
453453
(@subcommand remove_benchmark =>

0 commit comments

Comments
 (0)