]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/objectstore/Allocator_bench.cc
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 benchmarks.
5 * Author: Igor Fedotov, ifedotov@suse.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 #include <boost/random/uniform_int.hpp>
18 typedef boost::mt11213b gen_type
;
20 #include "common/debug.h"
21 #define dout_context g_ceph_context
22 #define dout_subsys ceph_subsys_
24 class AllocTest
: public ::testing::TestWithParam
<const char*> {
27 boost::scoped_ptr
<Allocator
> alloc
;
28 AllocTest(): alloc(0) { }
29 void init_alloc(int64_t size
, uint64_t min_alloc_size
) {
30 std::cout
<< "Creating alloc type " << string(GetParam()) << " \n";
31 alloc
.reset(Allocator::create(g_ceph_context
, string(GetParam()), size
,
38 void doOverwriteTest(uint64_t capacity
, uint64_t prefill
,
42 const uint64_t _1m
= 1024 * 1024;
47 Formatter
* f
= Formatter::create("json-pretty", "json-pretty", "json-pretty");
49 f
->open_object_section("mempools");
54 ldout(g_ceph_context
, 0) << ostr
.str() << dendl
;
59 std::vector
<uint64_t> allocations
;
63 boost::uniform_int
<> u1
;
66 AllocTracker(uint64_t capacity
, uint64_t alloc_unit
)
69 ceph_assert(alloc_unit
>= 0x100);
70 ceph_assert(capacity
<= (uint64_t(1) << 48)); // we use 5 octets (bytes 1 - 5) to store
71 // offset to save the required space.
72 // This supports capacity up to 281 TB
74 allocations
.resize(capacity
/ alloc_unit
);
76 inline uint64_t get_head() const
81 inline uint64_t get_tail() const
86 bool push(uint64_t offs
, uint32_t len
)
88 ceph_assert((len
& 0xff) == 0);
89 ceph_assert((offs
& 0xff) == 0);
90 ceph_assert((offs
& 0xffff000000000000) == 0);
94 uint64_t val
= (offs
<< 16) | (len
>> 8);
95 allocations
[head
++] = val
;
96 head
%= allocations
.size();
100 bool pop(uint64_t* offs
, uint32_t* len
)
104 uint64_t val
= allocations
[tail
++];
105 *len
= uint64_t((val
& 0xffffff) << 8);
106 *offs
= (val
>> 16) & ~uint64_t(0xff);
107 tail
%= allocations
.size();
111 bool pop_random(gen_type
& rng
, uint64_t* offs
, uint32_t* len
,
112 uint32_t max_len
= 0)
117 uint64_t pos
= (u1(rng
) % size
) + tail
;
118 pos
%= allocations
.size();
119 uint64_t val
= allocations
[pos
];
120 *len
= uint64_t((val
& 0xffffff) << 8);
121 *offs
= (val
>> 16) & ~uint64_t(0xff);
122 if (max_len
&& *len
> max_len
) {
123 val
= ((*offs
+ max_len
) << 16) | ((*len
- max_len
) >> 8);
124 allocations
[pos
] = val
;
127 allocations
[pos
] = allocations
[tail
++];
128 tail
%= allocations
.size();
135 TEST_P(AllocTest
, test_alloc_bench_seq
)
137 uint64_t capacity
= uint64_t(1024) * 1024 * 1024 * 1024;
138 uint64_t alloc_unit
= 4096;
139 uint64_t want_size
= alloc_unit
;
140 PExtentVector allocated
, tmp
;
142 init_alloc(capacity
, alloc_unit
);
143 alloc
->init_add_free(0, capacity
);
145 utime_t start
= ceph_clock_now();
146 for (uint64_t i
= 0; i
< capacity
; i
+= want_size
)
149 EXPECT_EQ(static_cast<int64_t>(want_size
),
150 alloc
->allocate(want_size
, alloc_unit
, 0, 0, &tmp
));
151 if (0 == (i
% (1 * 1024 * _1m
))) {
152 std::cout
<< "alloc " << i
/ 1024 / 1024 << " mb of "
153 << capacity
/ 1024 / 1024 << std::endl
;
157 std::cout
<< "releasing..." << std::endl
;
158 for (size_t i
= 0; i
< capacity
; i
+= want_size
)
160 interval_set
<uint64_t> release_set
;
161 release_set
.insert(i
, want_size
);
162 alloc
->release(release_set
);
163 if (0 == (i
% (1 * 1024 * _1m
))) {
164 std::cout
<< "release " << i
/ 1024 / 1024 << " mb of "
165 << capacity
/ 1024 / 1024 << std::endl
;
168 std::cout
<<"Executed in "<< ceph_clock_now() - start
<< std::endl
;
172 TEST_P(AllocTest
, test_alloc_bench
)
174 uint64_t capacity
= uint64_t(1024) * 1024 * 1024 * 1024;
175 uint64_t alloc_unit
= 4096;
176 PExtentVector allocated
, tmp
;
177 AllocTracker
at(capacity
, alloc_unit
);
179 init_alloc(capacity
, alloc_unit
);
180 alloc
->init_add_free(0, capacity
);
182 gen_type
rng(time(NULL
));
183 boost::uniform_int
<> u1(0, 9); // 4K-2M
184 boost::uniform_int
<> u2(0, 7); // 4K-512K
186 utime_t start
= ceph_clock_now();
187 for (uint64_t i
= 0; i
< capacity
* 2; )
189 uint32_t want
= alloc_unit
<< u1(rng
);
192 auto r
= alloc
->allocate(want
, alloc_unit
, 0, 0, &tmp
);
199 bool full
= !at
.push(a
.offset
, a
.length
);
200 EXPECT_EQ(full
, false);
202 uint64_t want_release
= alloc_unit
<< u2(rng
);
203 uint64_t released
= 0;
207 interval_set
<uint64_t> release_set
;
208 if (!at
.pop_random(rng
, &o
, &l
, want_release
- released
)) {
211 release_set
.insert(o
, l
);
212 alloc
->release(release_set
);
214 } while (released
< want_release
);
216 if (0 == (i
% (1 * 1024 * _1m
))) {
217 std::cout
<< "alloc " << i
/ 1024 / 1024 << " mb of "
218 << capacity
/ 1024 / 1024 << std::endl
;
221 std::cout
<<"Executed in "<< ceph_clock_now() - start
<< std::endl
;
222 std::cout
<<"Avail "<< alloc
->get_free() / _1m
<< " MB" << std::endl
;
226 void AllocTest::doOverwriteTest(uint64_t capacity
, uint64_t prefill
,
229 uint64_t alloc_unit
= 4096;
230 PExtentVector allocated
, tmp
;
231 AllocTracker
at(capacity
, alloc_unit
);
233 init_alloc(capacity
, alloc_unit
);
234 alloc
->init_add_free(0, capacity
);
236 gen_type
rng(time(NULL
));
237 boost::uniform_int
<> u1(0, 9); // 4K-2M
238 boost::uniform_int
<> u2(0, 9); // 4K-512K
240 utime_t start
= ceph_clock_now();
241 // allocate 90% of the capacity
243 for (uint64_t i
= 0; i
< cap
; )
245 uint32_t want
= alloc_unit
<< u1(rng
);
247 auto r
= alloc
->allocate(want
, alloc_unit
, 0, 0, &tmp
);
254 bool full
= !at
.push(a
.offset
, a
.length
);
255 EXPECT_EQ(full
, false);
257 if (0 == (i
% (1 * 1024 * _1m
))) {
258 std::cout
<< "alloc " << i
/ 1024 / 1024 << " mb of "
259 << cap
/ 1024 / 1024 << std::endl
;
264 for (uint64_t i
= 0; i
< cap
; )
266 uint64_t want_release
= alloc_unit
<< u2(rng
);
267 uint64_t released
= 0;
271 interval_set
<uint64_t> release_set
;
272 if (!at
.pop_random(rng
, &o
, &l
, want_release
- released
)) {
275 release_set
.insert(o
, l
);
276 alloc
->release(release_set
);
278 } while (released
< want_release
);
280 uint32_t want
= alloc_unit
<< u1(rng
);
282 auto r
= alloc
->allocate(want
, alloc_unit
, 0, 0, &tmp
);
284 std::cout
<<"Can't allocate more space, stopping."<< std::endl
;
290 bool full
= !at
.push(a
.offset
, a
.length
);
291 EXPECT_EQ(full
, false);
294 if (0 == (i
% (1 * 1024 * _1m
))) {
295 std::cout
<< "reuse " << i
/ 1024 / 1024 << " mb of "
296 << cap
/ 1024 / 1024 << std::endl
;
299 std::cout
<<"Executed in "<< ceph_clock_now() - start
<< std::endl
;
300 std::cout
<<"Avail "<< alloc
->get_free() / _1m
<< " MB" << std::endl
;
305 TEST_P(AllocTest
, test_alloc_bench_90_300
)
307 uint64_t capacity
= uint64_t(1024) * 1024 * 1024 * 1024;
308 auto prefill
= capacity
- capacity
/ 10;
309 auto overwrite
= capacity
* 3;
310 doOverwriteTest(capacity
, prefill
, overwrite
);
313 TEST_P(AllocTest
, test_alloc_bench_50_300
)
315 uint64_t capacity
= uint64_t(1024) * 1024 * 1024 * 1024;
316 auto prefill
= capacity
/ 2;
317 auto overwrite
= capacity
* 3;
318 doOverwriteTest(capacity
, prefill
, overwrite
);
321 TEST_P(AllocTest
, test_alloc_bench_10_300
)
323 uint64_t capacity
= uint64_t(1024) * 1024 * 1024 * 1024;
324 auto prefill
= capacity
/ 10;
325 auto overwrite
= capacity
* 3;
326 doOverwriteTest(capacity
, prefill
, overwrite
);
329 TEST_P(AllocTest
, mempoolAccounting
)
331 uint64_t bytes
= mempool::bluestore_alloc::allocated_bytes();
332 uint64_t items
= mempool::bluestore_alloc::allocated_items();
334 uint64_t alloc_size
= 4 * 1024;
335 uint64_t capacity
= 512ll * 1024 * 1024 * 1024;
336 Allocator
* alloc
= Allocator::create(g_ceph_context
, string(GetParam()),
337 capacity
, alloc_size
);
338 ASSERT_NE(alloc
, nullptr);
339 alloc
->init_add_free(0, capacity
);
341 std::map
<uint32_t, PExtentVector
> all_allocs
;
342 for (size_t i
= 0; i
< 10000; i
++) {
344 alloc
->allocate(alloc_size
, alloc_size
, 0, 0, &tmp
);
345 all_allocs
[rand()] = tmp
;
346 alloc
->allocate(alloc_size
, alloc_size
, 0, 0, &tmp
);
347 all_allocs
[rand()] = tmp
;
349 auto it
= all_allocs
.upper_bound(rand());
350 if (it
!= all_allocs
.end()) {
351 alloc
->release(it
->second
);
352 all_allocs
.erase(it
);
357 ASSERT_EQ(mempool::bluestore_alloc::allocated_bytes(), bytes
);
358 ASSERT_EQ(mempool::bluestore_alloc::allocated_items(), items
);
361 INSTANTIATE_TEST_SUITE_P(
364 ::testing::Values("stupid", "bitmap", "avl", "hybrid"));