1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph distributed storage system
6 * Copyright (C) 2016 Western Digital Corporation
8 * Author: Allen Samuels <allen.samuels@sandisk.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
19 #include "global/global_init.h"
20 #include "common/ceph_argparse.h"
21 #include "global/global_context.h"
22 #include "gtest/gtest.h"
23 #include "include/btree_map.h"
24 #include "include/mempool.h"
26 void check_usage(mempool::pool_index_t ix
)
28 mempool::pool_t
*pool
= &mempool::get_pool(ix
);
29 mempool::stats_t total
;
30 map
<std::string
,mempool::stats_t
> m
;
31 pool
->get_stats(&total
, &m
);
32 size_t usage
= pool
->allocated_bytes();
35 sum
+= p
.second
.bytes
;
38 ceph::TableFormatter jf
;
42 EXPECT_EQ(sum
, usage
);
45 template<typename A
, typename B
>
46 void eq_elements(const A
& a
, const B
& b
)
50 while (lhs
!= a
.end()) {
55 EXPECT_EQ(rhs
,b
.end());
58 template<typename A
, typename B
>
59 void eq_pairs(const A
& a
, const B
& b
)
63 while (lhs
!= a
.end()) {
64 EXPECT_EQ(lhs
->first
,rhs
->first
);
65 EXPECT_EQ(lhs
->second
,rhs
->second
);
69 EXPECT_EQ(rhs
,b
.end());
72 #define MAKE_INSERTER(inserter) \
73 template<typename A,typename B> \
74 void do_##inserter(A& a, B& b, int count, int base) { \
75 for (int i = 0; i < count; ++i) { \
76 a.inserter(base + i); \
77 b.inserter(base + i); \
81 MAKE_INSERTER(push_back
);
82 MAKE_INSERTER(insert
);
84 template<typename A
,typename B
>
85 void do_insert_key(A
& a
, B
& b
, int count
, int base
)
87 for (int i
= 0; i
< count
; ++i
) {
88 a
.insert(make_pair(base
+i
,base
+i
));
89 b
.insert(make_pair(base
+i
,base
+i
));
90 check_usage(mempool::osd::id
);
94 TEST(mempool
, vector_context
)
96 check_usage(mempool::osd::id
);
97 EXPECT_EQ(mempool::osd::allocated_bytes(), 0u);
98 EXPECT_EQ(mempool::osd::allocated_items(), 0u);
99 for (unsigned i
= 0; i
< 10; ++i
) {
101 mempool::osd::vector
<int> b
,c
;
103 do_push_back(a
,b
,i
,i
);
105 check_usage(mempool::osd::id
);
107 mempool::stats_t total
;
108 map
<std::string
,mempool::stats_t
> by_type
;
109 mempool::get_pool(mempool::osd::id
).get_stats(&total
, &by_type
);
110 EXPECT_GE(mempool::osd::allocated_bytes(), i
* 4u);
111 EXPECT_GE(mempool::osd::allocated_items(), i
);
115 check_usage(mempool::osd::id
);
122 TEST(mempool
, list_context
)
124 for (unsigned i
= 1; i
< 10; ++i
) {
126 mempool::osd::list
<int> b
,c
;
128 do_push_back(a
,b
,i
,i
);
138 do_push_back(a
,b
,i
,i
);
139 c
.splice(c
.begin(),b
,b
.begin(),b
.end());
141 mempool::stats_t total
;
142 map
<std::string
,mempool::stats_t
> by_type
;
143 mempool::get_pool(mempool::osd::id
).get_stats(&total
, &by_type
);
144 EXPECT_GE(mempool::osd::allocated_bytes(), i
* 4u);
145 EXPECT_EQ(mempool::osd::allocated_items(), i
);
148 check_usage(mempool::osd::id
);
152 TEST(mempool
, set_context
)
154 for (int i
= 0; i
< 10; ++i
) {
156 mempool::osd::set
<int> b
;
159 check_usage(mempool::osd::id
);
162 for (int i
= 1; i
< 10; ++i
) {
164 mempool::osd::set
<int> b
;
166 EXPECT_NE(a
.find(i
/2),a
.end());
167 EXPECT_NE(b
.find(i
/2),b
.end());
168 a
.erase(a
.find(i
/2));
169 b
.erase(b
.find(i
/2));
171 check_usage(mempool::osd::id
);
176 MEMPOOL_CLASS_HELPERS();
179 obj() : a(1), b(1) {}
180 explicit obj(int _a
) : a(_a
), b(2) {}
181 obj(int _a
,int _b
) : a(_a
), b(_b
) {}
182 friend inline bool operator<(const obj
& l
, const obj
& r
) {
186 MEMPOOL_DEFINE_OBJECT_FACTORY(obj
, obj
, osdmap
);
188 TEST(mempool
, test_factory
)
191 obj
*o2
= new obj(10);
192 obj
*o3
= new obj(20,30);
193 check_usage(mempool::osdmap::id
);
194 EXPECT_NE(o1
,nullptr);
205 check_usage(mempool::osdmap::id
);
208 TEST(mempool
, vector
)
211 mempool::osd::vector
<int> v
;
216 mempool::osdmap::vector
<obj
> v
;
224 mempool::osd::set
<int> set_int
;
227 mempool::osdmap::set
<obj
> set_obj
;
228 set_obj
.insert(obj());
229 set_obj
.insert(obj(1));
230 set_obj
.insert(obj(1, 2));
236 mempool::osd::map
<int,int> v
;
241 mempool::osdmap::map
<int,obj
> v
;
251 mempool::osd::list
<int> v
;
256 mempool::osdmap::list
<obj
> v
;
267 Formatter
* f
= Formatter::create("xml-pretty", "xml-pretty", "xml-pretty");
272 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
277 f
= Formatter::create("html-pretty", "html-pretty", "html-pretty");
282 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
286 f
= Formatter::create("table", "table", "table");
291 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
296 f
= Formatter::create("json-pretty", "json-pretty", "json-pretty");
301 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
305 TEST(mempool
, unordered_map
)
307 mempool::osdmap::unordered_map
<int,obj
> h
;
312 TEST(mempool
, string_test
)
314 mempool::osdmap::string s
;
316 EXPECT_GE(mempool::osdmap::allocated_items(), s
.capacity() + 1u); // +1 for zero-byte termination :
317 for (size_t i
= 0; i
< 10; ++i
) {
320 EXPECT_GE(mempool::osdmap::allocated_items(), s
.capacity() + 1u);
324 TEST(mempool
, bufferlist
)
328 size_t before
= mempool::buffer_anon::allocated_bytes();
329 cout
<< "before " << before
<< std::endl
;
330 bl
.append(buffer::create_aligned(len
, 4096));
331 size_t after
= mempool::buffer_anon::allocated_bytes();
332 cout
<< "after " << after
<< std::endl
;
333 ASSERT_GE(after
, before
+ len
);
336 TEST(mempool
, bufferlist_reassign
)
339 size_t items_before
= mempool::buffer_anon::allocated_items();
340 size_t bytes_before
= mempool::buffer_anon::allocated_bytes();
342 ASSERT_EQ(items_before
+ 1, mempool::buffer_anon::allocated_items());
343 ASSERT_LT(bytes_before
, mempool::buffer_anon::allocated_bytes());
346 bl
.reassign_to_mempool(mempool::mempool_osd
);
347 ASSERT_EQ(items_before
, mempool::buffer_anon::allocated_items());
348 ASSERT_EQ(bytes_before
, mempool::buffer_anon::allocated_bytes());
350 // additional appends should go to the same pool
351 items_before
= mempool::osd::allocated_items();
352 bytes_before
= mempool::osd::allocated_bytes();
353 cout
<< "anon b " << mempool::buffer_anon::allocated_bytes() << std::endl
;
354 for (unsigned i
= 0; i
< 1000; ++i
) {
355 bl
.append("asdfddddddddddddddddddddddasfdasdfasdfasdfasdfasdf");
357 cout
<< "anon a " << mempool::buffer_anon::allocated_bytes() << std::endl
;
358 ASSERT_LT(items_before
, mempool::osd::allocated_items());
359 ASSERT_LT(bytes_before
, mempool::osd::allocated_bytes());
362 items_before
= mempool::osd::allocated_items();
363 bytes_before
= mempool::osd::allocated_bytes();
364 bl
.try_assign_to_mempool(mempool::mempool_bloom_filter
);
365 ASSERT_EQ(items_before
, mempool::osd::allocated_items());
366 ASSERT_EQ(bytes_before
, mempool::osd::allocated_bytes());
369 TEST(mempool
, bufferlist_c_str
)
373 size_t before
= mempool::osd::allocated_bytes();
374 bl
.append(buffer::create_aligned(len
, 4096));
375 bl
.append(buffer::create_aligned(len
, 4096));
376 bl
.reassign_to_mempool(mempool::mempool_osd
);
377 size_t after
= mempool::osd::allocated_bytes();
378 ASSERT_GE(after
, before
+ len
* 2);
380 size_t after_c_str
= mempool::osd::allocated_bytes();
381 ASSERT_EQ(after
, after_c_str
);
384 TEST(mempool
, btree_map_test
)
386 typedef mempool::pool_allocator
<mempool::mempool_osd
,
387 pair
<const uint64_t,uint64_t>> allocator_t
;
388 typedef btree::btree_map
<uint64_t,uint64_t,std::less
<uint64_t>,allocator_t
> btree_t
;
392 ASSERT_EQ(0, mempool::osd::allocated_items());
393 ASSERT_EQ(0, mempool::osd::allocated_bytes());
394 for (size_t i
= 0; i
< 1000; ++i
) {
395 btree
[rand()] = rand();
397 ASSERT_LT(0, mempool::osd::allocated_items());
398 ASSERT_LT(0, mempool::osd::allocated_bytes());
401 ASSERT_EQ(0, mempool::osd::allocated_items());
402 ASSERT_EQ(0, mempool::osd::allocated_bytes());
405 TEST(mempool
, check_shard_select
)
407 const size_t samples
= 100;
408 std::atomic_int shards
[mempool::num_shards
] = {0};
409 std::vector
<std::thread
> workers
;
410 for (size_t i
= 0; i
< samples
; i
++) {
413 size_t i
= mempool::pool_t::pick_a_shard_int();
417 for (auto& t
:workers
) {
422 double EX
= (double)samples
/ (double)mempool::num_shards
;
424 for (size_t i
= 0; i
< mempool::num_shards
; i
++) {
425 VarX
+= (EX
- shards
[i
]) * (EX
- shards
[i
]);
427 //random gives VarX below 200
428 //when half slots are 0, we get ~300
429 //when all samples go into one slot, we get ~9000
430 EXPECT_LT(VarX
, 200);
434 int main(int argc
, char **argv
)
436 vector
<const char*> args
;
437 argv_to_vec(argc
, (const char **)argv
, args
);
439 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
440 CODE_ENVIRONMENT_UTILITY
,
441 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
442 common_init_finish(g_ceph_context
);
444 // enable debug mode for the tests
445 mempool::set_debug_mode(true);
447 ::testing::InitGoogleTest(&argc
, argv
);
448 return RUN_ALL_TESTS();
454 * compile-command: "cd ../../build ; make -j4 &&
455 * make unittest_mempool &&
456 * valgrind --tool=memcheck ./unittest_mempool --gtest_filter=*.*"