From fa8d079c729dbf991ebc61049b49132488ea77f3 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 3 May 2022 12:45:20 +0200 Subject: [PATCH] it: run tests in parallel --- src/it.rs | 52 ++++++++++++++++++++++++++++++++++--------- src/it/tests.rs | 2 +- src/utils.rs | 1 + src/utils/num_cpus.rs | 21 +++++++++++++++++ 4 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 src/utils/num_cpus.rs diff --git a/src/it.rs b/src/it.rs index 4a552ff9..ae6ba474 100644 --- a/src/it.rs +++ b/src/it.rs @@ -6,17 +6,19 @@ use { testrun::TestRun, tests::TestCase, }, - utils::errorfmt::ErrorFmt, + utils::{errorfmt::ErrorFmt, num_cpus::num_cpus}, }, ahash::AHashMap, futures_util::{future, future::Either}, isnt::std_1::collections::IsntHashMapExt, log::Level, std::{ - cell::{Cell, RefCell}, + cell::Cell, + collections::VecDeque, future::pending, pin::Pin, rc::Rc, + sync::{Arc, Mutex}, time::SystemTime, }, uapi::c, @@ -37,23 +39,51 @@ mod test_utils; mod testrun; mod tests; +const SINGLE_THREAD: bool = false; + pub fn run_tests() { test_logger::install(); test_logger::set_level(Level::Trace); - let it_run = ItRun { + let it_run = Arc::new(ItRun { path: format!( "{}/testruns/{}", env!("CARGO_MANIFEST_DIR"), humantime::format_rfc3339_millis(SystemTime::now()) ), failed: Default::default(), - }; - for test in tests::tests() { - with_test_config(|cfg| { - run_test(&it_run, test, cfg); - }) + }); + if SINGLE_THREAD { + for test in tests::tests() { + 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() { let mut failed: Vec<_> = failed.iter().collect(); failed.sort_by_key(|f| f.0); @@ -70,7 +100,7 @@ pub fn run_tests() { struct ItRun { path: String, - failed: RefCell>>, + failed: Mutex>>, } fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc) { @@ -130,7 +160,7 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc) { for e in &errors { 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(); } diff --git a/src/it/tests.rs b/src/it/tests.rs index 6a1c7d04..8252a8a4 100644 --- a/src/it/tests.rs +++ b/src/it/tests.rs @@ -58,7 +58,7 @@ mod t0002_window; mod t0003_multi_window; mod t0004_quit; -pub trait TestCase { +pub trait TestCase: Sync { fn name(&self) -> &'static str; fn run(&self, testrun: Rc) -> Box>>; } diff --git a/src/utils.rs b/src/utils.rs index 95be0c4e..9f700ab8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -13,6 +13,7 @@ pub mod hex; pub mod linkedlist; pub mod log_on_drop; pub mod nonblock; +pub mod num_cpus; pub mod numcell; pub mod oserror; pub mod ptr_ext; diff --git a/src/utils/num_cpus.rs b/src/utils/num_cpus.rs new file mode 100644 index 00000000..8f4ffa08 --- /dev/null +++ b/src/utils/num_cpus.rs @@ -0,0 +1,21 @@ +use { + crate::utils::oserror::OsError, + smallvec::{smallvec_inline, SmallVec}, + uapi::{c, Errno}, +}; + +#[allow(dead_code)] +pub fn num_cpus() -> Result { + 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() +}