diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 685494141..0b1e43deb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,6 +125,15 @@ jobs: - name: clippy run: ./ci/clippy.sh + # Run miri. + miri: + name: miri + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: miri + run: ./ci/miri.sh + # Run sanitizers. san: name: san @@ -174,6 +183,7 @@ jobs: - codegen - rustfmt - clippy + - miri - san - loom - docs diff --git a/ci/miri.sh b/ci/miri.sh new file mode 100755 index 000000000..52faef285 --- /dev/null +++ b/ci/miri.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +cd "$(dirname "$0")"/.. +set -ex + +toolchain=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) +rustup set profile minimal +rustup default "$toolchain" +rustup component add miri + +MIRIFLAGS="-Zmiri-tag-raw-pointers -Zmiri-disable-isolation" \ + cargo miri test \ + -p crossbeam-utils \ + -p crossbeam-queue + +# -Zmiri-ignore-leaks is needed because we use detached threads in tests/docs: https://github.com/rust-lang/miri/issues/1371 +# When enable -Zmiri-tag-raw-pointers, miri reports stacked borrows violation: https://github.com/crossbeam-rs/crossbeam/issues/762 +MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" \ + cargo miri test \ + -p crossbeam-channel + +# -Zmiri-ignore-leaks is needed for https://github.com/crossbeam-rs/crossbeam/issues/579 +# -Zmiri-disable-stacked-borrows is needed for https://github.com/crossbeam-rs/crossbeam/issues/545 +MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows" \ + cargo miri test \ + -p crossbeam-epoch \ + -p crossbeam-skiplist \ + -p crossbeam + +MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-compare-exchange-weak-failure-rate=1.0" \ + cargo miri test \ + -p crossbeam-deque diff --git a/crossbeam-channel/tests/after.rs b/crossbeam-channel/tests/after.rs index c6f6130d9..678a8c679 100644 --- a/crossbeam-channel/tests/after.rs +++ b/crossbeam-channel/tests/after.rs @@ -1,5 +1,7 @@ //! Tests for the after channel flavor. +#![cfg(not(miri))] // TODO: many assertions failed due to Miri is slow + use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use std::thread; diff --git a/crossbeam-channel/tests/array.rs b/crossbeam-channel/tests/array.rs index 2fed17541..bb2cebe88 100644 --- a/crossbeam-channel/tests/array.rs +++ b/crossbeam-channel/tests/array.rs @@ -1,5 +1,7 @@ //! Tests for the array channel flavor. +#![cfg(not(miri))] // TODO: many assertions failed due to Miri is slow + use std::any::Any; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/crossbeam-channel/tests/golang.rs b/crossbeam-channel/tests/golang.rs index afd07baf9..490795416 100644 --- a/crossbeam-channel/tests/golang.rs +++ b/crossbeam-channel/tests/golang.rs @@ -232,6 +232,9 @@ macro_rules! go { mod doubleselect { use super::*; + #[cfg(miri)] + const ITERATIONS: i32 = 100; + #[cfg(not(miri))] const ITERATIONS: i32 = 10_000; fn sender(n: i32, c1: Chan, c2: Chan, c3: Chan, c4: Chan) { @@ -691,6 +694,11 @@ mod select { mod select2 { use super::*; + #[cfg(miri)] + const N: i32 = 1000; + #[cfg(not(miri))] + const N: i32 = 100000; + #[test] fn main() { fn sender(c: &Chan, n: i32) { @@ -717,15 +725,18 @@ mod select2 { ALLOCATED.store(0, SeqCst); - go!(c, sender(&c, 100000)); - receiver(&c, &dummy, 100000); + go!(c, sender(&c, N)); + receiver(&c, &dummy, N); let alloc = ALLOCATED.load(SeqCst); - go!(c, sender(&c, 100000)); - receiver(&c, &dummy, 100000); + go!(c, sender(&c, N)); + receiver(&c, &dummy, N); - assert!(!(ALLOCATED.load(SeqCst) > alloc && (ALLOCATED.load(SeqCst) - alloc) > 110000)) + assert!( + !(ALLOCATED.load(SeqCst) > alloc + && (ALLOCATED.load(SeqCst) - alloc) > (N as usize + 10000)) + ) } } @@ -913,6 +924,9 @@ mod chan_test { #[test] fn test_chan() { + #[cfg(miri)] + const N: i32 = 20; + #[cfg(not(miri))] const N: i32 = 200; for cap in 0..N { @@ -1052,6 +1066,9 @@ mod chan_test { #[test] fn test_nonblock_recv_race() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] const N: usize = 1000; for _ in 0..N { @@ -1073,6 +1090,9 @@ mod chan_test { #[test] fn test_nonblock_select_race() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] const N: usize = 1000; let done = make::(1); @@ -1106,6 +1126,9 @@ mod chan_test { #[test] fn test_nonblock_select_race2() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] const N: usize = 1000; let done = make::(1); @@ -1142,6 +1165,11 @@ mod chan_test { // Ensure that send/recv on the same chan in select // does not crash nor deadlock. + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] + const N: usize = 1000; + for &cap in &[0, 10] { let wg = WaitGroup::new(); wg.add(2); @@ -1151,7 +1179,7 @@ mod chan_test { let p = p; go!(wg, p, c, { defer! { wg.done() } - for i in 0..1000 { + for i in 0..N { if p == 0 || i % 2 == 0 { select! { send(c.tx(), p) -> _ => {} @@ -1180,6 +1208,11 @@ mod chan_test { #[test] fn test_select_stress() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] + const N: usize = 10000; + let c = vec![ make::(0), make::(0), @@ -1187,8 +1220,6 @@ mod chan_test { make::(3), ]; - const N: usize = 10000; - // There are 4 goroutines that send N values on each of the chans, // + 4 goroutines that receive N values on each of the chans, // + 1 goroutine that sends N values on each of the chans in a single select, @@ -1286,6 +1317,9 @@ mod chan_test { #[test] fn test_select_fairness() { + #[cfg(miri)] + const TRIALS: usize = 100; + #[cfg(not(miri))] const TRIALS: usize = 10000; let c1 = make::(TRIALS + 1); @@ -1369,6 +1403,9 @@ mod chan_test { #[test] fn test_pseudo_random_send() { + #[cfg(miri)] + const N: usize = 20; + #[cfg(not(miri))] const N: usize = 100; for cap in 0..N { @@ -1412,6 +1449,9 @@ mod chan_test { #[test] fn test_multi_consumer() { const NWORK: usize = 23; + #[cfg(miri)] + const NITER: usize = 100; + #[cfg(not(miri))] const NITER: usize = 271828; let pn = [2, 3, 7, 11, 13, 17, 19, 23, 27, 31]; @@ -1510,6 +1550,9 @@ mod chan1 { use super::*; // sent messages + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] const N: usize = 1000; // receiving "goroutines" const M: usize = 10; diff --git a/crossbeam-channel/tests/list.rs b/crossbeam-channel/tests/list.rs index 6673e4b24..619e1fc50 100644 --- a/crossbeam-channel/tests/list.rs +++ b/crossbeam-channel/tests/list.rs @@ -239,6 +239,9 @@ fn disconnect_wakes_receiver() { #[test] fn spsc() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; let (s, r) = unbounded(); @@ -261,6 +264,9 @@ fn spsc() { #[test] fn mpmc() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; @@ -295,6 +301,9 @@ fn mpmc() { #[test] fn stress_oneshot() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; for _ in 0..COUNT { @@ -310,6 +319,9 @@ fn stress_oneshot() { #[test] fn stress_iter() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; let (request_s, request_r) = unbounded(); @@ -371,8 +383,11 @@ fn stress_timeout_two_threads() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn drops() { + const RUNS: usize = 100; + static DROPS: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, PartialEq)] @@ -386,7 +401,7 @@ fn drops() { let mut rng = thread_rng(); - for _ in 0..100 { + for _ in 0..RUNS { let steps = rng.gen_range(0..10_000); let additional = rng.gen_range(0..1000); @@ -421,6 +436,9 @@ fn drops() { #[test] fn linearizable() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; @@ -441,6 +459,9 @@ fn linearizable() { #[test] fn fairness() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = unbounded::<()>(); @@ -463,6 +484,9 @@ fn fairness() { #[test] fn fairness_duplicates() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s, r) = unbounded(); @@ -496,6 +520,9 @@ fn recv_in_send() { #[test] fn channel_through_channel() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 1000; type T = Box; diff --git a/crossbeam-channel/tests/mpsc.rs b/crossbeam-channel/tests/mpsc.rs index fc1cb2b0d..05089e469 100644 --- a/crossbeam-channel/tests/mpsc.rs +++ b/crossbeam-channel/tests/mpsc.rs @@ -176,7 +176,7 @@ macro_rules! select { ) => ({ cc::crossbeam_channel_internal! { $( - recv(($rx).inner) -> res => { + $meth(($rx).inner) -> res => { let $name = res.map_err(|_| ::std::sync::mpsc::RecvError); $code } @@ -314,13 +314,18 @@ mod channel_tests { #[test] fn stress() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] + const COUNT: usize = 10000; + let (tx, rx) = channel::(); let t = thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..COUNT { tx.send(1).unwrap(); } }); - for _ in 0..10000 { + for _ in 0..COUNT { assert_eq!(rx.recv().unwrap(), 1); } t.join().ok().unwrap(); @@ -328,6 +333,9 @@ mod channel_tests { #[test] fn stress_shared() { + #[cfg(miri)] + const AMT: u32 = 500; + #[cfg(not(miri))] const AMT: u32 = 10000; const NTHREADS: u32 = 8; let (tx, rx) = channel::(); @@ -735,12 +743,17 @@ mod channel_tests { #[test] fn recv_a_lot() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] + const N: usize = 10000; + // Regression test that we don't run out of stack in scheduler context let (tx, rx) = channel(); - for _ in 0..10000 { + for _ in 0..N { tx.send(()).unwrap(); } - for _ in 0..10000 { + for _ in 0..N { rx.recv().unwrap(); } } @@ -1079,13 +1092,18 @@ mod sync_channel_tests { #[test] fn stress() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] + const N: usize = 10000; + let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..N { tx.send(1).unwrap(); } }); - for _ in 0..10000 { + for _ in 0..N { assert_eq!(rx.recv().unwrap(), 1); } t.join().unwrap(); @@ -1093,10 +1111,15 @@ mod sync_channel_tests { #[test] fn stress_recv_timeout_two_threads() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] + const N: usize = 10000; + let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..N { tx.send(1).unwrap(); } }); @@ -1113,12 +1136,15 @@ mod sync_channel_tests { } } - assert_eq!(recv_count, 10000); + assert_eq!(recv_count, N); t.join().unwrap(); } #[test] fn stress_recv_timeout_shared() { + #[cfg(miri)] + const AMT: u32 = 100; + #[cfg(not(miri))] const AMT: u32 = 1000; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); @@ -1165,6 +1191,9 @@ mod sync_channel_tests { #[test] fn stress_shared() { + #[cfg(miri)] + const AMT: u32 = 100; + #[cfg(not(miri))] const AMT: u32 = 1000; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); @@ -1449,12 +1478,17 @@ mod sync_channel_tests { #[test] fn recv_a_lot() { + #[cfg(miri)] + const N: usize = 100; + #[cfg(not(miri))] + const N: usize = 10000; + // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = sync_channel(10000); - for _ in 0..10000 { + let (tx, rx) = sync_channel(N); + for _ in 0..N { tx.send(()).unwrap(); } - for _ in 0..10000 { + for _ in 0..N { rx.recv().unwrap(); } } @@ -1792,7 +1826,11 @@ mod select_tests { #[test] fn stress() { + #[cfg(miri)] + const AMT: i32 = 100; + #[cfg(not(miri))] const AMT: i32 = 10000; + let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); diff --git a/crossbeam-channel/tests/ready.rs b/crossbeam-channel/tests/ready.rs index 6779694a9..3a8807a1c 100644 --- a/crossbeam-channel/tests/ready.rs +++ b/crossbeam-channel/tests/ready.rs @@ -490,6 +490,9 @@ fn nesting() { #[test] fn stress_recv() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = unbounded(); @@ -527,6 +530,9 @@ fn stress_recv() { #[test] fn stress_send() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded(0); @@ -561,6 +567,9 @@ fn stress_send() { #[test] fn stress_mixed() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded(0); @@ -666,6 +675,9 @@ fn send_recv_same_channel() { #[test] fn channel_through_channel() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 1000; type T = Box; @@ -722,6 +734,9 @@ fn channel_through_channel() { #[test] fn fairness1() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded::<()>(COUNT); @@ -767,6 +782,9 @@ fn fairness1() { #[test] fn fairness2() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; let (s1, r1) = unbounded::<()>(); diff --git a/crossbeam-channel/tests/select.rs b/crossbeam-channel/tests/select.rs index dda54f059..7b4f00275 100644 --- a/crossbeam-channel/tests/select.rs +++ b/crossbeam-channel/tests/select.rs @@ -406,6 +406,7 @@ fn both_ready() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn loop_try() { const RUNS: usize = 20; @@ -690,6 +691,9 @@ fn nesting() { #[test] fn stress_recv() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = unbounded(); @@ -728,6 +732,9 @@ fn stress_recv() { #[test] fn stress_send() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded(0); @@ -763,6 +770,9 @@ fn stress_send() { #[test] fn stress_mixed() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded(0); @@ -940,6 +950,9 @@ fn matching_with_leftover() { #[test] fn channel_through_channel() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 1000; type T = Box; @@ -998,6 +1011,9 @@ fn channel_through_channel() { #[test] fn linearizable_try() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; for step in 0..2 { @@ -1050,6 +1066,9 @@ fn linearizable_try() { #[test] fn linearizable_timeout() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; for step in 0..2 { @@ -1102,6 +1121,9 @@ fn linearizable_timeout() { #[test] fn fairness1() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded::<()>(COUNT); @@ -1148,6 +1170,9 @@ fn fairness1() { #[test] fn fairness2() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = unbounded::<()>(); @@ -1264,6 +1289,9 @@ fn send_and_clone() { #[test] fn reuse() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded(0); diff --git a/crossbeam-channel/tests/select_macro.rs b/crossbeam-channel/tests/select_macro.rs index c05f7a0e6..571852a61 100644 --- a/crossbeam-channel/tests/select_macro.rs +++ b/crossbeam-channel/tests/select_macro.rs @@ -283,6 +283,7 @@ fn both_ready() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn loop_try() { const RUNS: usize = 20; @@ -485,6 +486,9 @@ fn panic_receiver() { #[test] fn stress_recv() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = unbounded(); @@ -518,6 +522,9 @@ fn stress_recv() { #[test] fn stress_send() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded(0); @@ -548,6 +555,9 @@ fn stress_send() { #[test] fn stress_mixed() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded(0); @@ -681,6 +691,9 @@ fn matching_with_leftover() { #[test] fn channel_through_channel() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 1000; type T = Box; @@ -726,6 +739,9 @@ fn channel_through_channel() { #[test] fn linearizable_default() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; for step in 0..2 { @@ -770,6 +786,9 @@ fn linearizable_default() { #[test] fn linearizable_timeout() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; for step in 0..2 { @@ -814,6 +833,9 @@ fn linearizable_timeout() { #[test] fn fairness1() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded::<()>(COUNT); @@ -838,6 +860,9 @@ fn fairness1() { #[test] fn fairness2() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = unbounded::<()>(); @@ -875,6 +900,9 @@ fn fairness2() { #[test] fn fairness_recv() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded::<()>(COUNT); @@ -897,6 +925,9 @@ fn fairness_recv() { #[test] fn fairness_send() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, _r1) = bounded::<()>(COUNT); diff --git a/crossbeam-channel/tests/thread_locals.rs b/crossbeam-channel/tests/thread_locals.rs index 9e27146df..effb6a143 100644 --- a/crossbeam-channel/tests/thread_locals.rs +++ b/crossbeam-channel/tests/thread_locals.rs @@ -1,5 +1,7 @@ //! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics. +#![cfg(not(miri))] // error: abnormal termination: the evaluated program aborted execution + use std::thread; use std::time::Duration; diff --git a/crossbeam-channel/tests/tick.rs b/crossbeam-channel/tests/tick.rs index ae59175a3..23bbb1f18 100644 --- a/crossbeam-channel/tests/tick.rs +++ b/crossbeam-channel/tests/tick.rs @@ -1,5 +1,7 @@ //! Tests for the tick channel flavor. +#![cfg(not(miri))] // TODO: many assertions failed due to Miri is slow + use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use std::thread; diff --git a/crossbeam-channel/tests/zero.rs b/crossbeam-channel/tests/zero.rs index 2adc1b244..ba41b1af5 100644 --- a/crossbeam-channel/tests/zero.rs +++ b/crossbeam-channel/tests/zero.rs @@ -187,6 +187,9 @@ fn send_timeout() { #[test] fn len() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 25_000; let (s, r) = bounded(0); @@ -249,6 +252,9 @@ fn disconnect_wakes_receiver() { #[test] fn spsc() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 100_000; let (s, r) = bounded(0); @@ -271,6 +277,9 @@ fn spsc() { #[test] fn mpmc() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; @@ -303,6 +312,9 @@ fn mpmc() { #[test] fn stress_oneshot() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; for _ in 0..COUNT { @@ -316,6 +328,7 @@ fn stress_oneshot() { } } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn stress_iter() { const COUNT: usize = 1000; @@ -383,8 +396,11 @@ fn stress_timeout_two_threads() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn drops() { + const RUNS: usize = 100; + static DROPS: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, PartialEq)] @@ -398,7 +414,7 @@ fn drops() { let mut rng = thread_rng(); - for _ in 0..100 { + for _ in 0..RUNS { let steps = rng.gen_range(0..3_000); DROPS.store(0, Ordering::SeqCst); @@ -428,6 +444,9 @@ fn drops() { #[test] fn fairness() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s1, r1) = bounded::<()>(0); @@ -459,6 +478,9 @@ fn fairness() { #[test] fn fairness_duplicates() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 10_000; let (s, r) = bounded::<()>(0); @@ -517,6 +539,9 @@ fn recv_in_send() { #[test] fn channel_through_channel() { + #[cfg(miri)] + const COUNT: usize = 100; + #[cfg(not(miri))] const COUNT: usize = 1000; type T = Box; diff --git a/crossbeam-deque/tests/fifo.rs b/crossbeam-deque/tests/fifo.rs index e2365fb91..7c18126c9 100644 --- a/crossbeam-deque/tests/fifo.rs +++ b/crossbeam-deque/tests/fifo.rs @@ -71,6 +71,9 @@ fn is_empty() { #[test] fn spsc() { + #[cfg(miri)] + const STEPS: usize = 500; + #[cfg(not(miri))] const STEPS: usize = 50_000; let w = Worker::new_fifo(); @@ -100,6 +103,9 @@ fn spsc() { #[test] fn stampede() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_fifo(); @@ -141,6 +147,9 @@ fn stampede() { #[test] fn stress() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_fifo(); @@ -197,6 +206,7 @@ fn stress() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn no_starvation() { const THREADS: usize = 8; @@ -256,6 +266,7 @@ fn no_starvation() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn destructors() { const THREADS: usize = 8; diff --git a/crossbeam-deque/tests/injector.rs b/crossbeam-deque/tests/injector.rs index 3f74d1bfb..bdcb630a3 100644 --- a/crossbeam-deque/tests/injector.rs +++ b/crossbeam-deque/tests/injector.rs @@ -46,6 +46,9 @@ fn is_empty() { #[test] fn spsc() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 100_000; let q = Injector::new(); @@ -73,6 +76,9 @@ fn spsc() { #[test] fn mpmc() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; @@ -111,6 +117,9 @@ fn mpmc() { #[test] fn stampede() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let q = Injector::new(); @@ -152,6 +161,9 @@ fn stampede() { #[test] fn stress() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let q = Injector::new(); @@ -208,6 +220,7 @@ fn stress() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn no_starvation() { const THREADS: usize = 8; @@ -267,6 +280,7 @@ fn no_starvation() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn destructors() { const THREADS: usize = 8; diff --git a/crossbeam-deque/tests/lifo.rs b/crossbeam-deque/tests/lifo.rs index 3e99e95c5..51d784058 100644 --- a/crossbeam-deque/tests/lifo.rs +++ b/crossbeam-deque/tests/lifo.rs @@ -71,6 +71,9 @@ fn is_empty() { #[test] fn spsc() { + #[cfg(miri)] + const STEPS: usize = 500; + #[cfg(not(miri))] const STEPS: usize = 50_000; let w = Worker::new_lifo(); @@ -100,6 +103,9 @@ fn spsc() { #[test] fn stampede() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_lifo(); @@ -141,6 +147,9 @@ fn stampede() { #[test] fn stress() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 50_000; let w = Worker::new_lifo(); @@ -197,6 +206,7 @@ fn stress() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn no_starvation() { const THREADS: usize = 8; @@ -256,6 +266,7 @@ fn no_starvation() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn destructors() { const THREADS: usize = 8; diff --git a/crossbeam-epoch/src/collector.rs b/crossbeam-epoch/src/collector.rs index 7cfb8192a..099a2ffc6 100644 --- a/crossbeam-epoch/src/collector.rs +++ b/crossbeam-epoch/src/collector.rs @@ -178,13 +178,18 @@ mod tests { #[test] fn pin_holds_advance() { + #[cfg(miri)] + const N: usize = 500; + #[cfg(not(miri))] + const N: usize = 500_000; + let collector = Collector::new(); thread::scope(|scope| { for _ in 0..NUM_THREADS { scope.spawn(|_| { let handle = collector.register(); - for _ in 0..500_000 { + for _ in 0..N { let guard = &handle.pin(); let before = collector.global.epoch.load(Ordering::Relaxed); @@ -202,6 +207,9 @@ mod tests { #[cfg(not(crossbeam_sanitize))] // TODO: assertions failed due to `cfg(crossbeam_sanitize)` reduce `internal::MAX_OBJECTS` #[test] fn incremental() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 100_000; static DESTROYS: AtomicUsize = AtomicUsize::new(0); @@ -230,12 +238,16 @@ mod tests { let guard = &handle.pin(); collector.global.collect(guard); } - assert!(DESTROYS.load(Ordering::Relaxed) == 100_000); + assert!(DESTROYS.load(Ordering::Relaxed) == COUNT); } #[test] fn buffering() { const COUNT: usize = 10; + #[cfg(miri)] + const N: usize = 500; + #[cfg(not(miri))] + const N: usize = 100_000; static DESTROYS: AtomicUsize = AtomicUsize::new(0); let collector = Collector::new(); @@ -252,7 +264,7 @@ mod tests { } } - for _ in 0..100_000 { + for _ in 0..N { collector.global.collect(&handle.pin()); } assert!(DESTROYS.load(Ordering::Relaxed) < COUNT); @@ -268,6 +280,9 @@ mod tests { #[test] fn count_drops() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 100_000; static DROPS: AtomicUsize = AtomicUsize::new(0); @@ -301,6 +316,9 @@ mod tests { #[test] fn count_destroy() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 100_000; static DESTROYS: AtomicUsize = AtomicUsize::new(0); @@ -367,6 +385,9 @@ mod tests { #[test] fn destroy_array() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 100_000; static DESTROYS: AtomicUsize = AtomicUsize::new(0); @@ -402,6 +423,9 @@ mod tests { #[test] fn stress() { const THREADS: usize = 8; + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 100_000; static DROPS: AtomicUsize = AtomicUsize::new(0); diff --git a/crossbeam-epoch/src/sync/queue.rs b/crossbeam-epoch/src/sync/queue.rs index 67c228de3..1722468c4 100644 --- a/crossbeam-epoch/src/sync/queue.rs +++ b/crossbeam-epoch/src/sync/queue.rs @@ -259,6 +259,9 @@ mod test { } } + #[cfg(miri)] + const CONC_COUNT: i64 = 1000; + #[cfg(not(miri))] const CONC_COUNT: i64 = 1000000; #[test] diff --git a/crossbeam-queue/tests/array_queue.rs b/crossbeam-queue/tests/array_queue.rs index b2467f9a7..9588ffafc 100644 --- a/crossbeam-queue/tests/array_queue.rs +++ b/crossbeam-queue/tests/array_queue.rs @@ -57,6 +57,7 @@ fn len_empty_full() { assert!(!q.is_full()); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn len() { const COUNT: usize = 25_000; @@ -114,6 +115,7 @@ fn len() { assert_eq!(q.len(), 0); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn spsc() { const COUNT: usize = 100_000; @@ -142,6 +144,7 @@ fn spsc() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn mpmc() { const COUNT: usize = 25_000; @@ -178,6 +181,7 @@ fn mpmc() { } } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn drops() { const RUNS: usize = 100; @@ -231,6 +235,9 @@ fn drops() { #[test] fn linearizable() { + #[cfg(miri)] + const COUNT: usize = 500; + #[cfg(not(miri))] const COUNT: usize = 25_000; const THREADS: usize = 4; diff --git a/crossbeam-queue/tests/seg_queue.rs b/crossbeam-queue/tests/seg_queue.rs index 642eb5ab1..1a1dcd562 100644 --- a/crossbeam-queue/tests/seg_queue.rs +++ b/crossbeam-queue/tests/seg_queue.rs @@ -52,6 +52,7 @@ fn len() { assert_eq!(q.len(), 0); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn spsc() { const COUNT: usize = 100_000; @@ -79,6 +80,7 @@ fn spsc() { .unwrap(); } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn mpmc() { const COUNT: usize = 25_000; @@ -115,8 +117,11 @@ fn mpmc() { } } +#[cfg_attr(miri, ignore)] // Miri is too slow #[test] fn drops() { + const RUNS: usize = 100; + static DROPS: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, PartialEq)] @@ -130,7 +135,7 @@ fn drops() { let mut rng = thread_rng(); - for _ in 0..100 { + for _ in 0..RUNS { let steps = rng.gen_range(0..10_000); let additional = rng.gen_range(0..1000); diff --git a/crossbeam-utils/src/sync/parker.rs b/crossbeam-utils/src/sync/parker.rs index aefa51527..531f5a5fc 100644 --- a/crossbeam-utils/src/sync/parker.rs +++ b/crossbeam-utils/src/sync/parker.rs @@ -175,6 +175,7 @@ impl Parker { /// /// let p = Parker::new(); /// let raw = Parker::into_raw(p); + /// # let _ = unsafe { Parker::from_raw(raw) }; /// ``` pub fn into_raw(this: Parker) -> *const () { Unparker::into_raw(this.unparker) @@ -258,6 +259,7 @@ impl Unparker { /// let p = Parker::new(); /// let u = p.unparker().clone(); /// let raw = Unparker::into_raw(u); + /// # let _ = unsafe { Unparker::from_raw(raw) }; /// ``` pub fn into_raw(this: Unparker) -> *const () { Arc::into_raw(this.inner) as *const () diff --git a/crossbeam-utils/tests/atomic_cell.rs b/crossbeam-utils/tests/atomic_cell.rs index 28208ee76..a065cabae 100644 --- a/crossbeam-utils/tests/atomic_cell.rs +++ b/crossbeam-utils/tests/atomic_cell.rs @@ -264,3 +264,21 @@ fn const_atomic_cell_new() { CELL.store(1); assert_eq!(CELL.load(), 1); } + +// https://github.com/crossbeam-rs/crossbeam/issues/748 +#[cfg_attr(miri, ignore)] // TODO +#[test] +fn issue_748() { + #[allow(dead_code)] + #[repr(align(8))] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + enum Test { + Field(u32), + FieldLess, + } + + assert_eq!(mem::size_of::(), 8); + assert!(AtomicCell::::is_lock_free()); + let x = AtomicCell::new(Test::FieldLess); + assert_eq!(x.load(), Test::FieldLess); +} diff --git a/crossbeam-utils/tests/sharded_lock.rs b/crossbeam-utils/tests/sharded_lock.rs index b46d64a76..ed50316e5 100644 --- a/crossbeam-utils/tests/sharded_lock.rs +++ b/crossbeam-utils/tests/sharded_lock.rs @@ -21,6 +21,9 @@ fn smoke() { #[test] fn frob() { const N: u32 = 10; + #[cfg(miri)] + const M: usize = 100; + #[cfg(not(miri))] const M: usize = 1000; let r = Arc::new(ShardedLock::new(()));