Skip to content

Commit f2d70c5

Browse files
committed
Implementation of build.print_step_rusage.
On non-unix platforms, does not try to call `getrusage` (and does not attempt to implement its own shim; that could be follow-on work, though its probably best to not invest too much effort there, versus using separate dedicated tooling). On unix platforms, calls libc::rusage and attempts to emit the subset of fields that are supported on Linux and Mac OS X. Omits groups of related stats which appear to be unsupported on the platform (due to them all remaining zero). Adjusts output to compensate for Mac using bytes instead of kb (a well known discrepancy on Mac OS X). However, so far I observe a lot of strange values (orders of magnitude wrong) reported on Mac OS X in some cases, so I would not trust this in that context currently.
1 parent 0d8bf72 commit f2d70c5

File tree

1 file changed

+79
-3
lines changed

1 file changed

+79
-3
lines changed

src/bootstrap/bin/rustc.rs

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,24 @@ fn main() {
155155
cmd.status().expect(&errmsg)
156156
};
157157

158-
if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
158+
if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
159+
|| env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
160+
{
159161
if let Some(crate_name) = crate_name {
160162
let dur = start.elapsed();
161163
let is_test = args.iter().any(|a| a == "--test");
164+
// If the user requested resource usage data, then
165+
// include that in addition to the timing output.
166+
let rusage_data =
167+
env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data());
162168
eprintln!(
163-
"[RUSTC-TIMING] {} test:{} {}.{:03}",
169+
"[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
164170
crate_name,
165171
is_test,
166172
dur.as_secs(),
167-
dur.subsec_millis()
173+
dur.subsec_millis(),
174+
if rusage_data.is_some() { " " } else { "" },
175+
rusage_data.unwrap_or(String::new()),
168176
);
169177
}
170178
}
@@ -192,3 +200,71 @@ fn main() {
192200
}
193201
}
194202
}
203+
204+
#[cfg(not(unix))]
205+
/// getrusage is not available on non-unix platforms. So for now, we do not
206+
/// bother trying to make a shim for it.
207+
fn format_rusage_data() -> Option<String> {
208+
None
209+
}
210+
211+
#[cfg(unix)]
212+
/// Tries to build a string with human readable data for several of the rusage
213+
/// fields. Note that we are focusing mainly on data that we believe to be
214+
/// supplied on Linux (the `rusage` struct has other fields in it but they are
215+
/// currently unsupported by Linux).
216+
fn format_rusage_data() -> Option<String> {
217+
let rusage: libc::rusage = unsafe {
218+
let mut recv = std::mem::zeroed();
219+
// -1 is RUSAGE_CHILDREN, which means to get the rusage for all children
220+
// (and grandchildren, etc) processes that have respectively terminated
221+
// and been waited for.
222+
let retval = libc::getrusage(-1, &mut recv);
223+
if retval != 0 {
224+
return None;
225+
}
226+
recv
227+
};
228+
// Mac OS X reports the maxrss in bytes, not kb.
229+
let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
230+
let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;
231+
232+
let mut init_str = format!(
233+
"user: {USER_SEC}.{USER_USEC:03} \
234+
sys: {SYS_SEC}.{SYS_USEC:03} \
235+
max rss (kb): {MAXRSS}",
236+
USER_SEC = rusage.ru_utime.tv_sec,
237+
USER_USEC = rusage.ru_utime.tv_usec,
238+
SYS_SEC = rusage.ru_stime.tv_sec,
239+
SYS_USEC = rusage.ru_stime.tv_usec,
240+
MAXRSS = maxrss
241+
);
242+
243+
// The remaining rusage stats vary in platform support. So we treat
244+
// uniformly zero values in each category as "not worth printing", since it
245+
// either means no events of that type occurred, or that the platform
246+
// does not support it.
247+
248+
let minflt = rusage.ru_minflt;
249+
let majflt = rusage.ru_majflt;
250+
if minflt != 0 || majflt != 0 {
251+
init_str.push_str(&format!(" page reclaims: {} page faults: {}", minflt, majflt));
252+
}
253+
254+
let inblock = rusage.ru_inblock;
255+
let oublock = rusage.ru_oublock;
256+
if inblock != 0 || oublock != 0 {
257+
init_str.push_str(&format!(" fs block inputs: {} fs block outputs: {}", inblock, oublock));
258+
}
259+
260+
let nvcsw = rusage.ru_nvcsw;
261+
let nivcsw = rusage.ru_nivcsw;
262+
if nvcsw != 0 || nivcsw != 0 {
263+
init_str.push_str(&format!(
264+
" voluntary ctxt switches: {} involuntary ctxt switches: {}",
265+
nvcsw, nivcsw
266+
));
267+
}
268+
269+
return Some(init_str);
270+
}

0 commit comments

Comments
 (0)