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