Skip to content

Commit 45888a5

Browse files
author
Yuki Okushi
authored
Rollup merge of #99939 - saethlin:pre-sort-tests, r=thomcc,jackh726
Sort tests at compile time, not at startup Recently, another Miri user was trying to run `cargo miri test` on the crate `iced-x86` with `--features=code_asm,mvex`. This configuration has a startup time of ~18 minutes. That's ~18 minutes before any tests even start to run. The fact that this crate has over 26,000 tests and Miri is slow makes a lot of code which is otherwise a bit sloppy but fine into a huge runtime issue. Sorting the tests when the test harness is created instead of at startup time knocks just under 4 minutes out of those ~18 minutes. I have ways to remove most of the rest of the startup time, but this change requires coordinating changes of both the compiler and libtest, so I'm sending it separately. (except for doctests, because there is no compile-time harness)
2 parents c887365 + 01550d2 commit 45888a5

File tree

3 files changed

+8
-38
lines changed

3 files changed

+8
-38
lines changed

test/src/console.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res
147147
let mut ntest = 0;
148148
let mut nbench = 0;
149149

150-
for test in filter_tests(&opts, tests) {
150+
for test in filter_tests(&opts, tests).into_iter() {
151151
use crate::TestFn::*;
152152

153153
let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;

test/src/lib.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -247,20 +247,20 @@ where
247247
let event = TestEvent::TeFiltered(filtered_descs, shuffle_seed);
248248
notify_about_test_event(event)?;
249249

250-
let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests
250+
let (mut filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests
251251
.into_iter()
252252
.enumerate()
253253
.map(|(i, e)| (TestId(i), e))
254254
.partition(|(_, e)| matches!(e.testfn, StaticTestFn(_) | DynTestFn(_)));
255255

256256
let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
257257

258-
let mut remaining = filtered_tests;
259258
if let Some(shuffle_seed) = shuffle_seed {
260-
shuffle_tests(shuffle_seed, &mut remaining);
261-
} else {
262-
remaining.reverse();
259+
shuffle_tests(shuffle_seed, &mut filtered_tests);
263260
}
261+
// Store the tests in a VecDeque so we can efficiently remove the first element to run the
262+
// tests in the order they were passed (unless shuffled).
263+
let mut remaining = VecDeque::from(filtered_tests);
264264
let mut pending = 0;
265265

266266
let (tx, rx) = channel::<CompletedTest>();
@@ -300,7 +300,7 @@ where
300300

301301
if concurrency == 1 {
302302
while !remaining.is_empty() {
303-
let (id, test) = remaining.pop().unwrap();
303+
let (id, test) = remaining.pop_front().unwrap();
304304
let event = TestEvent::TeWait(test.desc.clone());
305305
notify_about_test_event(event)?;
306306
let join_handle =
@@ -314,7 +314,7 @@ where
314314
} else {
315315
while pending > 0 || !remaining.is_empty() {
316316
while pending < concurrency && !remaining.is_empty() {
317-
let (id, test) = remaining.pop().unwrap();
317+
let (id, test) = remaining.pop_front().unwrap();
318318
let timeout = time::get_default_test_timeout();
319319
let desc = test.desc.clone();
320320

@@ -426,9 +426,6 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
426426
RunIgnored::No => {}
427427
}
428428

429-
// Sort the tests alphabetically
430-
filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
431-
432429
filtered
433430
}
434431

test/src/tests.rs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -610,33 +610,6 @@ fn sample_tests() -> Vec<TestDescAndFn> {
610610
tests
611611
}
612612

613-
#[test]
614-
pub fn sort_tests() {
615-
let mut opts = TestOpts::new();
616-
opts.run_tests = true;
617-
618-
let tests = sample_tests();
619-
let filtered = filter_tests(&opts, tests);
620-
621-
let expected = vec![
622-
"isize::test_pow".to_string(),
623-
"isize::test_to_str".to_string(),
624-
"sha1::test".to_string(),
625-
"test::do_not_run_ignored_tests".to_string(),
626-
"test::filter_for_ignored_option".to_string(),
627-
"test::first_free_arg_should_be_a_filter".to_string(),
628-
"test::ignored_tests_result_in_ignored".to_string(),
629-
"test::parse_ignored_flag".to_string(),
630-
"test::parse_include_ignored_flag".to_string(),
631-
"test::run_include_ignored_option".to_string(),
632-
"test::sort_tests".to_string(),
633-
];
634-
635-
for (a, b) in expected.iter().zip(filtered) {
636-
assert_eq!(*a, b.desc.name.to_string());
637-
}
638-
}
639-
640613
#[test]
641614
pub fn shuffle_tests() {
642615
let mut opts = TestOpts::new();

0 commit comments

Comments
 (0)