Code change:
An showed that removing the dependency from LLVM speed up its test suite by a huge amount. For us libstd doesn't depend on directly but it does depend on which depends on (according to the blog post). Specificaly it looks like , the same function as LLVM, is used by us! It'd be great to investigate removing the shell32 dependency from libstd (may be a few other functions here and there). We should run some tests on Windows to see if this improves rustc cycle times!
Based on my limited investigation, it's likely that replacing with a pure Rust equivalent should be good enough to get rid of the gdi32 dependency in things that only use libstd. So really someone just needs to write that pure Rust implementation which should be easy to do.
It would be nice to get rid of this in the compiler too. We spawn a lot of compiler instances during bootstrapping.
So now that the change has been implemented, have we actually investigated how much of an impact the change made?
Perf, an lolbench are both linux only. So nether help with this question. So don't waste your time like I did.
Here are just number for on 8 cores / 16 threads on Windows 10 v1809: Without the dependency: 333.012 325.587 320.650 With : 310.852 319.165 323.645
For what it's worth, though there's no good way to differentiate PR-to-PR due to very high variance, it does look like there was a recent regression in PR build times: <img width="1409" alt="image" src="https://user-"
I see that the CPU usage averages about 40% when running , so maybe we'd see some real improvements if we got rid of in the compiler too. Something is certainly holding things back.
Yeah, I saw that the compiler doesn't load . So there's probably some other reason why doesn't load all the cores.

Related discussion:
text: } } <del> unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { let mut len = 0; while *ptr.offset(len) != 0 { len += 1; } // Push it onto the list. let ptr = ptr as *const u16; let buf = slice::from_raw_parts(ptr, len as usize); OsStringExt::from_wide(buf) } </del> impl Iterator for Args { type Item = OsString; <del> fn next(&mut self) -> Option<OsString> { self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) } fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() } </del> <ins> fn next(&mut self) -> Option<OsString> { self.parsed_args_list.next() } fn size_hint(&self) -> (usize, Option<usize>) { self.parsed_args_list.size_hint() } </ins> } impl DoubleEndedIterator for Args { <del> fn next_back(&mut self) -> Option<OsString> { self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) } </del> <ins> fn next_back(&mut self) -> Option<OsString> { self.parsed_args_list.next_back() } </ins> } impl ExactSizeIterator for Args { <del> fn len(&self) -> usize { self.range.len() } </del> <ins> fn len(&self) -> usize { self.parsed_args_list.len() } </ins> } <del> impl Drop for Args { fn drop(&mut self) { // self.cur can be null if CommandLineToArgvW previously failed, // but LocalFree ignores NULL pointers unsafe { c::LocalFree(self.cur as *mut c_void); } </del> <ins> #[cfg(test)] mod tests { use sys::windows::args::*; use ffi::OsString; fn chk(string: &str, parts: &[&str]) { let mut wide: Vec<u16> = OsString::from(string).encode_wide().collect(); wide.push(0); let parsed = unsafe { parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) }; let expected: Vec<OsString> = parts.iter().map(|k| OsString::from(k)).collect(); assert_eq!(parsed.as_slice(), expected.as_slice()); } #[test] fn empty() { chk("", &["TEST.EXE"]); chk("0", &["TEST.EXE"]); } #[test] fn single_words() { chk("EXE one_word", &["EXE", "one_word"]); chk("EXE a", &["EXE", "a"]); chk("EXE 😅", &["EXE", "😅"]); chk("EXE 😅🤦", &["EXE", "😅🤦"]); } #[test] fn official_examples() { chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]); chk(r#"EXE ab d"e f"g h"#, &["EXE", r#"ab"#, "de fg", "h"]); chk(r#"EXE a"b c d"#, &["EXE", r#"a"b"#, "c", "d"]); chk(r#"EXE a"b c" d e"#, &["EXE", r#"ab c"#, "d", "e"]); } #[test] fn whitespace_behavior() { chk(r#" test"#, &["", "test"]); chk(r#"  test"#, &["", "test"]); chk(r#" test test2"#, &["", "test", "test2"]); chk(r#" test  test2"#, &["", "test", "test2"]); chk(r#"test test2 "#, &["test", "test2"]); chk(r#"test  test2 "#, &["test", "test2"]); chk(r#"test "#, &["test"]); } #[test] fn genius_quotes() { chk(r#"EXE "" """#, &["EXE", "", ""]); chk(r#"EXE "" """"#, &["EXE", "", """]); chk( r#"EXE "this is """all""" in the same argument""#, &["EXE", "this is "all" in the same argument"] ); chk(r#"EXE "a"""#, &["EXE", "a""]); chk(r#"EXE "a"" a"#, &["EXE", "a"", "a"]); // quotes cannot be escaped in command names chk(r#""EXE" check"#, &["EXE", "check"]); chk(r#""EXE check""#, &["EXE check"]); chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]); chk(r#""EXE "for" check"#, &[r#"EXE "#, r#"for""#,  "check"]); </ins> } }