1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * In memory space allocator test cases.
5 * Author: Ramesh Chander, Ramesh.Chander@sandisk.com
8 #include <boost/scoped_ptr.hpp>
9 #include <gtest/gtest.h>
11 #include "common/Cond.h"
12 #include "common/errno.h"
13 #include "include/stringify.h"
14 #include "include/Context.h"
15 #include "os/bluestore/Allocator.h"
17 typedef boost::mt11213b gen_type
;
19 class AllocTest
: public ::testing::TestWithParam
<const char*> {
22 boost::scoped_ptr
<Allocator
> alloc
;
23 AllocTest(): alloc(0) { }
24 void init_alloc(int64_t size
, uint64_t min_alloc_size
) {
25 std::cout
<< "Creating alloc type " << string(GetParam()) << " \n";
26 alloc
.reset(Allocator::create(g_ceph_context
, string(GetParam()), size
,
35 TEST_P(AllocTest
, test_alloc_init
)
38 init_alloc(blocks
, 1);
39 ASSERT_EQ(0U, alloc
->get_free());
41 blocks
= 1024 * 2 + 16;
42 init_alloc(blocks
, 1);
43 ASSERT_EQ(0U, alloc
->get_free());
46 init_alloc(blocks
, 1);
47 ASSERT_EQ(alloc
->get_free(), (uint64_t) 0);
50 TEST_P(AllocTest
, test_alloc_min_alloc
)
52 int64_t block_size
= 1024;
53 int64_t capacity
= 4 * 1024 * block_size
;
56 init_alloc(capacity
, block_size
);
58 alloc
->init_add_free(block_size
, block_size
);
59 PExtentVector extents
;
60 EXPECT_EQ(block_size
, alloc
->allocate(block_size
, block_size
,
61 0, (int64_t) 0, &extents
));
65 * Allocate extent and make sure all comes in single extent.
68 init_alloc(capacity
, block_size
);
69 alloc
->init_add_free(0, block_size
* 4);
70 PExtentVector extents
;
71 EXPECT_EQ(4*block_size
,
72 alloc
->allocate(4 * (uint64_t)block_size
, (uint64_t) block_size
,
73 0, (int64_t) 0, &extents
));
74 EXPECT_EQ(1u, extents
.size());
75 EXPECT_EQ(extents
[0].length
, 4 * block_size
);
79 * Allocate extent and make sure we get two different extents.
82 init_alloc(capacity
, block_size
);
83 alloc
->init_add_free(0, block_size
* 2);
84 alloc
->init_add_free(3 * block_size
, block_size
* 2);
85 PExtentVector extents
;
87 EXPECT_EQ(4*block_size
,
88 alloc
->allocate(4 * (uint64_t)block_size
, (uint64_t) block_size
,
89 0, (int64_t) 0, &extents
));
90 EXPECT_EQ(2u, extents
.size());
91 EXPECT_EQ(extents
[0].length
, 2 * block_size
);
92 EXPECT_EQ(extents
[1].length
, 2 * block_size
);
97 TEST_P(AllocTest
, test_alloc_min_max_alloc
)
99 int64_t block_size
= 1024;
101 int64_t capacity
= 4 * 1024 * block_size
;
102 init_alloc(capacity
, block_size
);
105 * Make sure we get all extents different when
106 * min_alloc_size == max_alloc_size
109 init_alloc(capacity
, block_size
);
110 alloc
->init_add_free(0, block_size
* 4);
111 PExtentVector extents
;
112 EXPECT_EQ(4*block_size
,
113 alloc
->allocate(4 * (uint64_t)block_size
, (uint64_t) block_size
,
114 block_size
, (int64_t) 0, &extents
));
115 for (auto e
: extents
) {
116 EXPECT_EQ(e
.length
, block_size
);
118 EXPECT_EQ(4u, extents
.size());
123 * Make sure we get extents of length max_alloc size
124 * when max alloc size > min_alloc size
127 init_alloc(capacity
, block_size
);
128 alloc
->init_add_free(0, block_size
* 4);
129 PExtentVector extents
;
130 EXPECT_EQ(4*block_size
,
131 alloc
->allocate(4 * (uint64_t)block_size
, (uint64_t) block_size
,
132 2 * block_size
, (int64_t) 0, &extents
));
133 EXPECT_EQ(2u, extents
.size());
134 for (auto& e
: extents
) {
135 EXPECT_EQ(e
.length
, block_size
* 2);
140 * Make sure allocations are of min_alloc_size when min_alloc_size > block_size.
143 init_alloc(capacity
, block_size
);
144 alloc
->init_add_free(0, block_size
* 1024);
145 PExtentVector extents
;
146 EXPECT_EQ(1024 * block_size
,
147 alloc
->allocate(1024 * (uint64_t)block_size
,
148 (uint64_t) block_size
* 4,
149 block_size
* 4, (int64_t) 0, &extents
));
150 for (auto& e
: extents
) {
151 EXPECT_EQ(e
.length
, block_size
* 4);
153 EXPECT_EQ(1024u/4, extents
.size());
160 init_alloc(capacity
, block_size
);
161 alloc
->init_add_free(0, block_size
* 16);
162 PExtentVector extents
;
163 EXPECT_EQ(16 * block_size
,
164 alloc
->allocate(16 * (uint64_t)block_size
, (uint64_t) block_size
,
165 2 * block_size
, (int64_t) 0, &extents
));
167 EXPECT_EQ(extents
.size(), 8u);
168 for (auto& e
: extents
) {
169 EXPECT_EQ(e
.length
, 2 * block_size
);
174 TEST_P(AllocTest
, test_alloc_failure
)
176 int64_t block_size
= 1024;
177 int64_t capacity
= 4 * 1024 * block_size
;
180 init_alloc(capacity
, block_size
);
181 alloc
->init_add_free(0, block_size
* 256);
182 alloc
->init_add_free(block_size
* 512, block_size
* 256);
184 PExtentVector extents
;
185 EXPECT_EQ(512 * block_size
,
186 alloc
->allocate(512 * (uint64_t)block_size
,
187 (uint64_t) block_size
* 256,
188 block_size
* 256, (int64_t) 0, &extents
));
189 alloc
->init_add_free(0, block_size
* 256);
190 alloc
->init_add_free(block_size
* 512, block_size
* 256);
193 alloc
->allocate(512 * (uint64_t)block_size
,
194 (uint64_t) block_size
* 512,
195 block_size
* 512, (int64_t) 0, &extents
));
199 TEST_P(AllocTest
, test_alloc_big
)
201 int64_t block_size
= 4096;
202 int64_t blocks
= 104857600;
204 init_alloc(blocks
*block_size
, block_size
);
205 alloc
->init_add_free(2*block_size
, (blocks
-2)*block_size
);
206 for (int64_t big
= mas
; big
< 1048576*128; big
*=2) {
207 cout
<< big
<< std::endl
;
208 PExtentVector extents
;
210 alloc
->allocate(big
, mas
, 0, &extents
));
214 TEST_P(AllocTest
, test_alloc_non_aligned_len
)
216 int64_t block_size
= 1 << 12;
217 int64_t blocks
= (1 << 20) * 100;
218 int64_t want_size
= 1 << 22;
219 int64_t alloc_unit
= 1 << 20;
221 init_alloc(blocks
*block_size
, block_size
);
222 alloc
->init_add_free(0, 2097152);
223 alloc
->init_add_free(2097152, 1064960);
224 alloc
->init_add_free(3670016, 2097152);
226 PExtentVector extents
;
227 EXPECT_EQ(want_size
, alloc
->allocate(want_size
, alloc_unit
, 0, &extents
));
230 TEST_P(AllocTest
, test_alloc_39334
)
232 uint64_t block
= 0x4000;
233 uint64_t size
= 0x5d00000000;
235 init_alloc(size
, block
);
236 alloc
->init_add_free(0x4000, 0x5cffffc000);
237 EXPECT_EQ(size
- block
, alloc
->get_free());
240 TEST_P(AllocTest
, test_alloc_fragmentation
)
242 uint64_t capacity
= 4 * 1024 * 1024;
243 uint64_t alloc_unit
= 4096;
244 uint64_t want_size
= alloc_unit
;
245 PExtentVector allocated
, tmp
;
247 init_alloc(capacity
, alloc_unit
);
248 alloc
->init_add_free(0, capacity
);
249 bool bitmap_alloc
= GetParam() == std::string("bitmap");
251 EXPECT_EQ(0.0, alloc
->get_fragmentation());
253 for (size_t i
= 0; i
< capacity
/ alloc_unit
; ++i
)
256 EXPECT_EQ(static_cast<int64_t>(want_size
),
257 alloc
->allocate(want_size
, alloc_unit
, 0, 0, &tmp
));
258 allocated
.insert(allocated
.end(), tmp
.begin(), tmp
.end());
260 // bitmap fragmentation calculation doesn't provide such constant
263 EXPECT_EQ(0.0, alloc
->get_fragmentation());
267 EXPECT_EQ(-ENOSPC
, alloc
->allocate(want_size
, alloc_unit
, 0, 0, &tmp
));
269 if (GetParam() == string("avl")) {
270 // AVL allocator uses a different allocating strategy
271 GTEST_SKIP() << "skipping for AVL allocator";
272 } else if (GetParam() == string("hybrid")) {
273 // AVL allocator uses a different allocating strategy
274 GTEST_SKIP() << "skipping for Hybrid allocator";
277 for (size_t i
= 0; i
< allocated
.size(); i
+= 2)
279 interval_set
<uint64_t> release_set
;
280 release_set
.insert(allocated
[i
].offset
, allocated
[i
].length
);
281 alloc
->release(release_set
);
283 EXPECT_EQ(1.0, alloc
->get_fragmentation());
284 EXPECT_EQ(66u, uint64_t(alloc
->get_fragmentation_score() * 100));
286 for (size_t i
= 1; i
< allocated
.size() / 2; i
+= 2)
288 interval_set
<uint64_t> release_set
;
289 release_set
.insert(allocated
[i
].offset
, allocated
[i
].length
);
290 alloc
->release(release_set
);
293 // fragmentation = one l1 slot is free + one l1 slot is partial
294 EXPECT_EQ(50U, uint64_t(alloc
->get_fragmentation() * 100));
296 // fragmentation approx = 257 intervals / 768 max intervals
297 EXPECT_EQ(33u, uint64_t(alloc
->get_fragmentation() * 100));
299 EXPECT_EQ(27u, uint64_t(alloc
->get_fragmentation_score() * 100));
301 for (size_t i
= allocated
.size() / 2 + 1; i
< allocated
.size(); i
+= 2)
303 interval_set
<uint64_t> release_set
;
304 release_set
.insert(allocated
[i
].offset
, allocated
[i
].length
);
305 alloc
->release(release_set
);
307 // doing some rounding trick as stupid allocator doesn't merge all the
308 // extents that causes some minor fragmentation (minor bug or by-design behavior?).
309 // Hence leaving just two
310 // digits after decimal point due to this.
311 EXPECT_EQ(0u, uint64_t(alloc
->get_fragmentation() * 100));
313 EXPECT_EQ(0u, uint64_t(alloc
->get_fragmentation_score() * 100));
315 EXPECT_EQ(11u, uint64_t(alloc
->get_fragmentation_score() * 100));
319 TEST_P(AllocTest
, test_dump_fragmentation_score
)
321 uint64_t capacity
= 1024 * 1024 * 1024;
322 uint64_t one_alloc_max
= 2 * 1024 * 1024;
323 uint64_t alloc_unit
= 4096;
324 uint64_t want_size
= alloc_unit
;
325 uint64_t rounds
= 10;
326 uint64_t actions_per_round
= 1000;
327 PExtentVector allocated
, tmp
;
330 init_alloc(capacity
, alloc_unit
);
331 alloc
->init_add_free(0, capacity
);
333 EXPECT_EQ(0.0, alloc
->get_fragmentation());
334 EXPECT_EQ(0.0, alloc
->get_fragmentation_score());
336 uint64_t allocated_cnt
= 0;
337 for (size_t round
= 0; round
< rounds
; round
++) {
338 for (size_t j
= 0; j
< actions_per_round
; j
++) {
340 if ( rng() % capacity
>= allocated_cnt
) {
342 want_size
= ( rng() % one_alloc_max
) / alloc_unit
* alloc_unit
+ alloc_unit
;
344 uint64_t r
= alloc
->allocate(want_size
, alloc_unit
, 0, 0, &tmp
);
347 allocated
.push_back(t
);
352 ceph_assert(allocated
.size() > 0);
353 size_t item
= rng() % allocated
.size();
354 ceph_assert(allocated
[item
].length
> 0);
355 allocated_cnt
-= allocated
[item
].length
;
356 interval_set
<uint64_t> release_set
;
357 release_set
.insert(allocated
[item
].offset
, allocated
[item
].length
);
358 alloc
->release(release_set
);
359 std::swap(allocated
[item
], allocated
[allocated
.size() - 1]);
360 allocated
.resize(allocated
.size() - 1);
365 auto iterated_allocation
= [&](size_t off
, size_t len
) {
366 ceph_assert(len
> 0);
369 alloc
->dump(iterated_allocation
);
370 EXPECT_GT(1, alloc
->get_fragmentation_score());
371 EXPECT_EQ(capacity
, free_sum
+ allocated_cnt
);
374 for (size_t i
= 0; i
< allocated
.size(); i
++)
376 interval_set
<uint64_t> release_set
;
377 release_set
.insert(allocated
[i
].offset
, allocated
[i
].length
);
378 alloc
->release(release_set
);
382 TEST_P(AllocTest
, test_alloc_bug_24598
)
384 if (string(GetParam()) != "bitmap")
387 uint64_t capacity
= 0x2625a0000ull
;
388 uint64_t alloc_unit
= 0x4000;
389 uint64_t want_size
= 0x200000;
390 PExtentVector allocated
, tmp
;
392 init_alloc(capacity
, alloc_unit
);
394 alloc
->init_add_free(0x4800000, 0x100000);
395 alloc
->init_add_free(0x4a00000, 0x100000);
397 alloc
->init_rm_free(0x4800000, 0x100000);
398 alloc
->init_rm_free(0x4a00000, 0x100000);
400 alloc
->init_add_free(0x3f00000, 0x500000);
401 alloc
->init_add_free(0x4500000, 0x100000);
402 alloc
->init_add_free(0x4700000, 0x100000);
403 alloc
->init_add_free(0x4900000, 0x100000);
404 alloc
->init_add_free(0x4b00000, 0x200000);
406 EXPECT_EQ(static_cast<int64_t>(want_size
),
407 alloc
->allocate(want_size
, 0x100000, 0, 0, &tmp
));
408 EXPECT_EQ(1u, tmp
.size());
409 EXPECT_EQ(0x4b00000u
, tmp
[0].offset
);
410 EXPECT_EQ(0x200000u
, tmp
[0].length
);
413 //Verifies issue from
414 //http://tracker.ceph.com/issues/40703
416 TEST_P(AllocTest
, test_alloc_big2
)
418 int64_t block_size
= 4096;
419 int64_t blocks
= 1048576 * 2;
420 int64_t mas
= 1024*1024;
421 init_alloc(blocks
*block_size
, block_size
);
422 alloc
->init_add_free(0, blocks
* block_size
);
424 PExtentVector extents
;
425 uint64_t need
= block_size
* blocks
/ 4; // 2GB
427 alloc
->allocate(need
, mas
, 0, &extents
));
428 need
= block_size
* blocks
/ 4; // 2GB
431 alloc
->allocate(need
, mas
, 0, &extents
));
432 EXPECT_TRUE(extents
[0].length
> 0);
435 //Verifies stuck 4GB chunk allocation
438 TEST_P(AllocTest
, test_alloc_big3
)
440 int64_t block_size
= 4096;
441 int64_t blocks
= 1048576 * 2;
442 int64_t mas
= 1024*1024;
443 init_alloc(blocks
*block_size
, block_size
);
444 alloc
->init_add_free(0, blocks
* block_size
);
446 PExtentVector extents
;
447 uint64_t need
= block_size
* blocks
/ 2; // 4GB
449 alloc
->allocate(need
, mas
, 0, &extents
));
450 EXPECT_TRUE(extents
[0].length
> 0);
453 TEST_P(AllocTest
, test_alloc_contiguous
)
455 int64_t block_size
= 0x1000;
456 int64_t capacity
= block_size
* 1024 * 1024;
459 init_alloc(capacity
, block_size
);
461 alloc
->init_add_free(0, capacity
);
462 PExtentVector extents
;
463 uint64_t need
= 4 * block_size
;
465 alloc
->allocate(need
, need
,
466 0, (int64_t)0, &extents
));
467 EXPECT_EQ(1u, extents
.size());
468 EXPECT_EQ(extents
[0].offset
, 0);
469 EXPECT_EQ(extents
[0].length
, 4 * block_size
);
473 alloc
->allocate(need
, need
,
474 0, (int64_t)0, &extents
));
475 EXPECT_EQ(1u, extents
.size());
476 EXPECT_EQ(extents
[0].offset
, 4 * block_size
);
477 EXPECT_EQ(extents
[0].length
, 4 * block_size
);
483 TEST_P(AllocTest
, test_alloc_47883
)
485 uint64_t block
= 0x1000;
486 uint64_t size
= 1599858540544ul;
488 init_alloc(size
, block
);
490 alloc
->init_add_free(0x1b970000, 0x26000);
491 alloc
->init_add_free(0x1747e9d5000, 0x493000);
492 alloc
->init_add_free(0x1747ee6a000, 0x196000);
494 PExtentVector extents
;
495 auto need
= 0x3f980000;
496 auto got
= alloc
->allocate(need
, 0x10000, 0, (int64_t)0, &extents
);
498 EXPECT_EQ(got
, 0x630000);
501 INSTANTIATE_TEST_SUITE_P(
504 ::testing::Values("stupid", "bitmap", "avl", "hybrid"));