diff --git a/kernel/libs/xarray/src/lib.rs b/kernel/libs/xarray/src/lib.rs index 5743a734..0d07afdf 100644 --- a/kernel/libs/xarray/src/lib.rs +++ b/kernel/libs/xarray/src/lib.rs @@ -72,6 +72,9 @@ mod mark; mod node; mod range; +#[cfg(ktest)] +mod test; + const BITS_PER_LAYER: usize = 6; const SLOT_SIZE: usize = 1 << BITS_PER_LAYER; const SLOT_MASK: usize = SLOT_SIZE - 1; diff --git a/kernel/libs/xarray/src/test.rs b/kernel/libs/xarray/src/test.rs new file mode 100644 index 00000000..4cde9390 --- /dev/null +++ b/kernel/libs/xarray/src/test.rs @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: MPL-2.0 + +use alloc::{boxed::Box, sync::Arc}; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + +use ostd::{ + prelude::ktest, + task::{disable_preempt, Task}, +}; + +use super::*; + +macro_rules! n { + ( $x:expr ) => { + $x * 10 + }; +} + +fn init_continuous_with_arc(xarray: &XArray, M>, item_num: i32) { + for i in 0..item_num { + let value = Arc::new(i); + xarray.lock().store(i as u64, value); + } +} + +fn init_sparse_with_arc(xarray: &XArray, M>, item_num: i32) { + for i in 0..2 * item_num { + if i % 2 == 0 { + let value = Arc::new(i); + xarray.lock().store(i as u64, value); + } + } +} + +#[ktest] +fn store_continuous() { + let xarray_arc: XArray> = XArray::new(); + init_continuous_with_arc(&xarray_arc, n!(100)); + let guard = disable_preempt(); + for i in 0..n!(100) { + let value = xarray_arc.load(&guard, i as u64).unwrap(); + assert_eq!(*value.as_ref(), i); + } +} + +#[ktest] +fn store_sparse() { + let xarray_arc: XArray> = XArray::new(); + init_sparse_with_arc(&xarray_arc, n!(100)); + + let guard = disable_preempt(); + for i in 0..n!(100) { + if i % 2 == 0 { + let value = xarray_arc.load(&guard, i as u64).unwrap(); + assert_eq!(*value.as_ref(), i); + } + } +} + +#[ktest] +fn store_overwrite() { + let xarray_arc: XArray> = XArray::new(); + init_continuous_with_arc(&xarray_arc, n!(100)); + + let mut locked_xarray = xarray_arc.lock(); + // Overwrite 20 at index 10. + let value = Arc::new(20); + locked_xarray.store(10, value); + let v = locked_xarray.load(10).unwrap(); + assert_eq!(*v.as_ref(), 20); + // Overwrite 40 at index 10. + let value = Arc::new(40); + locked_xarray.store(10, value); + let v = locked_xarray.load(10).unwrap(); + assert_eq!(*v.as_ref(), 40); +} + +#[ktest] +fn remove() { + let xarray_arc: XArray> = XArray::new(); + assert!(xarray_arc.lock().remove(n!(1)).is_none()); + init_continuous_with_arc(&xarray_arc, n!(100)); + + let mut locked_xarray = xarray_arc.lock(); + for i in 0..n!(100) { + assert_eq!(*locked_xarray.remove(i as u64).unwrap().as_ref(), i); + let value = locked_xarray.load(i as u64); + assert!(value.is_none()); + assert!(locked_xarray.remove(i as u64).is_none()); + } +} + +#[ktest] +fn cursor_load() { + let xarray_arc: XArray> = XArray::new(); + init_continuous_with_arc(&xarray_arc, n!(100)); + + let guard = disable_preempt(); + let mut cursor = xarray_arc.cursor(&guard, 0); + + for i in 0..n!(100) { + let value = cursor.load().unwrap(); + assert_eq!(*value.as_ref(), i); + cursor.next(); + } + + cursor.reset_to(n!(200)); + assert!(cursor.load().is_none()); +} + +#[ktest] +fn cursor_load_very_sparse() { + let xarray_arc: XArray> = XArray::new(); + let mut locked_xarray = xarray_arc.lock(); + locked_xarray.store(0, Arc::new(1)); + locked_xarray.store(n!(100), Arc::new(2)); + + let mut cursor = locked_xarray.cursor(0); + assert_eq!(*cursor.load().unwrap().as_ref(), 1); + for _ in 0..n!(100) { + cursor.next(); + } + assert_eq!(*cursor.load().unwrap().as_ref(), 2); +} + +#[ktest] +fn cursor_store_continuous() { + let xarray_arc: XArray> = XArray::new(); + let mut locked_xarray = xarray_arc.lock(); + let mut cursor = locked_xarray.cursor_mut(0); + + for i in 0..n!(100) { + let value = Arc::new(i); + cursor.store(value); + cursor.next(); + } + + for i in 0..n!(100) { + let value = locked_xarray.load(i as u64).unwrap(); + assert_eq!(*value.as_ref(), i); + } +} + +#[ktest] +fn cursor_store_sparse() { + let xarray_arc: XArray> = XArray::new(); + let mut locked_xarray = xarray_arc.lock(); + let mut cursor = locked_xarray.cursor_mut(0); + + for i in 0..n!(100) { + if i % 2 == 0 { + let value = Arc::new(i); + cursor.store(value); + } + cursor.next(); + } + + for i in 0..n!(100) { + if i % 2 == 0 { + let value = locked_xarray.load(i as u64).unwrap(); + assert_eq!(*value.as_ref(), i); + } + } +} + +#[ktest] +fn set_mark() { + let xarray_arc: XArray, XMark> = XArray::new(); + init_continuous_with_arc(&xarray_arc, n!(100)); + + let mut locked_xarray = xarray_arc.lock(); + let mut cursor = locked_xarray.cursor_mut(n!(10)); + cursor.set_mark(XMark::Mark0).unwrap(); + cursor.set_mark(XMark::Mark1).unwrap(); + cursor.reset_to(n!(20)); + cursor.set_mark(XMark::Mark1).unwrap(); + + cursor.reset_to(n!(10)); + let value1_mark0 = cursor.is_marked(XMark::Mark0); + let value1_mark1 = cursor.is_marked(XMark::Mark1); + + cursor.reset_to(n!(20)); + let value2_mark0 = cursor.is_marked(XMark::Mark0); + let value2_mark1 = cursor.is_marked(XMark::Mark1); + + cursor.reset_to(n!(30)); + let value3_mark1 = cursor.is_marked(XMark::Mark1); + + assert!(value1_mark0); + assert!(value1_mark1); + assert!(!value2_mark0); + assert!(value2_mark1); + assert!(!value3_mark1); +} + +#[ktest] +fn unset_mark() { + let xarray_arc: XArray, XMark> = XArray::new(); + init_continuous_with_arc(&xarray_arc, n!(100)); + + let mut locked_xarray = xarray_arc.lock(); + let mut cursor = locked_xarray.cursor_mut(n!(10)); + cursor.set_mark(XMark::Mark0).unwrap(); + cursor.set_mark(XMark::Mark1).unwrap(); + + cursor.unset_mark(XMark::Mark0).unwrap(); + cursor.unset_mark(XMark::Mark2).unwrap(); + + let value1_mark0 = cursor.is_marked(XMark::Mark0); + let value1_mark2 = cursor.is_marked(XMark::Mark2); + assert!(!value1_mark0); + assert!(!value1_mark2); +} + +#[ktest] +fn mark_overflow() { + let xarray_arc: XArray, XMark> = XArray::new(); + init_continuous_with_arc(&xarray_arc, n!(100)); + let mut locked_xarray = xarray_arc.lock(); + let mut cursor = locked_xarray.cursor_mut(n!(200)); + + assert!(cursor.set_mark(XMark::Mark1).is_err()); + assert!(!cursor.is_marked(XMark::Mark1)); +} + +#[ktest] +fn box_operate() { + let xarray_box: XArray> = XArray::new(); + let mut locked_xarray = xarray_box.lock(); + let mut cursor_mut = locked_xarray.cursor_mut(0); + for i in 0..n!(100) { + if i % 2 == 0 { + cursor_mut.store(Box::new(i * 2)); + } + cursor_mut.next(); + } + + cursor_mut.reset_to(0); + for i in 0..n!(100) { + if i % 2 == 0 { + assert_eq!(*cursor_mut.load().unwrap().as_ref(), i * 2); + } else { + assert!(cursor_mut.load().is_none()); + } + cursor_mut.next(); + } + + let mut cursor = locked_xarray.cursor(0); + for i in 0..n!(100) { + if i % 2 == 0 { + assert_eq!(*cursor.load().unwrap().as_ref(), i * 2); + } else { + assert!(cursor.load().is_none()); + } + cursor.next(); + } +} + +#[ktest] +fn range() { + let xarray_arc: XArray> = XArray::new(); + for i in 0..n!(100) { + let value = Arc::new(i * 2); + xarray_arc.lock().store((i * 2) as u64, value); + } + + let mut count = 0; + let guard = disable_preempt(); + for (index, item) in xarray_arc.range(&guard, n!(10)..n!(20)) { + assert_eq!(*item.as_ref() as u64, index); + count += 1; + } + assert_eq!(count, n!(5)); +} + +#[ktest] +fn load_after_clear() { + let xarray_arc: XArray> = XArray::new(); + init_continuous_with_arc(&xarray_arc, n!(100)); + + let guard = disable_preempt(); + let mut cursor = xarray_arc.cursor(&guard, 100); + let mut locked_xarray = xarray_arc.lock(); + + let value = cursor.load().unwrap(); + assert_eq!(*value.as_ref(), 100); + + // Read the old data. + locked_xarray.clear(); + let value = cursor.load().unwrap(); + assert_eq!(*value.as_ref(), 100); + + // Read the new data. + cursor.reset(); + assert!(cursor.load().is_none()); +} + +static TEST_LEAKAGE: AtomicBool = AtomicBool::new(false); +static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); + +impl Drop for node::XNode

{ + fn drop(&mut self) { + if TEST_LEAKAGE.load(Ordering::Relaxed) { + DROP_COUNT.fetch_add(1, Ordering::Relaxed); + } + } +} + +#[ktest] +fn no_leakage() { + fn finish_grace_period() { + let task = || {}; + let _ = ostd::task::TaskOptions::new(task).data(()).spawn(); + Task::yield_now(); + } + + // Drop the nodes created by the previous tests. + finish_grace_period(); + TEST_LEAKAGE.store(true, Ordering::Relaxed); + + let xarray_arc: XArray> = XArray::new(); + init_sparse_with_arc(&xarray_arc, (SLOT_SIZE * SLOT_SIZE / 2 + 1) as i32); + drop(xarray_arc); + + // Drop the nodes created in the test. + finish_grace_period(); + TEST_LEAKAGE.store(false, Ordering::Relaxed); + + let count = DROP_COUNT.load(Ordering::Relaxed); + // layer 3: 1 + // layer 2: 1 + 1 + // layer 1: 64 + 1 + let expected = 68; + assert_eq!(count, expected); +}