Skip to main content

rumtk_arena/
lib.rs

1#![feature(allocator_api)]
2#![feature(slice_ptr_get)]
3#![feature(linked_list_retain)]
4#![feature(linked_list_cursors)]
5#![feature(portable_simd)]
6#![feature(str_as_str)]
7
8extern crate alloc;
9extern crate core;
10
11pub mod arena;
12pub mod constants;
13pub mod buffers;
14pub mod cpu;
15pub mod mem;
16pub mod dune;
17pub mod base;
18pub mod serde;
19
20pub use arena::Arena;
21pub use mem::*;
22
23#[cfg(test)]
24mod tests {
25    use crate::buffers::RUMBuffer;
26    use crate::constants::*;
27    use crate::cpu::{cpu_find, cpu_slice_to_array_padded};
28    use crate::{as_slice_mut, direct_alloc, rumtk_arena_new, Arena};
29    use std::alloc::{alloc, Layout};
30    use std::collections::{HashMap, VecDeque};
31
32    macro_rules! rumtk_benchmark_snippet {
33        ( $closure:expr ) => {{
34            use std::time::Instant;
35
36            let start = Instant::now();
37            let r = $closure();
38            let end = Instant::now();
39
40            let time = end - start;
41            let micros = time.as_micros();
42
43            (r, micros)
44        }};
45    }
46
47    #[test]
48    fn test_cpu_slice_to_array_padded() {
49        let expected = b"Hello World\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
50        let result = cpu_slice_to_array_padded::<32, 0>(b"Hello World");
51        assert_eq!(&result, expected, "Stack array was not properly padded!");
52    }
53
54    #[test]
55    fn test_cpu_slice_to_array_padded_newline() {
56        let expected = b"Hello World\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
57        let result = cpu_slice_to_array_padded::<32, b'\n'>(b"Hello World");
58        assert_eq!(&result, expected, "Stack array was not properly padded!");
59    }
60
61    #[test]
62    fn test_cpu_find_simd_aligned() {
63        let input = b"Hello World\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n00000000000000000000000000000000";
64        let expected = 6;
65        let result = cpu_find(input, b'W').unwrap();
66        assert_eq!(result, expected, "Failed to find needle in haystack!");
67    }
68
69    #[test]
70    fn test_cpu_find_simd_unaligned() {
71        let input = b"Hello World\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
72        let expected = 6;
73        let result = cpu_find(input, b'W').unwrap();
74        assert_eq!(result, expected, "Failed to find needle in haystack!");
75    }
76
77    #[test]
78    fn test_cpu_find_simd_unaligned_none() {
79        let input = b"Hello World\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
80        let expected = 6;
81        let result = cpu_find(input, b'\0');
82        assert!(result.is_none() || (result.unwrap() -1) < input.len(), "Succeeded to find needle in haystack when the search character is not part of the haystack!");
83    }
84
85    #[test]
86    fn test_arena_direct_allocation() {
87
88        let (r, time) = rumtk_benchmark_snippet!(|| {
89            unsafe { as_slice_mut(direct_alloc(DEFAULT_GLOBAL_MB_ALLOCATION), DEFAULT_GLOBAL_MB_ALLOCATION) }
90        });
91
92        assert_eq!(r.len(), DEFAULT_GLOBAL_MB_ALLOCATION);
93        assert!(time < 500, "Allocation took long! => {}us", time)
94
95    }
96
97    #[test]
98    fn test_arena_basic_allocation() {
99        let (r, time) = rumtk_benchmark_snippet!(|| {
100            unsafe { as_slice_mut(alloc(Layout::from_size_align_unchecked(DEFAULT_GLOBAL_MB_ALLOCATION, size_of::<u8>())), DEFAULT_GLOBAL_MB_ALLOCATION) }
101        });
102
103        assert_eq!(r.len(), DEFAULT_GLOBAL_MB_ALLOCATION);
104        assert!(time < 310, "Allocation took long! => {}us", time)
105
106    }
107
108    #[test]
109    fn test_arena_allocate_and_use() {
110        let (r, time) = rumtk_benchmark_snippet!(|| {
111            let slice = unsafe { as_slice_mut(alloc(Layout::from_size_align_unchecked(DEFAULT_GLOBAL_MB_ALLOCATION, size_of::<u8>())), DEFAULT_GLOBAL_MB_ALLOCATION) };
112            let v = slice.to_vec();
113            let mut buffer = RUMBuffer::from(v);
114            let mut chunk = buffer.freeze();
115
116            for _ in 0..(DEFAULT_GLOBAL_MB_ALLOCATION/5) {
117                chunk.split_to(5);
118            }
119
120            chunk
121        });
122
123        assert_eq!(r.len(), 0);
124        assert!(time < 200000, "Allocation took long!")
125
126    }
127
128    #[test]
129    fn test_arena_simple_vec_allocation() {
130        let arena = Arena::with_capacity(1024);
131        let mut v = Vec::<usize>::with_capacity(10);
132
133        v.push(10);
134        v.push(10);
135
136        assert_eq!(v, [10, 10], "Failed to allocate and fill a small vector!");
137    }
138
139    #[test]
140    fn test_arena_simple_vec_reallocation() {
141        let arena = Arena::with_capacity(1024);
142        let mut v = Vec::<usize>::with_capacity(1);
143
144        v.push(10);
145        v.push(10);
146
147        assert_eq!(v, [10, 10], "Failed to reallocate and fill a small vector!");
148    }
149
150    #[test]
151    fn test_arena_allocate_more_than_allowed() {
152        let mut arena = Arena::with_capacity(5);
153        let v = arena.commit(10);
154
155        assert!(v.is_err(), "Arena did not emit error upon allocation of byte count higher than current capacity.");
156    }
157
158    #[test]
159    fn test_arena_create_vec_with_macro() {
160        let arena = Arena::with_capacity(5);
161        let v: Vec<String> = vec![];
162
163        assert!(v.is_empty(), "Failed to create vector with arena allocation enabled.");
164    }
165
166    #[test]
167    fn test_arena_benchmark_arenavec_vs_vec() {
168        struct ptr {
169            data: usize,
170            len: usize,
171            index: usize,
172            bad: usize,
173        }
174
175        impl ptr {
176            pub fn new() -> Self {
177                Self {
178                    data: 0,
179                    len: 0,
180                    index: 0,
181                    bad: 0,
182                }
183            }
184        }
185
186        let total_items = 20000;
187
188        let (arena, arena_time) = rumtk_benchmark_snippet!(|| {
189            let total_bytes = (total_items * size_of::<ptr>()) + size_of::<Vec<ptr>>();
190            Arena::with_capacity(total_bytes)
191        });
192
193        let (arena_vec_r, arena_vec_time) = rumtk_benchmark_snippet!(|| {
194            let mut v: Vec<ptr> = vec![];
195
196            for _ in 0..total_items {
197                v.push(ptr::new());
198            }
199
200            v
201        });
202
203        let (vec_r, vec_time) = rumtk_benchmark_snippet!(|| {
204            let mut v = Vec::<ptr>::with_capacity(total_items);
205
206            for _ in 0..total_items {
207                v.push(ptr::new());
208            }
209
210            v
211        });
212
213        let total_arena_vec_time = arena_time + arena_vec_time;
214        println!("ArenaVec => {} us vs. Vec => {} us.", total_arena_vec_time, vec_time);
215
216        //assert!(total_arena_vec_time < vec_time, "ArenaVec is too slow. ArenaVec => {} us vs. Vec => {} us.", total_arena_vec_time, vec_time);
217    }
218
219    #[test]
220    fn test_arena_create_vec_with_macro_with_items() {
221        let arena = Arena::with_capacity(50);
222        let expected = &["Hello", "World", "!"];
223        let v: Vec<&str> = vec!["Hello", "World", "!"];
224
225        assert_eq!(v.as_slice(), expected, "Failed to create vector with arena allocation enabled and item slice.");
226    }
227
228    #[test]
229    fn test_arena_create_vecdeque_with_macro() {
230        let arena = Arena::with_capacity(5);
231        let v: VecDeque<String> = VecDeque::new();
232
233        assert!(v.is_empty(), "Failed to create vector with arena allocation enabled.");
234    }
235
236    #[test]
237    fn test_arena_create_vecdeque_with_macro_with_items() {
238        let arena = Arena::with_capacity(50);
239        let expected = ["Hello", "World", "!"];
240        let mut v: VecDeque<&str> = VecDeque::from(expected.clone());
241
242        assert_eq!(v.pop_front(), Some(expected[0]), "Failed to create queue with arena allocation enabled and item slice.");
243    }
244
245    #[test]
246    fn test_arena_create_hashmap_with_macro() {
247        let arena = Arena::with_capacity(5);
248        let v: HashMap<&str, &str> = HashMap::new();
249
250        assert!(v.is_empty(), "Failed to create vector with arena allocation enabled.");
251    }
252
253    #[test]
254    fn test_arena_create_hashmap_with_macro_with_items() {
255        let arena = Arena::with_capacity(120);
256        let expected = [(0, "Hello"), (1, "World"), (2, "!")];
257        let v: HashMap<usize, &str> = HashMap::from_iter(expected.clone());
258
259        assert_eq!(v[&0], expected[0].1, "Failed to create hashmap with arena allocation enabled and item slice.");
260    }
261
262    #[test]
263    fn test_arena_vec_debug_print() {
264        let arena = rumtk_arena_new!(500);
265        let mut test_vec = Vec::new();
266        let expected = ["Hello", "World", "!"];
267
268        for s in expected.iter() {
269            test_vec.push(s);
270        }
271
272        println!("{:?}", &test_vec);
273    }
274
275    #[test]
276    fn test_arena_map_debug_print() {
277        let expected = [(5, "Hello"), (1, "World"), (3, "!")];
278
279
280        let m = HashMap::<usize, &str>::from_iter(expected.clone());
281
282        for (k, v) in expected.iter() {
283            assert!(m.contains_key(k), "Key missing!");
284            assert_eq!(v, &m[k], "Contents mismatch!");
285        }
286    }
287}