Browse Source

chore(ci): split loom tests into separate CI jobs (#10)

This lets different groups of loom tests run in parallel, which might
make CI runs faster.
Eliza Weisman 3 years ago
parent
commit
e27852dd63
9 changed files with 108 additions and 19 deletions
  1. 84 0
      .github/workflows/loom.yml
  2. 1 3
      .github/workflows/tests.yml
  3. 6 1
      Cargo.toml
  4. 4 4
      src/lib.rs
  5. 4 2
      src/loom.rs
  6. 1 1
      src/mpsc.rs
  7. 1 1
      src/thingbuf.rs
  8. 4 4
      src/util.rs
  9. 3 3
      src/util/wait/wait_cell.rs

+ 84 - 0
.github/workflows/loom.yml

@@ -0,0 +1,84 @@
+on:
+ - push
+ - pull_request
+ - workflow_dispatch
+
+name: Loom Models
+
+env:
+  LOOM_MAX_PREEMPTIONS: 2
+  LOOM_LOG: loom=trace
+  RUSTFLAGS: "--cfg loom"
+
+jobs:
+  loom_mpsc_async:
+    name: "mpsc"
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Install stable toolchain
+        uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+          components: rustfmt
+      - name: Run cargo test
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --profile loom --lib -- mpsc_async
+
+  loom_mpsc_sync:
+    name: "mpsc::sync"
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Install stable toolchain
+        uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+          components: rustfmt
+      - name: Run cargo test
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --profile loom --lib -- mpsc_sync
+
+  loom_thingbuf:
+    name: "ThingBuf"
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Install stable toolchain
+        uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+          components: rustfmt
+      - name: Run cargo test
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --profile loom --lib -- thingbuf
+
+  loom_util:
+    name: "util"
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Install stable toolchain
+        uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+          components: rustfmt
+      - name: Run cargo test
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+          args: --profile loom --lib -- util

+ 1 - 3
.github/workflows/tests.yml

@@ -19,6 +19,4 @@ jobs:
       - name: Run cargo test
         uses: actions-rs/cargo@v1
         with:
-          command: test
-        env:
-          LOOM_MAX_PREEMPTIONS: 2
+          command: test

+ 6 - 1
Cargo.toml

@@ -24,8 +24,13 @@ crossbeam = "0.8.1"
 tokio = { version = "1.14.0", features = ["rt", "rt-multi-thread", "sync", "macros"] }
 async-std = "1"
 
-[profile.test]
+# Custom profile for Loom tests: enable release optimizations so that the loom
+# tests are less slow, but don't disable debug assertions.
+[profile.loom]
+inherits = "test"
+lto = true
 opt-level = 3
+
 [[bench]]
 name = "sync_mpsc"
 harness = false

+ 4 - 4
src/lib.rs

@@ -56,7 +56,7 @@ struct Slot<T> {
 }
 
 impl Core {
-    #[cfg(not(test))]
+    #[cfg(not(all(loom, test)))]
     const fn new(capacity: usize) -> Self {
         let closed = (capacity + 1).next_power_of_two();
         let idx_mask = closed - 1;
@@ -73,7 +73,7 @@ impl Core {
         }
     }
 
-    #[cfg(test)]
+    #[cfg(all(loom, test))]
     fn new(capacity: usize) -> Self {
         let closed = (capacity + 1).next_power_of_two();
         let idx_mask = closed - 1;
@@ -377,7 +377,7 @@ impl<T: fmt::Write> fmt::Write for Ref<'_, T> {
 const EMPTY_STATE: usize = usize::MAX;
 
 impl<T> Slot<T> {
-    #[cfg(not(test))]
+    #[cfg(not(all(loom, test)))]
     const fn empty() -> Self {
         Self {
             value: UnsafeCell::new(MaybeUninit::uninit()),
@@ -385,7 +385,7 @@ impl<T> Slot<T> {
         }
     }
 
-    #[cfg(test)]
+    #[cfg(all(loom, test))]
     fn empty() -> Self {
         Self {
             value: UnsafeCell::new(MaybeUninit::uninit()),

+ 4 - 2
src/loom.rs

@@ -1,6 +1,6 @@
 pub(crate) use self::inner::*;
 
-#[cfg(test)]
+#[cfg(all(test, loom))]
 mod inner {
 
     pub(crate) mod atomic {
@@ -105,6 +105,7 @@ mod inner {
         // wrap the loom model with `catch_unwind` to avoid potentially losing
         // test output on double panics.
         let current_iteration = std::sync::Arc::new(AtomicUsize::new(1));
+        let iteration = current_iteration.clone();
         let test_name = match std::thread::current().name() {
             Some("main") | None => "test".to_string(),
             Some(name) => name.to_string(),
@@ -121,6 +122,7 @@ mod inner {
             // next iteration...
             TRACE_BUF.with(|buf| buf.borrow_mut().clear());
         });
+        print!("({} iterations) ", iteration.load(Ordering::Relaxed));
     }
 
     #[track_caller]
@@ -178,7 +180,7 @@ mod inner {
     }
 }
 
-#[cfg(not(test))]
+#[cfg(not(all(loom, test)))]
 mod inner {
     #![allow(dead_code)]
     pub(crate) mod sync {

+ 1 - 1
src/mpsc.rs

@@ -357,5 +357,5 @@ feature! {
     pub mod sync;
 }
 
-#[cfg(test)]
+#[cfg(all(loom, test))]
 mod tests;

+ 1 - 1
src/thingbuf.rs

@@ -3,7 +3,7 @@ use crate::{Core, Full, Ref, Slot};
 use alloc::boxed::Box;
 use core::{fmt, ptr};
 
-#[cfg(test)]
+#[cfg(all(loom, test))]
 mod tests;
 
 pub struct ThingBuf<T> {

+ 4 - 4
src/util.rs

@@ -30,12 +30,12 @@ impl Backoff {
 
     #[inline]
     pub(crate) fn spin(&mut self) {
-        #[cfg(not(test))]
+        #[cfg(not(all(loom, test)))]
         for _ in 0..test_dbg!(1 << self.0.min(Self::MAX_SPINS)) {
             loom::hint::spin_loop();
         }
 
-        #[cfg(test)]
+        #[cfg(all(loom, test))]
         {
             test_println!("hint::spin_loop() (x{})", 1 << self.0.min(Self::MAX_SPINS));
             loom::hint::spin_loop();
@@ -49,7 +49,7 @@ impl Backoff {
     #[inline]
     pub(crate) fn spin_yield(&mut self) {
         if self.0 <= Self::MAX_SPINS || cfg!(not(any(feature = "std", test))) {
-            #[cfg(not(test))]
+            #[cfg(not(all(loom, test)))]
             for _ in 0..1 << self.0 {
                 loom::hint::spin_loop();
             }
@@ -58,7 +58,7 @@ impl Backoff {
         }
 
         test_println!("thread::yield_now()");
-        #[cfg(any(test, feature = "std"))]
+        #[cfg(any(all(loom, test), feature = "std"))]
         loom::thread::yield_now();
 
         if self.0 <= Self::MAX_YIELDS {

+ 3 - 3
src/util/wait/wait_cell.rs

@@ -38,7 +38,7 @@ struct State(usize);
 
 // === impl WaitCell ===
 impl<T> WaitCell<T> {
-    #[cfg(not(test))]
+    #[cfg(not(all(loom, test)))]
     pub(crate) const fn new() -> Self {
         Self {
             lock: AtomicUsize::new(State::WAITING.0),
@@ -46,7 +46,7 @@ impl<T> WaitCell<T> {
         }
     }
 
-    #[cfg(test)]
+    #[cfg(all(loom, test))]
     pub(crate) fn new() -> Self {
         Self {
             lock: AtomicUsize::new(State::WAITING.0),
@@ -260,7 +260,7 @@ impl fmt::Debug for State {
         Ok(())
     }
 }
-#[cfg(test)]
+#[cfg(all(loom, test))]
 mod tests {
     use super::*;
     use crate::loom::{