Skip to content

Commit e1236d9

Browse files
Merge pull request #726 from nnethercote/wrap-eprintln
Avoid collecting extraneous stuff on `eprintln` runs.
2 parents 79e630e + b374d77 commit e1236d9

File tree

3 files changed

+68
-36
lines changed

3 files changed

+68
-36
lines changed

ci/check-profiling.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,17 @@ RUST_BACKTRACE=1 RUST_LOG=raw_cargo_messages=trace,collector=debug,rust_sysroot=
7676
test -f results/msout-Test-helloworld-Check-Full
7777
grep -q "snapshot=0" results/msout-Test-helloworld-Check-Full
7878

79-
# eprintln.
79+
# eprintln. The output file is empty because a vanilla rustc doesn't print
80+
# anything to stderr.
8081
RUST_BACKTRACE=1 RUST_LOG=raw_cargo_messages=trace,collector=debug,rust_sysroot=debug \
8182
cargo run -p collector --bin collector -- \
8283
profile_local eprintln $bindir/rustc Test \
8384
--builds Check \
8485
--cargo $bindir/cargo \
8586
--include helloworld \
8687
--runs Full
87-
test -f results/eprintln-Test-helloworld-Check-Full
88-
grep -q "Checking helloworld" results/eprintln-Test-helloworld-Check-Full
88+
test -f results/eprintln-Test-helloworld-Check-Full
89+
test ! -s results/eprintln-Test-helloworld-Check-Full
8990

9091
# llvm-lines. `Debug` not `Check` because it doesn't support `Check` builds.
9192
RUST_BACKTRACE=1 RUST_LOG=raw_cargo_messages=trace,collector=debug,rust_sysroot=debug \

collector/src/execute.rs

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ impl<'a> Processor for ProfileProcessor<'a> {
661661
}
662662

663663
// -Zself-profile produces (via rustc-fake) a data directory called
664-
// 'Zsp' containing three files with names of the form
664+
// `Zsp` containing three files with names of the form
665665
// `$BENCHMARK-$PID.{events,string_data,string_index}`. We copy it
666666
// from the temp dir to the output dir, renaming the files within
667667
// as `Zsp.{events,string_data,string_index}` in the process, then
@@ -703,8 +703,7 @@ impl<'a> Processor for ProfileProcessor<'a> {
703703
// Run `summarize`.
704704
let mut summarize_cmd = Command::new("summarize");
705705
summarize_cmd.arg("summarize").arg(&zsp_files_prefix);
706-
let output = summarize_cmd.output()?;
707-
fs::write(&summarize_file, &output.stdout)?;
706+
fs::write(&summarize_file, &summarize_cmd.output()?.stdout)?;
708707

709708
// Run `flamegraph`.
710709
let mut flamegraph_cmd = Command::new("flamegraph");
@@ -719,15 +718,16 @@ impl<'a> Processor for ProfileProcessor<'a> {
719718
fs::rename("chrome_profiler.json", crox_file)?;
720719
}
721720

722-
// -Ztime-passes writes its output to stdout. We copy that output
723-
// into a file in the output dir.
721+
// `-Ztime-passes` output is redirected (via rustc-fake) to a file
722+
// called `Ztp`. We copy that output into a file in the output dir.
724723
Profiler::TimePasses => {
724+
let tmp_ztp_file = filepath(data.cwd.as_ref(), "Ztp");
725725
let ztp_file = filepath(self.output_dir, &out_file("Ztp"));
726726

727-
fs::write(ztp_file, &output.stdout)?;
727+
fs::copy(&tmp_ztp_file, &ztp_file)?;
728728
}
729729

730-
// perf-record produces (via rustc-fake) a data file called 'perf'.
730+
// perf-record produces (via rustc-fake) a data file called `perf`.
731731
// We copy it from the temp dir to the output dir, giving it a new
732732
// name in the process.
733733
Profiler::PerfRecord => {
@@ -738,7 +738,7 @@ impl<'a> Processor for ProfileProcessor<'a> {
738738
}
739739

740740
// OProfile produces (via rustc-fake) a data directory called
741-
// 'oprofile_data'. We copy it from the temp dir to the output dir,
741+
// `oprofile_data`. We copy it from the temp dir to the output dir,
742742
// giving it a new name in the process, and then post-process it
743743
// twice to produce another two data files in the output dir.
744744
Profiler::OProfile => {
@@ -765,8 +765,7 @@ impl<'a> Processor for ProfileProcessor<'a> {
765765
.arg("--threshold")
766766
.arg("0.5")
767767
.arg(&session_dir_arg);
768-
let output = op_report_cmd.output()?;
769-
fs::write(oprep_file, &output.stdout)?;
768+
fs::write(oprep_file, &op_report_cmd.output()?.stdout)?;
770769

771770
let mut op_annotate_cmd = Command::new("opannotate");
772771
// Other possibly useful args: --assembly
@@ -775,11 +774,10 @@ impl<'a> Processor for ProfileProcessor<'a> {
775774
.arg("--threshold")
776775
.arg("0.5")
777776
.arg(&session_dir_arg);
778-
let output = op_annotate_cmd.output()?;
779-
fs::write(opann_file, &output.stdout)?;
777+
fs::write(opann_file, &op_annotate_cmd.output()?.stdout)?;
780778
}
781779

782-
// Cachegrind produces (via rustc-fake) a data file called 'cgout'.
780+
// Cachegrind produces (via rustc-fake) a data file called `cgout`.
783781
// We copy it from the temp dir to the output dir, giving it a new
784782
// name in the process, and then post-process it to produce another
785783
// data file in the output dir.
@@ -795,11 +793,10 @@ impl<'a> Processor for ProfileProcessor<'a> {
795793
.arg("--auto=yes")
796794
.arg("--show-percs=yes")
797795
.arg(&cgout_file);
798-
let output = cg_annotate_cmd.output()?;
799-
fs::write(cgann_file, &output.stdout)?;
796+
fs::write(cgann_file, &cg_annotate_cmd.output()?.stdout)?;
800797
}
801798

802-
// Callgrind produces (via rustc-fake) a data file called 'clgout'.
799+
// Callgrind produces (via rustc-fake) a data file called `clgout`.
803800
// We copy it from the temp dir to the output dir, giving it a new
804801
// name in the process, and then post-process it to produce another
805802
// data file in the output dir.
@@ -815,11 +812,10 @@ impl<'a> Processor for ProfileProcessor<'a> {
815812
.arg("--auto=yes")
816813
.arg("--show-percs=yes")
817814
.arg(&clgout_file);
818-
let output = clg_annotate_cmd.output()?;
819-
fs::write(clgann_file, &output.stdout)?;
815+
fs::write(clgann_file, &clg_annotate_cmd.output()?.stdout)?;
820816
}
821817

822-
// DHAT produces (via rustc-fake) a data file called 'dhout'. We
818+
// DHAT produces (via rustc-fake) a data file called `dhout`. We
823819
// copy it from the temp dir to the output dir, giving it a new
824820
// name in the process.
825821
Profiler::DHAT => {
@@ -829,7 +825,7 @@ impl<'a> Processor for ProfileProcessor<'a> {
829825
fs::copy(&tmp_dhout_file, &dhout_file)?;
830826
}
831827

832-
// Massif produces (via rustc-fake) a data file called 'msout'. We
828+
// Massif produces (via rustc-fake) a data file called `msout`. We
833829
// copy it from the temp dir to the output dir, giving it a new
834830
// name in the process.
835831
Profiler::Massif => {
@@ -839,12 +835,14 @@ impl<'a> Processor for ProfileProcessor<'a> {
839835
fs::copy(&tmp_msout_file, &msout_file)?;
840836
}
841837

842-
// `eprintln!` statements writes their output to stderr. We copy
843-
// that output into a file in the output dir.
838+
// `eprintln!` statements are redirected (via rustc-fake) to a file
839+
// called `eprintln`. We copy it from the temp dir to the output
840+
// dir, giving it a new name in the process.
844841
Profiler::Eprintln => {
842+
let tmp_eprintln_file = filepath(data.cwd.as_ref(), "eprintln");
845843
let eprintln_file = filepath(self.output_dir, &out_file("eprintln"));
846844

847-
fs::write(eprintln_file, &output.stderr)?;
845+
fs::copy(&tmp_eprintln_file, &eprintln_file)?;
848846
}
849847

850848
// `cargo llvm-lines` writes its output to stdout. We copy that

collector/src/rustc-fake.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::env;
2+
use std::ffi::OsString;
3+
use std::fs;
24
use std::path::Path;
35
use std::process::Command;
46
use std::time::{Duration, Instant};
@@ -21,11 +23,11 @@ fn main() {
2123
.ok()
2224
.and_then(|v| v.parse::<u32>().ok())
2325
{
24-
args.push(std::ffi::OsString::from(format!("-Zthreads={}", count)));
26+
args.push(OsString::from(format!("-Zthreads={}", count)));
2527
}
2628

27-
args.push(std::ffi::OsString::from("-Adeprecated"));
28-
args.push(std::ffi::OsString::from("-Aunknown-lints"));
29+
args.push(OsString::from("-Adeprecated"));
30+
args.push(OsString::from("-Aunknown-lints"));
2931

3032
if let Some(pos) = args.iter().position(|arg| arg == "--wrap-rustc-with") {
3133
// Strip out the flag and its argument, and run rustc under the wrapper
@@ -56,8 +58,8 @@ fn main() {
5658
"-Zself-profile={}",
5759
prof_out_dir.to_str().unwrap()
5860
));
59-
let _ = std::fs::remove_dir_all(&prof_out_dir);
60-
let _ = std::fs::create_dir_all(&prof_out_dir);
61+
let _ = fs::remove_dir_all(&prof_out_dir);
62+
let _ = fs::create_dir_all(&prof_out_dir);
6163
}
6264

6365
let start = Instant::now();
@@ -75,7 +77,7 @@ fn main() {
7577
let mut prefix = None;
7678
// We don't know the pid of rustc, and can't easily get it -- we only know the
7779
// `perf` pid. So just blindly look in the directory to hopefully find it.
78-
for entry in std::fs::read_dir(&prof_out_dir).unwrap() {
80+
for entry in fs::read_dir(&prof_out_dir).unwrap() {
7981
let entry = entry.unwrap();
8082
if entry
8183
.file_name()
@@ -109,8 +111,8 @@ fn main() {
109111
}
110112

111113
"time-passes" => {
112-
let mut cmd = Command::new(&tool);
113-
cmd.arg("-Ztime-passes").args(&args);
114+
args.insert(0, "-Ztime-passes".into());
115+
let mut cmd = bash_command(tool, args, "> Ztp");
114116

115117
assert!(cmd.status().expect("failed to spawn").success());
116118
}
@@ -203,7 +205,20 @@ fn main() {
203205
assert!(cmd.status().expect("failed to spawn").success());
204206
}
205207

206-
"eprintln" | "llvm-lines" => {
208+
"eprintln" => {
209+
let mut cmd = bash_command(tool, args, "2> eprintln");
210+
211+
assert!(cmd.status().expect("failed to spawn").success());
212+
}
213+
214+
"llvm-lines" => {
215+
// `cargo llvm-lines` writes its output to stdout. But we can't
216+
// redirect it to a file here like we do for "time-passes" and
217+
// "eprintln". This is because `cargo llvm-lines` invokes rustc
218+
// as part of its processing and then it does some analysis of
219+
// its output and then it prints out some results. Because
220+
// `rustc` (which this file wraps) doesn't produce the output,
221+
// this file can't redirect that output.
207222
let mut cmd = Command::new(&tool);
208223
cmd.args(&args);
209224

@@ -227,6 +242,24 @@ fn main() {
227242
}
228243
}
229244

245+
/// Run a command via bash, in order to redirect its output to a file.
246+
/// `redirect` should be something like "> out" or "2> out".
247+
fn bash_command(tool: OsString, args: Vec<OsString>, redirect: &str) -> Command {
248+
let mut bash_cmd = String::new();
249+
bash_cmd.push_str(&format!("{} ", tool.to_str().unwrap()));
250+
for arg in args {
251+
// Args with double quotes (e.g. `--cfg feature="foo"`)
252+
// will be munged by bash if we don't protect them. So we
253+
// wrap every arg in single quotes.
254+
bash_cmd.push_str(&format!("'{}' ", arg.to_str().unwrap()));
255+
}
256+
bash_cmd.push_str(redirect);
257+
258+
let mut cmd = Command::new("bash");
259+
cmd.args(&["-c", &bash_cmd]);
260+
cmd
261+
}
262+
230263
#[cfg(unix)]
231264
fn exec(cmd: &mut Command) -> ! {
232265
use std::os::unix::prelude::*;
@@ -289,7 +322,7 @@ fn run_summarize(name: &str, prof_out_dir: &Path, prefix: &str) -> std::io::Resu
289322
"Failed to run successfully",
290323
));
291324
}
292-
std::fs::read_to_string(prof_out_dir.join(&format!("{}.json", prefix)))
325+
fs::read_to_string(prof_out_dir.join(&format!("{}.json", prefix)))
293326
}
294327

295328
#[cfg(windows)]

0 commit comments

Comments
 (0)