]>
Commit | Line | Data |
---|---|---|
dc9dc135 | 1 | extern crate test; |
dc9dc135 XL |
2 | use super::TypedArena; |
3 | use std::cell::Cell; | |
dfeec247 | 4 | use test::Bencher; |
dc9dc135 XL |
5 | |
6 | #[allow(dead_code)] | |
7 | #[derive(Debug, Eq, PartialEq)] | |
8 | struct Point { | |
9 | x: i32, | |
10 | y: i32, | |
11 | z: i32, | |
12 | } | |
13 | ||
6a06907d XL |
14 | impl<T> TypedArena<T> { |
15 | /// Clears the arena. Deallocates all but the longest chunk which may be reused. | |
16 | fn clear(&mut self) { | |
17 | unsafe { | |
18 | // Clear the last chunk, which is partially filled. | |
19 | let mut chunks_borrow = self.chunks.borrow_mut(); | |
20 | if let Some(mut last_chunk) = chunks_borrow.last_mut() { | |
21 | self.clear_last_chunk(&mut last_chunk); | |
22 | let len = chunks_borrow.len(); | |
23 | // If `T` is ZST, code below has no effect. | |
24 | for mut chunk in chunks_borrow.drain(..len - 1) { | |
25 | chunk.destroy(chunk.entries); | |
26 | } | |
27 | } | |
28 | } | |
29 | } | |
30 | } | |
31 | ||
dc9dc135 XL |
32 | #[test] |
33 | pub fn test_unused() { | |
34 | let arena: TypedArena<Point> = TypedArena::default(); | |
35 | assert!(arena.chunks.borrow().is_empty()); | |
36 | } | |
37 | ||
38 | #[test] | |
39 | fn test_arena_alloc_nested() { | |
40 | struct Inner { | |
41 | value: u8, | |
42 | } | |
43 | struct Outer<'a> { | |
44 | inner: &'a Inner, | |
45 | } | |
46 | enum EI<'e> { | |
47 | I(Inner), | |
48 | O(Outer<'e>), | |
49 | } | |
50 | ||
51 | struct Wrap<'a>(TypedArena<EI<'a>>); | |
52 | ||
53 | impl<'a> Wrap<'a> { | |
54 | fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner { | |
487cf647 FG |
55 | match self.0.alloc(EI::I(f())) { |
56 | EI::I(i) => i, | |
57 | _ => panic!("mismatch"), | |
dc9dc135 XL |
58 | } |
59 | } | |
60 | fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer<'_> { | |
487cf647 FG |
61 | match self.0.alloc(EI::O(f())) { |
62 | EI::O(o) => o, | |
63 | _ => panic!("mismatch"), | |
dc9dc135 XL |
64 | } |
65 | } | |
66 | } | |
67 | ||
68 | let arena = Wrap(TypedArena::default()); | |
69 | ||
dfeec247 | 70 | let result = arena.alloc_outer(|| Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }); |
dc9dc135 XL |
71 | |
72 | assert_eq!(result.inner.value, 10); | |
73 | } | |
74 | ||
75 | #[test] | |
76 | pub fn test_copy() { | |
77 | let arena = TypedArena::default(); | |
064997fb FG |
78 | #[cfg(not(miri))] |
79 | const N: usize = 100000; | |
80 | #[cfg(miri)] | |
81 | const N: usize = 1000; | |
82 | for _ in 0..N { | |
dc9dc135 XL |
83 | arena.alloc(Point { x: 1, y: 2, z: 3 }); |
84 | } | |
85 | } | |
86 | ||
87 | #[bench] | |
88 | pub fn bench_copy(b: &mut Bencher) { | |
89 | let arena = TypedArena::default(); | |
90 | b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 })) | |
91 | } | |
92 | ||
93 | #[bench] | |
94 | pub fn bench_copy_nonarena(b: &mut Bencher) { | |
95 | b.iter(|| { | |
96 | let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 }); | |
97 | }) | |
98 | } | |
99 | ||
100 | #[allow(dead_code)] | |
101 | struct Noncopy { | |
102 | string: String, | |
103 | array: Vec<i32>, | |
104 | } | |
105 | ||
106 | #[test] | |
107 | pub fn test_noncopy() { | |
108 | let arena = TypedArena::default(); | |
064997fb FG |
109 | #[cfg(not(miri))] |
110 | const N: usize = 100000; | |
111 | #[cfg(miri)] | |
112 | const N: usize = 1000; | |
113 | for _ in 0..N { | |
dfeec247 | 114 | arena.alloc(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }); |
dc9dc135 XL |
115 | } |
116 | } | |
117 | ||
118 | #[test] | |
119 | pub fn test_typed_arena_zero_sized() { | |
120 | let arena = TypedArena::default(); | |
064997fb FG |
121 | #[cfg(not(miri))] |
122 | const N: usize = 100000; | |
123 | #[cfg(miri)] | |
124 | const N: usize = 1000; | |
125 | for _ in 0..N { | |
dc9dc135 XL |
126 | arena.alloc(()); |
127 | } | |
128 | } | |
129 | ||
130 | #[test] | |
131 | pub fn test_typed_arena_clear() { | |
132 | let mut arena = TypedArena::default(); | |
133 | for _ in 0..10 { | |
134 | arena.clear(); | |
064997fb FG |
135 | #[cfg(not(miri))] |
136 | const N: usize = 10000; | |
137 | #[cfg(miri)] | |
138 | const N: usize = 100; | |
139 | for _ in 0..N { | |
dc9dc135 XL |
140 | arena.alloc(Point { x: 1, y: 2, z: 3 }); |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | #[bench] | |
146 | pub fn bench_typed_arena_clear(b: &mut Bencher) { | |
147 | let mut arena = TypedArena::default(); | |
148 | b.iter(|| { | |
149 | arena.alloc(Point { x: 1, y: 2, z: 3 }); | |
150 | arena.clear(); | |
151 | }) | |
152 | } | |
153 | ||
1b1a35ee XL |
154 | #[bench] |
155 | pub fn bench_typed_arena_clear_100(b: &mut Bencher) { | |
156 | let mut arena = TypedArena::default(); | |
157 | b.iter(|| { | |
158 | for _ in 0..100 { | |
159 | arena.alloc(Point { x: 1, y: 2, z: 3 }); | |
160 | } | |
161 | arena.clear(); | |
162 | }) | |
163 | } | |
164 | ||
dc9dc135 XL |
165 | // Drop tests |
166 | ||
167 | struct DropCounter<'a> { | |
168 | count: &'a Cell<u32>, | |
169 | } | |
170 | ||
171 | impl Drop for DropCounter<'_> { | |
172 | fn drop(&mut self) { | |
173 | self.count.set(self.count.get() + 1); | |
174 | } | |
175 | } | |
176 | ||
177 | #[test] | |
178 | fn test_typed_arena_drop_count() { | |
179 | let counter = Cell::new(0); | |
180 | { | |
181 | let arena: TypedArena<DropCounter<'_>> = TypedArena::default(); | |
182 | for _ in 0..100 { | |
183 | // Allocate something with drop glue to make sure it doesn't leak. | |
184 | arena.alloc(DropCounter { count: &counter }); | |
185 | } | |
186 | }; | |
187 | assert_eq!(counter.get(), 100); | |
188 | } | |
189 | ||
190 | #[test] | |
191 | fn test_typed_arena_drop_on_clear() { | |
192 | let counter = Cell::new(0); | |
193 | let mut arena: TypedArena<DropCounter<'_>> = TypedArena::default(); | |
194 | for i in 0..10 { | |
195 | for _ in 0..100 { | |
196 | // Allocate something with drop glue to make sure it doesn't leak. | |
197 | arena.alloc(DropCounter { count: &counter }); | |
198 | } | |
199 | arena.clear(); | |
200 | assert_eq!(counter.get(), i * 100 + 100); | |
201 | } | |
202 | } | |
203 | ||
204 | thread_local! { | |
205 | static DROP_COUNTER: Cell<u32> = Cell::new(0) | |
206 | } | |
207 | ||
208 | struct SmallDroppable; | |
209 | ||
210 | impl Drop for SmallDroppable { | |
211 | fn drop(&mut self) { | |
212 | DROP_COUNTER.with(|c| c.set(c.get() + 1)); | |
213 | } | |
214 | } | |
215 | ||
216 | #[test] | |
217 | fn test_typed_arena_drop_small_count() { | |
218 | DROP_COUNTER.with(|c| c.set(0)); | |
219 | { | |
220 | let arena: TypedArena<SmallDroppable> = TypedArena::default(); | |
221 | for _ in 0..100 { | |
222 | // Allocate something with drop glue to make sure it doesn't leak. | |
223 | arena.alloc(SmallDroppable); | |
224 | } | |
225 | // dropping | |
226 | }; | |
227 | assert_eq!(DROP_COUNTER.with(|c| c.get()), 100); | |
228 | } | |
229 | ||
230 | #[bench] | |
231 | pub fn bench_noncopy(b: &mut Bencher) { | |
232 | let arena = TypedArena::default(); | |
233 | b.iter(|| { | |
dfeec247 | 234 | arena.alloc(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }) |
dc9dc135 XL |
235 | }) |
236 | } | |
237 | ||
238 | #[bench] | |
239 | pub fn bench_noncopy_nonarena(b: &mut Bencher) { | |
240 | b.iter(|| { | |
dfeec247 XL |
241 | let _: Box<_> = |
242 | Box::new(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }); | |
dc9dc135 XL |
243 | }) |
244 | } |