]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/container/test/monotonic_buffer_resource_test.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / container / test / monotonic_buffer_resource_test.cpp
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/container for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10
11 #include <boost/container/pmr/monotonic_buffer_resource.hpp>
12 #include <boost/container/pmr/global_resource.hpp>
13 #include <boost/core/lightweight_test.hpp>
14 #include "derived_from_memory_resource.hpp"
15 #include "memory_resource_logger.hpp"
16
17 using namespace boost::container::pmr;
18
19 static const std::size_t AllocCount = 32u;
20
21 namespace test_block_chain{
22
23 //explicit block_slist(memory_resource &upstream_rsrc)
24 void test_constructor()
25 {
26 memory_resource_logger mrl;
27 block_slist bc(mrl);
28 //Resource stored
29 BOOST_TEST(&bc.upstream_resource() == &mrl);
30 //No allocation performed
31 BOOST_TEST(mrl.m_info.size() == 0u);
32 }
33
34 //void *allocate(std::size_t size)
35 void test_allocate()
36 {
37 memory_resource_logger mrl;
38 block_slist bc(mrl);
39
40 for(unsigned i = 0; i != unsigned(AllocCount); ++i){
41 //Allocate and trace data
42 const std::size_t alloc = i+1;
43 char *const addr = (char*)bc.allocate(alloc);
44 //Should have allocated a new entry
45 BOOST_TEST(mrl.m_info.size() == (i+1));
46 //Requested size must be bigger to include metadata
47 BOOST_TEST(mrl.m_info[i].bytes > alloc);
48 BOOST_TEST(mrl.m_info[i].alignment == memory_resource::max_align);
49 //Returned address should be between the allocated buffer
50 BOOST_TEST(mrl.m_info[i].address < addr);
51 BOOST_TEST(addr < (mrl.m_info[i].address + mrl.m_info[i].bytes));
52 //Allocate size should include all requested size
53 BOOST_TEST((addr + alloc) <= (mrl.m_info[i].address + mrl.m_info[i].bytes));
54 //Allocation must be max-aligned
55 BOOST_TEST((std::size_t(addr) % memory_resource::max_align) == 0);
56 }
57 }
58
59 //void release() BOOST_NOEXCEPT
60 void test_release()
61 {
62 memory_resource_logger mrl;
63 block_slist bc(mrl);
64
65 //Allocate and trace data
66 char *bufs[AllocCount];
67 for(unsigned i = 0; i != unsigned(AllocCount); ++i){
68 bufs[i] = (char*)bc.allocate(i+1);
69 }
70 (void)bufs;
71 //Should have allocated a new entry
72 BOOST_TEST(mrl.m_info.size() == AllocCount);
73
74 //Now release and check all allocations match deallocations
75 bc.release();
76 BOOST_TEST(mrl.m_mismatches == 0);
77 BOOST_TEST(mrl.m_info.size() == 0u);
78 }
79
80 //memory_resource* upstream_resource()
81 void test_memory_resource()
82 {
83 derived_from_memory_resource d;
84 block_slist bc(d);
85 //Resource stored
86 BOOST_TEST(&bc.upstream_resource() == &d);
87 }
88
89 //~block_slist() { this->release(); }
90 void test_destructor()
91 {
92 memory_resource_logger mrl;
93 {
94 block_slist bc(mrl);
95
96 //Allocate and trace data
97 char *bufs[AllocCount];
98 for(unsigned i = 0; i != unsigned(AllocCount); ++i){
99 bufs[i] = (char*)bc.allocate(i+1);
100 }
101 (void)bufs;
102 //Should have allocated a new entry
103 BOOST_TEST(mrl.m_info.size() == AllocCount);
104
105 //Destructor should release all memory
106 }
107 BOOST_TEST(mrl.m_mismatches == 0);
108 BOOST_TEST(mrl.m_info.size() == 0u);
109 }
110
111 } //namespace test_block_chain {
112
113 void test_resource_constructor()
114 {
115 //First constructor, null resource
116 {
117 memory_resource_logger mrl;
118 BOOST_TEST(mrl.m_info.size() == 0u);
119 set_default_resource(&mrl);
120 monotonic_buffer_resource m;
121 //test postconditions
122 BOOST_TEST(m.upstream_resource() == get_default_resource());
123 //test it does not allocate any memory
124 BOOST_TEST(mrl.m_info.size() == 0u);
125 set_default_resource(0);
126 }
127 //First constructor, non-null resource
128 {
129 derived_from_memory_resource dmr;
130 dmr.reset();
131 monotonic_buffer_resource m(&dmr);
132 //test postconditions
133 BOOST_TEST(m.upstream_resource() == &dmr);
134 BOOST_TEST(m.next_buffer_size() == monotonic_buffer_resource::initial_next_buffer_size);
135 BOOST_TEST(m.current_buffer() == 0);
136 //test it does not allocate any memory
137 BOOST_TEST(dmr.do_allocate_called == false);
138 }
139 }
140
141 void test_initial_size_constructor()
142 {
143 //Second constructor, null resource
144 const std::size_t initial_size = monotonic_buffer_resource::initial_next_buffer_size*2;
145 {
146 memory_resource_logger mrl;
147 BOOST_TEST(mrl.m_info.size() == 0u);
148 set_default_resource(&mrl);
149 monotonic_buffer_resource m(initial_size);
150 //test postconditions
151 BOOST_TEST(m.upstream_resource() == get_default_resource());
152 BOOST_TEST(m.next_buffer_size() >= initial_size);
153 BOOST_TEST(m.current_buffer() == 0);
154 //test it does not allocate any memory
155 BOOST_TEST(mrl.m_info.size() == 0u);
156 set_default_resource(0);
157 }
158 //Second constructor, non-null resource
159 {
160 derived_from_memory_resource dmr;
161 dmr.reset();
162 monotonic_buffer_resource m(initial_size, &dmr);
163 //test postconditions
164 BOOST_TEST(m.upstream_resource() == &dmr);
165 BOOST_TEST(m.next_buffer_size() >= initial_size);
166 BOOST_TEST(m.current_buffer() == 0);
167 //test it does not allocate any memory
168 BOOST_TEST(dmr.do_allocate_called == false);
169 }
170 }
171
172 void test_buffer_constructor()
173 {
174 const std::size_t BufSz = monotonic_buffer_resource::initial_next_buffer_size*2;
175 unsigned char buf[BufSz];
176 //Third constructor, null resource
177 {
178 memory_resource_logger mrl;
179 BOOST_TEST(mrl.m_info.size() == 0u);
180 set_default_resource(&mrl);
181 monotonic_buffer_resource m(buf, BufSz);
182 //test postconditions
183 BOOST_TEST(m.upstream_resource() == get_default_resource());
184 BOOST_TEST(m.next_buffer_size() >= BufSz*2);
185 BOOST_TEST(m.current_buffer() == buf);
186 //test it does not allocate any memory
187 BOOST_TEST(mrl.m_info.size() == 0u);
188 set_default_resource(0);
189 }
190 //Third constructor, non-null resource
191 {
192 derived_from_memory_resource dmr;
193 dmr.reset();
194 monotonic_buffer_resource m(buf, sizeof(buf), &dmr);
195 //test postconditions
196 BOOST_TEST(m.upstream_resource() == &dmr);
197 BOOST_TEST(m.next_buffer_size() >= sizeof(buf)*2);
198 BOOST_TEST(m.current_buffer() == buf);
199 //test it does not allocate any memory
200 BOOST_TEST(dmr.do_allocate_called == false);
201 }
202 //Check for empty buffers
203 {
204 monotonic_buffer_resource m(buf, 0);
205 BOOST_TEST(m.upstream_resource() == get_default_resource());
206 BOOST_TEST(m.next_buffer_size() > 1);
207 BOOST_TEST(m.current_buffer() == buf);
208 }
209 }
210
211 struct derived_from_monotonic_buffer_resource
212 : public monotonic_buffer_resource
213 {
214 explicit derived_from_monotonic_buffer_resource(memory_resource *p)
215 : monotonic_buffer_resource(p)
216 {}
217
218 explicit derived_from_monotonic_buffer_resource(std::size_t initial_size, memory_resource* upstream)
219 : monotonic_buffer_resource(initial_size, upstream)
220 {}
221
222 explicit derived_from_monotonic_buffer_resource(void* buffer, std::size_t buffer_size, memory_resource* upstream)
223 : monotonic_buffer_resource(buffer, buffer_size, upstream)
224 {}
225
226 using monotonic_buffer_resource::do_allocate;
227 using monotonic_buffer_resource::do_deallocate;
228 using monotonic_buffer_resource::do_is_equal;
229 };
230
231 void test_upstream_resource()
232 {
233 //Test stores the resource and uses it to allocate memory
234 derived_from_memory_resource dmr;
235 dmr.reset();
236 derived_from_monotonic_buffer_resource dmbr(&dmr);
237 //Resource must be stored and initial values given (no current buffer)
238 BOOST_TEST(dmbr.upstream_resource() == &dmr);
239 BOOST_TEST(dmbr.next_buffer_size() == monotonic_buffer_resource::initial_next_buffer_size);
240 BOOST_TEST(dmbr.current_buffer() == 0);
241 //Test it does not allocate any memory
242 BOOST_TEST(dmr.do_allocate_called == false);
243 const std::size_t BufSz = monotonic_buffer_resource::initial_next_buffer_size;
244 //Now allocate storage, and stub it as the return buffer
245 //for "derived_from_memory_resource":
246 boost::move_detail::aligned_storage<BufSz+block_slist::header_size>::type buf;
247 dmr.do_allocate_return = &buf;
248 //Test that allocation uses the upstream_resource()
249 void *addr = dmbr.do_allocate(1u, 1u);
250 //Test returns stubbed memory with the internal initial size plus metadata size
251 BOOST_TEST(addr > (char*)&buf);
252 BOOST_TEST(addr < (char*)(&buf+1));
253 BOOST_TEST(dmr.do_allocate_called == true);
254 BOOST_TEST(dmr.do_allocate_bytes > BufSz);
255 //Alignment for the resource must be max_align
256 BOOST_TEST(dmr.do_allocate_alignment == memory_resource::max_align);
257 }
258
259 void test_do_allocate()
260 {
261 memory_resource_logger mrl;
262 {
263 std::size_t remaining_storage = 0u;
264 derived_from_monotonic_buffer_resource dmbr(&mrl);
265 //First test, no buffer
266 {
267 dmbr.do_allocate(1, 1);
268 //It should allocate initial size
269 BOOST_TEST(mrl.m_info.size() == 1u);
270 //... which requests the initial size plus the header size to the allcoator
271 BOOST_TEST(mrl.m_info[0].bytes == monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size);
272 std::size_t remaining = dmbr.remaining_storage(1u);
273 //Remaining storage should be one less than initial, as we requested 1 byte with minimal alignment
274 BOOST_TEST(remaining == monotonic_buffer_resource::initial_next_buffer_size-1u);
275 remaining_storage = remaining;
276 }
277 //Now ask for more internal storage with misaligned current buffer
278 {
279 //Test wasted space
280 std::size_t wasted_due_to_alignment;
281 dmbr.remaining_storage(4u, wasted_due_to_alignment);
282 BOOST_TEST(wasted_due_to_alignment == 3u);
283 dmbr.do_allocate(4, 4);
284 //It should not have allocated
285 BOOST_TEST(mrl.m_info.size() == 1u);
286 std::size_t remaining = dmbr.remaining_storage(1u);
287 //We wasted some bytes due to alignment plus 4 bytes of real storage
288 BOOST_TEST(remaining == remaining_storage - 4 - wasted_due_to_alignment);
289 remaining_storage = remaining;
290 }
291 //Now request the same alignment to test no storage is wasted
292 {
293 std::size_t wasted_due_to_alignment;
294 std::size_t remaining = dmbr.remaining_storage(1u, wasted_due_to_alignment);
295 BOOST_TEST(mrl.m_info.size() == 1u);
296 dmbr.do_allocate(4, 4);
297 //It should not have allocated
298 BOOST_TEST(mrl.m_info.size() == 1u);
299 remaining = dmbr.remaining_storage(1u);
300 //We wasted no bytes due to alignment plus 4 bytes of real storage
301 BOOST_TEST(remaining == remaining_storage - 4u);
302 remaining_storage = remaining;
303 }
304 //Now exhaust the remaining storage with 2 byte alignment (the last allocation
305 //was 4 bytes with 4 byte alignment) so it should be already 2-byte aligned.
306 {
307 dmbr.do_allocate(remaining_storage, 2);
308 std::size_t wasted_due_to_alignment;
309 std::size_t remaining = dmbr.remaining_storage(1u, wasted_due_to_alignment);
310 BOOST_TEST(wasted_due_to_alignment == 0u);
311 BOOST_TEST(remaining == 0u);
312 //It should not have allocated
313 BOOST_TEST(mrl.m_info.size() == 1u);
314 remaining_storage = 0u;
315 }
316 //The next allocation should trigger the upstream resource, even with a 1 byte
317 //allocation.
318 {
319 dmbr.do_allocate(1u, 1u);
320 BOOST_TEST(mrl.m_info.size() == 2u);
321 //The next allocation should be geometrically bigger.
322 BOOST_TEST(mrl.m_info[1].bytes == 2*monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size);
323 std::size_t wasted_due_to_alignment;
324 //For a 2 byte alignment one byte will be wasted from the previous 1 byte allocation
325 std::size_t remaining = dmbr.remaining_storage(2u, wasted_due_to_alignment);
326 BOOST_TEST(wasted_due_to_alignment == 1u);
327 BOOST_TEST(remaining == (mrl.m_info[1].bytes - 1u - wasted_due_to_alignment - block_slist::header_size));
328 //It should not have allocated
329 remaining_storage = dmbr.remaining_storage(1u);
330 }
331 //Now try a bigger than next allocation and see if next_buffer_size is doubled.
332 {
333 std::size_t next_alloc = 5*monotonic_buffer_resource::initial_next_buffer_size;
334 dmbr.do_allocate(next_alloc, 1u);
335 BOOST_TEST(mrl.m_info.size() == 3u);
336 //The next allocation should be geometrically bigger.
337 BOOST_TEST(mrl.m_info[2].bytes == 8*monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size);
338 remaining_storage = dmbr.remaining_storage(1u);
339 }
340 }
341 //derived_from_monotonic_buffer_resource dmbr(&mrl) is destroyed
342 BOOST_TEST(mrl.m_mismatches == 0u);
343 BOOST_TEST(mrl.m_info.size() == 0u);
344
345 //Now use a local buffer
346 {
347 boost::move_detail::aligned_storage
348 <monotonic_buffer_resource::initial_next_buffer_size>::type buf;
349 //Supply an external buffer
350 derived_from_monotonic_buffer_resource dmbr(&buf, sizeof(buf), &mrl);
351 BOOST_TEST(dmbr.remaining_storage(1u) == sizeof(buf));
352 //Allocate all remaining storage
353 dmbr.do_allocate(dmbr.remaining_storage(1u), 1u);
354 //No new allocation should have ocurred
355 BOOST_TEST(mrl.m_info.size() == 0u);
356 BOOST_TEST(dmbr.remaining_storage(1u) == 0u);
357 }
358 BOOST_TEST(mrl.m_mismatches == 0u);
359 BOOST_TEST(mrl.m_info.size() == 0u);
360 }
361
362 void test_do_deallocate()
363 {
364 memory_resource_logger mrl;
365 const std::size_t initial_size = 1u;
366 {
367 derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl);
368 //First test, no buffer
369 const unsigned iterations = 8;
370 char *bufs[iterations];
371 std::size_t sizes[iterations];
372 //Test each iteration allocates memory
373 for(unsigned i = 0; i != iterations; ++i)
374 {
375 sizes[i] = dmbr.remaining_storage()+1;
376 bufs[i] = (char*)dmbr.do_allocate(sizes[i], 1);
377 BOOST_TEST(mrl.m_info.size() == (i+1));
378 }
379 std::size_t remaining = dmbr.remaining_storage();
380 //Test do_deallocate does not release any storage
381 for(unsigned i = 0; i != iterations; ++i)
382 {
383 dmbr.do_deallocate(bufs[i], sizes[i], 1u);
384 BOOST_TEST(mrl.m_info.size() == iterations);
385 BOOST_TEST(remaining == dmbr.remaining_storage());
386 BOOST_TEST(mrl.m_mismatches == 0u);
387 }
388 }
389 }
390
391 void test_do_is_equal()
392 {
393 //! <b>Returns</b>:
394 //! `this == dynamic_cast<const monotonic_buffer_resource*>(&other)`.
395 memory_resource_logger mrl;
396 derived_from_monotonic_buffer_resource dmbr(&mrl);
397 derived_from_monotonic_buffer_resource dmbr2(&mrl);
398 BOOST_TEST(true == dmbr.do_is_equal(dmbr));
399 BOOST_TEST(false == dmbr.do_is_equal(dmbr2));
400 //A different type should be always different
401 derived_from_memory_resource dmr;
402 BOOST_TEST(false == dmbr.do_is_equal(dmr));
403 }
404
405 void test_release()
406 {
407 memory_resource_logger mrl;
408 const std::size_t initial_size = 1u;
409 derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl);
410 //First test, no buffer
411 const unsigned iterations = 8;
412 //Test each iteration allocates memory
413 for(unsigned i = 0; i != iterations; ++i)
414 {
415 dmbr.do_allocate(dmbr.remaining_storage()+1, 1);
416 BOOST_TEST(mrl.m_info.size() == (i+1));
417 }
418 //Release and check memory was released
419 dmbr.release();
420 BOOST_TEST(mrl.m_mismatches == 0u);
421 BOOST_TEST(mrl.m_info.size() == 0u);
422 }
423
424 void test_destructor()
425 {
426 memory_resource_logger mrl;
427 const std::size_t initial_size = 1u;
428 {
429 derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl);
430 //First test, no buffer
431 const unsigned iterations = 8;
432 //Test each iteration allocates memory
433 for(unsigned i = 0; i != iterations; ++i)
434 {
435 dmbr.do_allocate(dmbr.remaining_storage()+1, 1);
436 BOOST_TEST(mrl.m_info.size() == (i+1));
437 }
438 } //dmbr is destroyed, memory should be released
439 BOOST_TEST(mrl.m_mismatches == 0u);
440 BOOST_TEST(mrl.m_info.size() == 0u);
441 }
442
443 int main()
444 {
445 test_block_chain::test_constructor();
446 test_block_chain::test_allocate();
447 test_block_chain::test_release();
448 test_block_chain::test_memory_resource();
449 test_block_chain::test_destructor();
450
451 test_resource_constructor();
452 test_initial_size_constructor();
453 test_buffer_constructor();
454
455 test_upstream_resource();
456 test_do_allocate();
457 test_do_deallocate();
458 test_do_is_equal();
459 test_release();
460 test_destructor();
461 return ::boost::report_errors();
462 }