From 8c718bd3f657003f603ea6d4435f8d83752f0751 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 4 Mar 2021 10:43:24 +0100 Subject: [PATCH 1/3] Attempt to gather similar stats as rusage on Windows --- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/bin/rustc.rs | 72 +++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e04128d1b0b..c14ad6fa5ff 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -53,7 +53,7 @@ merge = "0.1.0" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" -features = ["fileapi", "ioapiset", "jobapi2", "handleapi", "winioctl"] +features = ["fileapi", "ioapiset", "jobapi2", "handleapi", "winioctl", "psapi", "impl-default"] [dev-dependencies] pretty_assertions = "0.6" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 6b1be0ca09d..fb9f21bfd3c 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -156,9 +156,11 @@ fn main() { } let start = Instant::now(); - let status = { + let (child, status) = { let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd); - cmd.status().expect(&errmsg) + let mut child = cmd.spawn().expect(&errmsg); + let status = child.wait().expect(&errmsg); + (child, status) }; if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() @@ -169,8 +171,19 @@ fn main() { 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()); + let rusage_data = env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| { + #[cfg(windows)] + { + use std::os::windows::io::AsRawHandle; + let handle = child.as_raw_handle(); + format_rusage_data(handle) + } + #[cfg(not(windows))] + { + let _child = child; + format_rusage_data() + } + }); eprintln!( "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}", crate_name, @@ -207,13 +220,62 @@ fn main() { } } -#[cfg(not(unix))] +#[cfg(all(not(unix), not(windows)))] /// 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 { None } +#[cfg(windows)] +fn format_rusage_data(handle: std::os::windows::raw::HANDLE) -> Option { + macro_rules! try_bool { + ($e:expr) => { + if $e != 1 { + return None; + } + }; + } + unsafe { + let mut _filetime = winapi::shared::minwindef::FILETIME::default(); + let mut user_filetime = winapi::shared::minwindef::FILETIME::default(); + let mut kernel_filetime = winapi::shared::minwindef::FILETIME::default(); + try_bool!(winapi::um::processthreadsapi::GetProcessTimes( + handle, + &mut _filetime, + &mut _filetime, + &mut kernel_filetime, + &mut user_filetime, + )); + let mut memory_counters = winapi::um::psapi::PROCESS_MEMORY_COUNTERS_EX::default(); + try_bool!(winapi::um::psapi::GetProcessMemoryInfo( + handle as _, + &mut memory_counters as *mut _ as _, + std::mem::size_of::() as u32, + )); + let mut user_time = winapi::um::minwinbase::SYSTEMTIME::default(); + try_bool!(winapi::um::timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time)); + let mut kernel_time = winapi::um::minwinbase::SYSTEMTIME::default(); + try_bool!(winapi::um::timezoneapi::FileTimeToSystemTime( + &kernel_filetime, + &mut kernel_time + )); + let maxrss = memory_counters.PeakWorkingSetSize / 1024; + Some(format!( + "user: {USER_SEC}.{USER_USEC:03} \ + sys: {SYS_SEC}.{SYS_USEC:03} \ + max rss (kb): {MAXRSS} \ + page faults: {PAGE_FAULTS}", + USER_SEC = user_time.wSecond + (user_time.wMinute * 60), + USER_USEC = user_time.wMilliseconds, + SYS_SEC = kernel_time.wSecond + (kernel_time.wMinute * 60), + SYS_USEC = kernel_time.wMilliseconds, + MAXRSS = maxrss, + PAGE_FAULTS = memory_counters.PageFaultCount, + )) + } +} + #[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 From 0201e2bbde001aced41352d5437028a915e5556e Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 5 Mar 2021 14:38:52 +0100 Subject: [PATCH 2/3] Add more windows specific numbers --- src/bootstrap/bin/rustc.rs | 72 +++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index fb9f21bfd3c..97cea74fc53 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -229,6 +229,7 @@ fn format_rusage_data() -> Option { #[cfg(windows)] fn format_rusage_data(handle: std::os::windows::raw::HANDLE) -> Option { + use winapi::um::{processthreadsapi, psapi, timezoneapi}; macro_rules! try_bool { ($e:expr) => { if $e != 1 { @@ -236,44 +237,57 @@ fn format_rusage_data(handle: std::os::windows::raw::HANDLE) -> Option { } }; } + + let mut user_filetime = Default::default(); + let mut user_time = Default::default(); + let mut kernel_filetime = Default::default(); + let mut kernel_time = Default::default(); + let mut memory_counters = psapi::PROCESS_MEMORY_COUNTERS::default(); + unsafe { - let mut _filetime = winapi::shared::minwindef::FILETIME::default(); - let mut user_filetime = winapi::shared::minwindef::FILETIME::default(); - let mut kernel_filetime = winapi::shared::minwindef::FILETIME::default(); - try_bool!(winapi::um::processthreadsapi::GetProcessTimes( + try_bool!(processthreadsapi::GetProcessTimes( handle, - &mut _filetime, - &mut _filetime, + &mut Default::default(), + &mut Default::default(), &mut kernel_filetime, &mut user_filetime, )); - let mut memory_counters = winapi::um::psapi::PROCESS_MEMORY_COUNTERS_EX::default(); - try_bool!(winapi::um::psapi::GetProcessMemoryInfo( + try_bool!(timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time)); + try_bool!(timezoneapi::FileTimeToSystemTime(&kernel_filetime, &mut kernel_time)); + + // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process + // with the given handle and none of that process's children. + try_bool!(psapi::GetProcessMemoryInfo( handle as _, &mut memory_counters as *mut _ as _, - std::mem::size_of::() as u32, + std::mem::size_of::() as u32, )); - let mut user_time = winapi::um::minwinbase::SYSTEMTIME::default(); - try_bool!(winapi::um::timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time)); - let mut kernel_time = winapi::um::minwinbase::SYSTEMTIME::default(); - try_bool!(winapi::um::timezoneapi::FileTimeToSystemTime( - &kernel_filetime, - &mut kernel_time - )); - let maxrss = memory_counters.PeakWorkingSetSize / 1024; - Some(format!( - "user: {USER_SEC}.{USER_USEC:03} \ - sys: {SYS_SEC}.{SYS_USEC:03} \ - max rss (kb): {MAXRSS} \ - page faults: {PAGE_FAULTS}", - USER_SEC = user_time.wSecond + (user_time.wMinute * 60), - USER_USEC = user_time.wMilliseconds, - SYS_SEC = kernel_time.wSecond + (kernel_time.wMinute * 60), - SYS_USEC = kernel_time.wMilliseconds, - MAXRSS = maxrss, - PAGE_FAULTS = memory_counters.PageFaultCount, - )) } + + // Guide on interpreting these numbers: + // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information + let peak_working_set = memory_counters.PeakWorkingSetSize / 1024; + let peak_page_file = memory_counters.PeakPagefileUsage / 1024; + let peak_paged_pool = memory_counters.QuotaPeakPagedPoolUsage / 1024; + let peak_nonpaged_pool = memory_counters.QuotaPeakNonPagedPoolUsage / 1024; + Some(format!( + "user: {USER_SEC}.{USER_USEC:03} \ + sys: {SYS_SEC}.{SYS_USEC:03} \ + peak working set (kb): {PEAK_WORKING_SET} \ + peak page file usage (kb): {PEAK_PAGE_FILE} \ + peak paged pool usage (kb): {PEAK_PAGED_POOL} \ + peak non-paged pool usage (kb): {PEAK_NONPAGED_POOL} \ + page faults: {PAGE_FAULTS}", + USER_SEC = user_time.wSecond + (user_time.wMinute * 60), + USER_USEC = user_time.wMilliseconds, + SYS_SEC = kernel_time.wSecond + (kernel_time.wMinute * 60), + SYS_USEC = kernel_time.wMilliseconds, + PEAK_WORKING_SET = peak_working_set, + PEAK_PAGE_FILE = peak_page_file, + PEAK_PAGED_POOL = peak_paged_pool, + PEAK_NONPAGED_POOL = peak_nonpaged_pool, + PAGE_FAULTS = memory_counters.PageFaultCount, + )) } #[cfg(unix)] From 302867cf48db284cc666fff7c2953f6f94f30aac Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 11 Mar 2021 16:23:25 +0100 Subject: [PATCH 3/3] Clean up handling of child process --- src/bootstrap/bin/rustc.rs | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 97cea74fc53..269f810192e 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -17,7 +17,7 @@ use std::env; use std::path::PathBuf; -use std::process::Command; +use std::process::{Child, Command}; use std::str::FromStr; use std::time::Instant; @@ -171,19 +171,8 @@ fn main() { 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(|_| { - #[cfg(windows)] - { - use std::os::windows::io::AsRawHandle; - let handle = child.as_raw_handle(); - format_rusage_data(handle) - } - #[cfg(not(windows))] - { - let _child = child; - format_rusage_data() - } - }); + let rusage_data = + env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data(child)); eprintln!( "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}", crate_name, @@ -221,15 +210,16 @@ fn main() { } #[cfg(all(not(unix), not(windows)))] -/// 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 { +// In the future we can add this for more platforms +fn format_rusage_data(_child: Child) -> Option { None } #[cfg(windows)] -fn format_rusage_data(handle: std::os::windows::raw::HANDLE) -> Option { +fn format_rusage_data(child: Child) -> Option { + use std::os::windows::io::AsRawHandle; use winapi::um::{processthreadsapi, psapi, timezoneapi}; + let handle = child.as_raw_handle(); macro_rules! try_bool { ($e:expr) => { if $e != 1 { @@ -295,7 +285,7 @@ fn format_rusage_data(handle: std::os::windows::raw::HANDLE) -> Option { /// 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 { +fn format_rusage_data(_child: Child) -> Option { let rusage: libc::rusage = unsafe { let mut recv = std::mem::zeroed(); // -1 is RUSAGE_CHILDREN, which means to get the rusage for all children