]> git.lizzy.rs Git - rust.git/commitdiff
Implementation of build.print_step_rusage.
authorFelix S. Klock II <pnkfelix@pnkfx.org>
Fri, 19 Feb 2021 18:27:39 +0000 (13:27 -0500)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Thu, 25 Feb 2021 16:38:52 +0000 (11:38 -0500)
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.

src/bootstrap/bin/rustc.rs

index 3694bdbf67054e68d44d757e48979bb67b6ba179..670046ff08b56581e3ab505664105ece96d53da7 100644 (file)
@@ -155,16 +155,24 @@ fn main() {
         cmd.status().expect(&errmsg)
     };
 
-    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
+    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
+        || env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
+    {
         if let Some(crate_name) = crate_name {
             let dur = start.elapsed();
             let is_test = args.iter().any(|a| a == "--test");
+            // If the user requested resource usage data, then
+            // include that in addition to the timing output.
+            let rusage_data =
+                env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data());
             eprintln!(
-                "[RUSTC-TIMING] {} test:{} {}.{:03}",
+                "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
                 crate_name,
                 is_test,
                 dur.as_secs(),
-                dur.subsec_millis()
+                dur.subsec_millis(),
+                if rusage_data.is_some() { " " } else { "" },
+                rusage_data.unwrap_or(String::new()),
             );
         }
     }
@@ -192,3 +200,71 @@ fn main() {
         }
     }
 }
+
+#[cfg(not(unix))]
+/// getrusage is not available on non-unix platforms. So for now, we do not
+/// bother trying to make a shim for it.
+fn format_rusage_data() -> Option<String> {
+    None
+}
+
+#[cfg(unix)]
+/// Tries to build a string with human readable data for several of the rusage
+/// fields. Note that we are focusing mainly on data that we believe to be
+/// supplied on Linux (the `rusage` struct has other fields in it but they are
+/// currently unsupported by Linux).
+fn format_rusage_data() -> Option<String> {
+    let rusage: libc::rusage = unsafe {
+        let mut recv = std::mem::zeroed();
+        // -1 is RUSAGE_CHILDREN, which means to get the rusage for all children
+        // (and grandchildren, etc) processes that have respectively terminated
+        // and been waited for.
+        let retval = libc::getrusage(-1, &mut recv);
+        if retval != 0 {
+            return None;
+        }
+        recv
+    };
+    // Mac OS X reports the maxrss in bytes, not kb.
+    let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
+    let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;
+
+    let mut init_str = format!(
+        "user: {USER_SEC}.{USER_USEC:03} \
+         sys: {SYS_SEC}.{SYS_USEC:03} \
+         max rss (kb): {MAXRSS}",
+        USER_SEC = rusage.ru_utime.tv_sec,
+        USER_USEC = rusage.ru_utime.tv_usec,
+        SYS_SEC = rusage.ru_stime.tv_sec,
+        SYS_USEC = rusage.ru_stime.tv_usec,
+        MAXRSS = maxrss
+    );
+
+    // The remaining rusage stats vary in platform support. So we treat
+    // uniformly zero values in each category as "not worth printing", since it
+    // either means no events of that type occurred, or that the platform
+    // does not support it.
+
+    let minflt = rusage.ru_minflt;
+    let majflt = rusage.ru_majflt;
+    if minflt != 0 || majflt != 0 {
+        init_str.push_str(&format!(" page reclaims: {} page faults: {}", minflt, majflt));
+    }
+
+    let inblock = rusage.ru_inblock;
+    let oublock = rusage.ru_oublock;
+    if inblock != 0 || oublock != 0 {
+        init_str.push_str(&format!(" fs block inputs: {} fs block outputs: {}", inblock, oublock));
+    }
+
+    let nvcsw = rusage.ru_nvcsw;
+    let nivcsw = rusage.ru_nivcsw;
+    if nvcsw != 0 || nivcsw != 0 {
+        init_str.push_str(&format!(
+            " voluntary ctxt switches: {} involuntary ctxt switches: {}",
+            nvcsw, nivcsw
+        ));
+    }
+
+    return Some(init_str);
+}