1
0
Fork 0
forked from wry/wry

it: run tests in parallel

This commit is contained in:
Julian Orth 2022-05-03 12:45:20 +02:00
parent 09d9f2ccbb
commit fa8d079c72
4 changed files with 64 additions and 12 deletions

View file

@ -6,17 +6,19 @@ use {
testrun::TestRun, testrun::TestRun,
tests::TestCase, tests::TestCase,
}, },
utils::errorfmt::ErrorFmt, utils::{errorfmt::ErrorFmt, num_cpus::num_cpus},
}, },
ahash::AHashMap, ahash::AHashMap,
futures_util::{future, future::Either}, futures_util::{future, future::Either},
isnt::std_1::collections::IsntHashMapExt, isnt::std_1::collections::IsntHashMapExt,
log::Level, log::Level,
std::{ std::{
cell::{Cell, RefCell}, cell::Cell,
collections::VecDeque,
future::pending, future::pending,
pin::Pin, pin::Pin,
rc::Rc, rc::Rc,
sync::{Arc, Mutex},
time::SystemTime, time::SystemTime,
}, },
uapi::c, uapi::c,
@ -37,23 +39,51 @@ mod test_utils;
mod testrun; mod testrun;
mod tests; mod tests;
const SINGLE_THREAD: bool = false;
pub fn run_tests() { pub fn run_tests() {
test_logger::install(); test_logger::install();
test_logger::set_level(Level::Trace); test_logger::set_level(Level::Trace);
let it_run = ItRun { let it_run = Arc::new(ItRun {
path: format!( path: format!(
"{}/testruns/{}", "{}/testruns/{}",
env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_DIR"),
humantime::format_rfc3339_millis(SystemTime::now()) humantime::format_rfc3339_millis(SystemTime::now())
), ),
failed: Default::default(), failed: Default::default(),
}; });
for test in tests::tests() { if SINGLE_THREAD {
with_test_config(|cfg| { for test in tests::tests() {
run_test(&it_run, test, cfg); with_test_config(|cfg| {
}) run_test(&it_run, test, cfg);
})
}
} else {
let queue = Arc::new(Mutex::new(VecDeque::from_iter(tests::tests())));
let mut threads = vec![];
let num_cpus = match num_cpus() {
Ok(n) => n,
Err(e) => fatal!("Could not determine the number of cpus: {}", ErrorFmt(e)),
};
log::info!("Running {} tests in parallel", num_cpus);
for _ in 0..num_cpus {
let queue = queue.clone();
let it_run = it_run.clone();
threads.push(std::thread::spawn(move || loop {
let test = match queue.lock().unwrap().pop_front() {
Some(t) => t,
_ => break,
};
with_test_config(|cfg| {
run_test(&it_run, test, cfg);
})
}));
}
for thread in threads {
thread.join().unwrap();
}
} }
let failed = it_run.failed.borrow_mut(); let failed = it_run.failed.lock().unwrap();
if failed.is_not_empty() { if failed.is_not_empty() {
let mut failed: Vec<_> = failed.iter().collect(); let mut failed: Vec<_> = failed.iter().collect();
failed.sort_by_key(|f| f.0); failed.sort_by_key(|f| f.0);
@ -70,7 +100,7 @@ pub fn run_tests() {
struct ItRun { struct ItRun {
path: String, path: String,
failed: RefCell<AHashMap<&'static str, Vec<String>>>, failed: Mutex<AHashMap<&'static str, Vec<String>>>,
} }
fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc<TestConfig>) { fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc<TestConfig>) {
@ -130,7 +160,7 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc<TestConfig>) {
for e in &errors { for e in &errors {
log::error!(" {}", e); log::error!(" {}", e);
} }
it_run.failed.borrow_mut().insert(test.name(), errors); it_run.failed.lock().unwrap().insert(test.name(), errors);
} }
test_logger::unset_file(); test_logger::unset_file();
} }

View file

@ -58,7 +58,7 @@ mod t0002_window;
mod t0003_multi_window; mod t0003_multi_window;
mod t0004_quit; mod t0004_quit;
pub trait TestCase { pub trait TestCase: Sync {
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
fn run(&self, testrun: Rc<TestRun>) -> Box<dyn Future<Output = Result<(), TestError>>>; fn run(&self, testrun: Rc<TestRun>) -> Box<dyn Future<Output = Result<(), TestError>>>;
} }

View file

@ -13,6 +13,7 @@ pub mod hex;
pub mod linkedlist; pub mod linkedlist;
pub mod log_on_drop; pub mod log_on_drop;
pub mod nonblock; pub mod nonblock;
pub mod num_cpus;
pub mod numcell; pub mod numcell;
pub mod oserror; pub mod oserror;
pub mod ptr_ext; pub mod ptr_ext;

21
src/utils/num_cpus.rs Normal file
View file

@ -0,0 +1,21 @@
use {
crate::utils::oserror::OsError,
smallvec::{smallvec_inline, SmallVec},
uapi::{c, Errno},
};
#[allow(dead_code)]
pub fn num_cpus() -> Result<u32, OsError> {
let mut buf: SmallVec<[usize; 32]> = smallvec_inline![0; 32];
loop {
match uapi::sched_getaffinity(0, &mut buf) {
Ok(_) => return Ok(count(&buf)),
Err(Errno(c::EINVAL)) => buf.extend_from_slice(&[0; 32][..]),
Err(e) => return Err(e.into()),
}
}
}
fn count(buf: &[usize]) -> u32 {
buf.iter().copied().map(|n| n.count_ones()).sum()
}