1
Fork 0

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.
This commit is contained in:
Ben Kimock 2022-07-26 17:40:48 -04:00
parent 4f9898a794
commit df6221adc6
10 changed files with 130 additions and 57 deletions

View file

@ -19,9 +19,11 @@ use tracing::debug;
use std::{iter, mem};
#[derive(Clone)]
struct Test {
span: Span,
ident: Ident,
name: Symbol,
}
struct TestCtxt<'a> {
@ -121,10 +123,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let mut item = i.into_inner();
if is_test_case(&self.cx.ext_cx.sess, &item) {
if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) {
debug!("this is a test item");
let test = Test { span: item.span, ident: item.ident };
let test = Test { span: item.span, ident: item.ident, name };
self.tests.push(test);
}
@ -355,9 +357,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
debug!("building test vector from {} tests", cx.test_cases.len());
let ecx = &cx.ext_cx;
let mut tests = cx.test_cases.clone();
tests.sort_by(|a, b| a.name.as_str().cmp(&b.name.as_str()));
ecx.expr_array_ref(
sp,
cx.test_cases
tests
.iter()
.map(|test| {
ecx.expr_addr_of(test.span, ecx.expr_path(ecx.path(test.span, vec![test.ident])))
@ -366,8 +371,8 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
)
}
fn is_test_case(sess: &Session, i: &ast::Item) -> bool {
sess.contains_name(&i.attrs, sym::rustc_test_marker)
fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> {
sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
}
fn get_test_runner(