Skip to content

Commit cf08eda

Browse files
authored
Rollup merge of #105829 - the8472:tidy-style, r=jyn514
Speed up tidy This can be reviewed commit by commit since they contain separate optimizations. ``` # master $ taskset -c 0-5 hyperfine './x test tidy' Benchmark #1: ./x test tidy Time (mean ± σ): 4.857 s ± 0.064 s [User: 12.967 s, System: 2.014 s] Range (min … max): 4.779 s … 4.997 s 10 runs # PR $ taskset -c 0-5 hyperfine './x test tidy' Benchmark #1: ./x test tidy Time (mean ± σ): 3.672 s ± 0.035 s [User: 10.524 s, System: 2.029 s] Range (min … max): 3.610 s … 3.725 s 10 runs ```
2 parents eaf2f26 + ab7d769 commit cf08eda

File tree

3 files changed

+70
-34
lines changed

3 files changed

+70
-34
lines changed

src/bootstrap/format.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::path::{Path, PathBuf};
88
use std::process::{Command, Stdio};
99
use std::sync::mpsc::SyncSender;
1010

11-
fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut() {
11+
fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool {
1212
let mut cmd = Command::new(&rustfmt);
1313
// avoid the submodule config paths from coming into play,
1414
// we only allow a single global config for the workspace for now
@@ -23,7 +23,13 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
2323
let cmd_debug = format!("{:?}", cmd);
2424
let mut cmd = cmd.spawn().expect("running rustfmt");
2525
// poor man's async: return a closure that'll wait for rustfmt's completion
26-
move || {
26+
move |block: bool| -> bool {
27+
if !block {
28+
match cmd.try_wait() {
29+
Ok(Some(_)) => {}
30+
_ => return false,
31+
}
32+
}
2733
let status = cmd.wait().unwrap();
2834
if !status.success() {
2935
eprintln!(
@@ -34,6 +40,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
3440
);
3541
crate::detail_exit(1);
3642
}
43+
true
3744
}
3845
}
3946

@@ -146,15 +153,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
146153
let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check);
147154
children.push_back(child);
148155

156+
// poll completion before waiting
157+
for i in (0..children.len()).rev() {
158+
if children[i](false) {
159+
children.swap_remove_back(i);
160+
break;
161+
}
162+
}
163+
149164
if children.len() >= max_processes {
150165
// await oldest child
151-
children.pop_front().unwrap()();
166+
children.pop_front().unwrap()(true);
152167
}
153168
}
154169

155170
// await remaining children
156171
for mut child in children {
157-
child();
172+
child(true);
158173
}
159174
});
160175

src/tools/tidy/src/main.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,26 @@ fn main() {
3535

3636
let bad = std::sync::Arc::new(AtomicBool::new(false));
3737

38+
let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
39+
// poll all threads for completion before awaiting the oldest one
40+
for i in (0..handles.len()).rev() {
41+
if handles[i].is_finished() {
42+
handles.swap_remove_back(i).unwrap().join().unwrap();
43+
}
44+
}
45+
46+
while handles.len() >= concurrency.get() {
47+
handles.pop_front().unwrap().join().unwrap();
48+
}
49+
};
50+
3851
scope(|s| {
3952
let mut handles: VecDeque<ScopedJoinHandle<'_, ()>> =
4053
VecDeque::with_capacity(concurrency.get());
4154

4255
macro_rules! check {
4356
($p:ident $(, $args:expr)* ) => {
44-
while handles.len() >= concurrency.get() {
45-
handles.pop_front().unwrap().join().unwrap();
46-
}
57+
drain_handles(&mut handles);
4758

4859
let handle = s.spawn(|| {
4960
let mut flag = false;
@@ -97,9 +108,8 @@ fn main() {
97108
check!(alphabetical, &library_path);
98109

99110
let collected = {
100-
while handles.len() >= concurrency.get() {
101-
handles.pop_front().unwrap().join().unwrap();
102-
}
111+
drain_handles(&mut handles);
112+
103113
let mut flag = false;
104114
let r = features::check(&src_path, &compiler_path, &library_path, &mut flag, verbose);
105115
if flag {

src/tools/tidy/src/style.rs

+35-24
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! `// ignore-tidy-CHECK-NAME`.
1818
1919
use crate::walk::{filter_dirs, walk};
20-
use regex::Regex;
20+
use regex::{Regex, RegexSet};
2121
use std::path::Path;
2222

2323
/// Error code markdown is restricted to 80 columns because they can be
@@ -225,6 +225,7 @@ pub fn check(path: &Path, bad: &mut bool) {
225225
.chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v)))
226226
.chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v)))
227227
.collect();
228+
let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
228229
walk(path, &mut skip, &mut |entry, contents| {
229230
let file = entry.path();
230231
let filename = file.file_name().unwrap().to_string_lossy();
@@ -281,7 +282,27 @@ pub fn check(path: &Path, bad: &mut bool) {
281282
let mut trailing_new_lines = 0;
282283
let mut lines = 0;
283284
let mut last_safety_comment = false;
285+
let is_test = file.components().any(|c| c.as_os_str() == "tests");
286+
// scanning the whole file for multiple needles at once is more efficient than
287+
// executing lines times needles separate searches.
288+
let any_problematic_line = problematic_regex.is_match(contents);
284289
for (i, line) in contents.split('\n').enumerate() {
290+
if line.is_empty() {
291+
if i == 0 {
292+
leading_new_lines = true;
293+
}
294+
trailing_new_lines += 1;
295+
continue;
296+
} else {
297+
trailing_new_lines = 0;
298+
}
299+
300+
let trimmed = line.trim();
301+
302+
if !trimmed.starts_with("//") {
303+
lines += 1;
304+
}
305+
285306
let mut err = |msg: &str| {
286307
tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
287308
};
@@ -308,36 +329,38 @@ pub fn check(path: &Path, bad: &mut bool) {
308329
suppressible_tidy_err!(err, skip_cr, "CR character");
309330
}
310331
if filename != "style.rs" {
311-
if line.contains("TODO") {
332+
if trimmed.contains("TODO") {
312333
err("TODO is deprecated; use FIXME")
313334
}
314-
if line.contains("//") && line.contains(" XXX") {
335+
if trimmed.contains("//") && trimmed.contains(" XXX") {
315336
err("XXX is deprecated; use FIXME")
316337
}
317-
for s in problematic_consts_strings.iter() {
318-
if line.contains(s) {
319-
err("Don't use magic numbers that spell things (consider 0x12345678)");
338+
if any_problematic_line {
339+
for s in problematic_consts_strings.iter() {
340+
if trimmed.contains(s) {
341+
err("Don't use magic numbers that spell things (consider 0x12345678)");
342+
}
320343
}
321344
}
322345
}
323-
let is_test = || file.components().any(|c| c.as_os_str() == "tests");
324346
// for now we just check libcore
325-
if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment {
326-
if file.components().any(|c| c.as_os_str() == "core") && !is_test() {
347+
if trimmed.contains("unsafe {") && !trimmed.starts_with("//") && !last_safety_comment {
348+
if file.components().any(|c| c.as_os_str() == "core") && !is_test {
327349
suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
328350
}
329351
}
330-
if line.contains("// SAFETY:") {
352+
if trimmed.contains("// SAFETY:") {
331353
last_safety_comment = true;
332-
} else if line.trim().starts_with("//") || line.trim().is_empty() {
354+
} else if trimmed.starts_with("//") || trimmed.is_empty() {
333355
// keep previous value
334356
} else {
335357
last_safety_comment = false;
336358
}
337359
if (line.starts_with("// Copyright")
338360
|| line.starts_with("# Copyright")
339361
|| line.starts_with("Copyright"))
340-
&& (line.contains("Rust Developers") || line.contains("Rust Project Developers"))
362+
&& (trimmed.contains("Rust Developers")
363+
|| trimmed.contains("Rust Project Developers"))
341364
{
342365
suppressible_tidy_err!(
343366
err,
@@ -351,18 +374,6 @@ pub fn check(path: &Path, bad: &mut bool) {
351374
if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
352375
err(LLVM_UNREACHABLE_INFO);
353376
}
354-
if line.is_empty() {
355-
if i == 0 {
356-
leading_new_lines = true;
357-
}
358-
trailing_new_lines += 1;
359-
} else {
360-
trailing_new_lines = 0;
361-
}
362-
363-
if !line.trim().starts_with("//") {
364-
lines += 1;
365-
}
366377
}
367378
if leading_new_lines {
368379
let mut err = |_| {

0 commit comments

Comments
 (0)