From 3ecd976c6a9dd9385ad2691ca419067da71450ae Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Thu, 28 Oct 2021 20:51:38 +0200 Subject: [PATCH] tools/api: Speed up fmt from 1min to 18s by writing to rustfmt stdin This reintroduces the "pipe Rust code through rustfmt before writing to disk" code from [#828] and yields a massive performance improvement for running in parallel over all files now, and not having to write, read, and write the same files over again. Unfortunately Rust's `Command` structure does not yet have proper support for forwarding stdout to a file (that's not unix-specific), though it could possibly be beneficial to write chunks read from stdout directly to a file instead of reading the whole lot into memory first. [#828]: https://github.com/microsoft/windows-rs/pull/828 --- crates/tools/api/src/main.rs | 29 +++++++++++++++++------------ src/Windows/Win32/Foundation/mod.rs | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/crates/tools/api/src/main.rs b/crates/tools/api/src/main.rs index 254621d874..d2eb59fa1f 100644 --- a/crates/tools/api/src/main.rs +++ b/crates/tools/api/src/main.rs @@ -24,17 +24,6 @@ fn main() { write_toml(&output, root); println!("Elapsed: {} ms", start.elapsed().as_millis()); - let start = std::time::Instant::now(); - - // rustfmt doesn't work reliably in parallel so have to run cargo fmt at the end, very slowly... - println!("\ncargo fmt..."); - let mut cmd = ::std::process::Command::new("cargo"); - output.pop(); - cmd.current_dir(output); - cmd.arg("fmt"); - cmd.output().unwrap(); - - println!("Elapsed: {} ms", start.elapsed().as_millis()); } fn write_toml(output: &std::path::Path, tree: &reader::TypeTree) { @@ -149,5 +138,21 @@ fn gen_tree(output: &std::path::Path, root: &'static str, tree: &reader::TypeTre path.push("mod.rs"); let tokens = gen::gen_source_file(root, tree); - std::fs::write(&path, tokens.into_string().as_bytes()).unwrap(); + + let mut child = std::process::Command::new("rustfmt") + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn() + .expect("Failed to spawn `rustfmt`"); + let mut stdin = child.stdin.take().expect("Failed to open stdin"); + stdin.write_all(tokens.into_string().as_bytes()).unwrap(); + drop(stdin); + + let output = child.wait_with_output().unwrap(); + assert!(output.status.success()); + std::fs::write( + &path, + String::from_utf8(output.stdout).expect("Failed to parse UTF-8"), + ) + .unwrap(); } diff --git a/src/Windows/Win32/Foundation/mod.rs b/src/Windows/Win32/Foundation/mod.rs index 909b06a36b..0908d3ba16 100644 --- a/src/Windows/Win32/Foundation/mod.rs +++ b/src/Windows/Win32/Foundation/mod.rs @@ -270,7 +270,7 @@ impl ::std::default::Default for BSTR { } impl ::std::fmt::Display for BSTR { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - use ::std::fmt::Write; + use std::fmt::Write; for c in ::std::char::decode_utf16(self.as_wide().iter().cloned()) { f.write_char(c.map_err(|_| ::std::fmt::Error)?)? }