diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b4c5ca60c..d628b2091 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -100,6 +100,17 @@ jobs: run: sudo apt-get install libopenblas-dev gfortran - run: ./scripts/blas-integ-tests.sh "$FEATURES" 1.67.0 + miri: + runs-on: ubuntu-latest + name: miri + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + components: miri + - uses: Swatinem/rust-cache@v2 + - run: ./scripts/miri-tests.sh + cross_test: #if: ${{ github.event_name == 'merge_group' }} runs-on: ubuntu-latest @@ -161,6 +172,7 @@ jobs: - format # should format be required? - nostd - tests + - miri - cross_test - cargo-careful - docs diff --git a/crates/serialization-tests/tests/serialize.rs b/crates/serialization-tests/tests/serialize.rs index 6e6fb4d64..478eb20ef 100644 --- a/crates/serialization-tests/tests/serialize.rs +++ b/crates/serialization-tests/tests/serialize.rs @@ -45,13 +45,13 @@ fn serial_many_dim_serde() { // Test a sliced array. - let mut a = ArcArray::linspace(0., 31., 32) + let mut a = ArcArray::from_iter(0..32) .into_shape_with_order((2, 2, 2, 4)) .unwrap(); a.slice_collapse(s![..;-1, .., .., ..2]); let serial = serde_json::to_string(&a).unwrap(); println!("Encode {:?} => {:?}", a, serial); - let res = serde_json::from_str::>(&serial); + let res = serde_json::from_str::>(&serial); println!("{:?}", res); assert_eq!(a, res.unwrap()); } @@ -160,7 +160,7 @@ fn serial_many_dim_serde_msgpack() { // Test a sliced array. - let mut a = ArcArray::linspace(0., 31., 32) + let mut a = ArcArray::from_iter(0..32) .into_shape_with_order((2, 2, 2, 4)) .unwrap(); a.slice_collapse(s![..;-1, .., .., ..2]); @@ -171,7 +171,7 @@ fn serial_many_dim_serde_msgpack() .unwrap(); let mut deserializer = rmp_serde::Deserializer::new(&buf[..]); - let a_de: ArcArray = serde::Deserialize::deserialize(&mut deserializer).unwrap(); + let a_de: ArcArray = serde::Deserialize::deserialize(&mut deserializer).unwrap(); assert_eq!(a, a_de); } @@ -215,14 +215,14 @@ fn serial_many_dim_ron() { // Test a sliced array. - let mut a = ArcArray::linspace(0., 31., 32) + let mut a = ArcArray::from_iter(0..32) .into_shape_with_order((2, 2, 2, 4)) .unwrap(); a.slice_collapse(s![..;-1, .., .., ..2]); let a_s = ron_serialize(&a).unwrap(); - let a_de: ArcArray = ron_deserialize(&a_s).unwrap(); + let a_de: ArcArray = ron_deserialize(&a_s).unwrap(); assert_eq!(a, a_de); } diff --git a/ndarray-rand/tests/tests.rs b/ndarray-rand/tests/tests.rs index 2db040310..e39347c0c 100644 --- a/ndarray-rand/tests/tests.rs +++ b/ndarray-rand/tests/tests.rs @@ -57,6 +57,7 @@ fn oversampling_without_replacement_should_panic() } quickcheck! { + #[cfg_attr(miri, ignore)] // Takes an insufferably long time fn oversampling_with_replacement_is_fine(m: u8, n: u8) -> TestResult { let (m, n) = (m as usize, n as usize); let a = Array::random((m, n), Uniform::new(0., 2.)); @@ -86,6 +87,7 @@ quickcheck! { #[cfg(feature = "quickcheck")] quickcheck! { + #[cfg_attr(miri, ignore)] // This takes *forever* with Miri fn sampling_behaves_as_expected(m: u8, n: u8, strategy: SamplingStrategy) -> TestResult { let (m, n) = (m as usize, n as usize); let a = Array::random((m, n), Uniform::new(0., 2.)); diff --git a/scripts/all-tests.sh b/scripts/all-tests.sh index 01dd9abc0..e15c57983 100755 --- a/scripts/all-tests.sh +++ b/scripts/all-tests.sh @@ -13,6 +13,8 @@ cargo build -v --no-default-features # ndarray with no features cargo test -p ndarray -v --no-default-features +# ndarray with no_std-compatible features +cargo test -p ndarray -v --no-default-features --features approx # all with features cargo test -v --features "$FEATURES" $QC_FEAT # all with features and release (ignore test crates which is already optimized) diff --git a/scripts/miri-tests.sh b/scripts/miri-tests.sh new file mode 100755 index 000000000..0100f3e6a --- /dev/null +++ b/scripts/miri-tests.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -x +set -e + +# We rely on layout-dependent casts, which should be covered with #[repr(transparent)] +# This should catch if we missed that +RUSTFLAGS="-Zrandomize-layout" + +# Miri reports a stacked borrow violation deep within rayon, in a crate called crossbeam-epoch +# The crate has a PR to fix this: https://github.com/crossbeam-rs/crossbeam/pull/871 +# but using Miri's tree borrow mode may resolve it for now. +# Disabled until we can figure out a different rayon issue: https://github.com/rust-lang/miri/issues/1371 +# MIRIFLAGS="-Zmiri-tree-borrows" + +# General tests +# Note that we exclude blas feature because Miri can't do cblas_gemm +cargo miri test -v -p ndarray -p ndarray-rand --features approx,serde diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 601f0dc43..eb07252b2 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -1020,6 +1020,7 @@ mod test } quickcheck! { + #[cfg_attr(miri, ignore)] // Very slow on CI/CD machines // FIXME: This test is extremely slow, even with i16 values, investigate fn arith_seq_intersect_correct( first1: i8, len1: i8, step1: i8, diff --git a/tests/array.rs b/tests/array.rs index 696904dab..ac38fdd03 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -2629,6 +2629,7 @@ mod array_cow_tests }); } + #[cfg_attr(miri, ignore)] // Very slow on CI/CD machines #[test] fn test_clone_from() { diff --git a/tests/azip.rs b/tests/azip.rs index a4bb6ffac..96be9d913 100644 --- a/tests/azip.rs +++ b/tests/azip.rs @@ -216,7 +216,7 @@ fn test_azip2_sum() } #[test] -#[cfg(feature = "approx")] +#[cfg(all(feature = "approx", feature = "std"))] fn test_azip3_slices() { use approx::assert_abs_diff_eq; @@ -232,7 +232,7 @@ fn test_azip3_slices() *a += b / 10.; *c = a.sin(); }); - let res = Array::linspace(0., 3.1, 32).mapv_into(f32::sin); + let res = Array::from_iter(0..32).mapv(|x| f32::sin(x as f32 / 10.)); assert_abs_diff_eq!(res, ArrayView::from(&c), epsilon = 1e-4); } diff --git a/tests/dimension.rs b/tests/dimension.rs index 6a9207e4c..fe53d96b3 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -323,6 +323,7 @@ fn test_array_view() } #[test] +#[cfg_attr(miri, ignore)] // Very slow on CI/CD machines #[cfg(feature = "std")] #[allow(clippy::cognitive_complexity)] fn test_all_ndindex() diff --git a/tests/iterators.rs b/tests/iterators.rs index 908b64d15..bdfd3ee50 100644 --- a/tests/iterators.rs +++ b/tests/iterators.rs @@ -971,6 +971,7 @@ fn test_into_iter_2d() assert_eq!(v, [1, 3, 2, 4]); } +#[cfg_attr(miri, ignore)] // Very slow on CI/CD machines #[test] fn test_into_iter_sliced() { diff --git a/tests/numeric.rs b/tests/numeric.rs index 2395366b0..839aba58e 100644 --- a/tests/numeric.rs +++ b/tests/numeric.rs @@ -163,6 +163,7 @@ fn std_empty_arr() #[test] #[cfg(feature = "approx")] +#[cfg(feature = "std")] fn var_axis() { use ndarray::{aview0, aview2}; @@ -222,6 +223,7 @@ fn var_axis() #[test] #[cfg(feature = "approx")] +#[cfg(feature = "std")] fn std_axis() { use ndarray::aview2; diff --git a/tests/oper.rs b/tests/oper.rs index 5e3e669d0..401913e2b 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -502,6 +502,7 @@ fn scaled_add() } #[cfg(feature = "approx")] +#[cfg_attr(miri, ignore)] // Very slow on CI/CD machines #[test] fn scaled_add_2() { @@ -540,6 +541,7 @@ fn scaled_add_2() } #[cfg(feature = "approx")] +#[cfg_attr(miri, ignore)] // Very slow on CI/CD machines #[test] fn scaled_add_3() { @@ -592,6 +594,7 @@ fn scaled_add_3() } #[cfg(feature = "approx")] +#[cfg_attr(miri, ignore)] #[test] fn gen_mat_mul() { @@ -681,6 +684,7 @@ fn gen_mat_mul_i32() #[cfg(feature = "approx")] #[test] +#[cfg_attr(miri, ignore)] // Takes too long fn gen_mat_vec_mul() { use approx::assert_relative_eq; @@ -746,6 +750,7 @@ fn gen_mat_vec_mul() } #[cfg(feature = "approx")] +#[cfg_attr(miri, ignore)] // Very slow on CI/CD machines #[test] fn vec_mat_mul() {