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"
28 void check_usage(mempool::pool_index_t ix
)
30 mempool::pool_t
*pool
= &mempool::get_pool(ix
);
31 mempool::stats_t total
;
32 map
<std::string
,mempool::stats_t
> m
;
33 pool
->get_stats(&total
, &m
);
34 size_t usage
= pool
->allocated_bytes();
37 sum
+= p
.second
.bytes
;
40 ceph::TableFormatter jf
;
44 EXPECT_EQ(sum
, usage
);
47 template<typename A
, typename B
>
48 void eq_elements(const A
& a
, const B
& b
)
52 while (lhs
!= a
.end()) {
57 EXPECT_EQ(rhs
,b
.end());
60 template<typename A
, typename B
>
61 void eq_pairs(const A
& a
, const B
& b
)
65 while (lhs
!= a
.end()) {
66 EXPECT_EQ(lhs
->first
,rhs
->first
);
67 EXPECT_EQ(lhs
->second
,rhs
->second
);
71 EXPECT_EQ(rhs
,b
.end());
74 #define MAKE_INSERTER(inserter) \
75 template<typename A,typename B> \
76 void do_##inserter(A& a, B& b, int count, int base) { \
77 for (int i = 0; i < count; ++i) { \
78 a.inserter(base + i); \
79 b.inserter(base + i); \
83 MAKE_INSERTER(push_back
);
84 MAKE_INSERTER(insert
);
86 template<typename A
,typename B
>
87 void do_insert_key(A
& a
, B
& b
, int count
, int base
)
89 for (int i
= 0; i
< count
; ++i
) {
90 a
.insert(make_pair(base
+i
,base
+i
));
91 b
.insert(make_pair(base
+i
,base
+i
));
92 check_usage(mempool::osd::id
);
96 TEST(mempool
, vector_context
)
98 check_usage(mempool::osd::id
);
99 EXPECT_EQ(mempool::osd::allocated_bytes(), 0u);
100 EXPECT_EQ(mempool::osd::allocated_items(), 0u);
101 for (unsigned i
= 0; i
< 10; ++i
) {
103 mempool::osd::vector
<int> b
,c
;
105 do_push_back(a
,b
,i
,i
);
107 check_usage(mempool::osd::id
);
109 mempool::stats_t total
;
110 map
<std::string
,mempool::stats_t
> by_type
;
111 mempool::get_pool(mempool::osd::id
).get_stats(&total
, &by_type
);
112 EXPECT_GE(mempool::osd::allocated_bytes(), i
* 4u);
113 EXPECT_GE(mempool::osd::allocated_items(), i
);
117 check_usage(mempool::osd::id
);
124 TEST(mempool
, list_context
)
126 for (unsigned i
= 1; i
< 10; ++i
) {
128 mempool::osd::list
<int> b
,c
;
130 do_push_back(a
,b
,i
,i
);
140 do_push_back(a
,b
,i
,i
);
141 c
.splice(c
.begin(),b
,b
.begin(),b
.end());
143 mempool::stats_t total
;
144 map
<std::string
,mempool::stats_t
> by_type
;
145 mempool::get_pool(mempool::osd::id
).get_stats(&total
, &by_type
);
146 EXPECT_GE(mempool::osd::allocated_bytes(), i
* 4u);
147 EXPECT_EQ(mempool::osd::allocated_items(), i
);
150 check_usage(mempool::osd::id
);
154 TEST(mempool
, set_context
)
156 for (int i
= 0; i
< 10; ++i
) {
158 mempool::osd::set
<int> b
;
161 check_usage(mempool::osd::id
);
164 for (int i
= 1; i
< 10; ++i
) {
166 mempool::osd::set
<int> b
;
168 EXPECT_NE(a
.find(i
/2),a
.end());
169 EXPECT_NE(b
.find(i
/2),b
.end());
170 a
.erase(a
.find(i
/2));
171 b
.erase(b
.find(i
/2));
173 check_usage(mempool::osd::id
);
178 MEMPOOL_CLASS_HELPERS();
181 obj() : a(1), b(1) {}
182 explicit obj(int _a
) : a(_a
), b(2) {}
183 obj(int _a
,int _b
) : a(_a
), b(_b
) {}
184 friend inline bool operator<(const obj
& l
, const obj
& r
) {
188 MEMPOOL_DEFINE_OBJECT_FACTORY(obj
, obj
, osdmap
);
190 TEST(mempool
, test_factory
)
193 obj
*o2
= new obj(10);
194 obj
*o3
= new obj(20,30);
195 check_usage(mempool::osdmap::id
);
196 EXPECT_NE(o1
,nullptr);
207 check_usage(mempool::osdmap::id
);
210 TEST(mempool
, vector
)
213 mempool::osd::vector
<int> v
;
218 mempool::osdmap::vector
<obj
> v
;
226 mempool::osd::set
<int> set_int
;
229 mempool::osdmap::set
<obj
> set_obj
;
230 set_obj
.insert(obj());
231 set_obj
.insert(obj(1));
232 set_obj
.insert(obj(1, 2));
238 mempool::osd::map
<int,int> v
;
243 mempool::osdmap::map
<int,obj
> v
;
253 mempool::osd::list
<int> v
;
258 mempool::osdmap::list
<obj
> v
;
269 Formatter
* f
= Formatter::create("xml-pretty", "xml-pretty", "xml-pretty");
274 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
279 f
= Formatter::create("html-pretty", "html-pretty", "html-pretty");
284 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
288 f
= Formatter::create("table", "table", "table");
293 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
298 f
= Formatter::create("json-pretty", "json-pretty", "json-pretty");
303 ASSERT_NE(ostr
.str().find(mempool::get_pool_name((mempool::pool_index_t
)0)),
307 TEST(mempool
, unordered_map
)
309 mempool::osdmap::unordered_map
<int,obj
> h
;
314 TEST(mempool
, string_test
)
316 mempool::osdmap::string s
;
318 EXPECT_GE(mempool::osdmap::allocated_items(), s
.capacity() + 1u); // +1 for zero-byte termination :
319 for (size_t i
= 0; i
< 10; ++i
) {
322 EXPECT_GE(mempool::osdmap::allocated_items(), s
.capacity() + 1u);
326 TEST(mempool
, bufferlist
)
330 size_t before
= mempool::buffer_anon::allocated_bytes();
331 cout
<< "before " << before
<< std::endl
;
332 bl
.append(buffer::create_aligned(len
, 4096));
333 size_t after
= mempool::buffer_anon::allocated_bytes();
334 cout
<< "after " << after
<< std::endl
;
335 ASSERT_GE(after
, before
+ len
);
338 TEST(mempool
, bufferlist_reassign
)
341 size_t items_before
= mempool::buffer_anon::allocated_items();
342 size_t bytes_before
= mempool::buffer_anon::allocated_bytes();
344 ASSERT_EQ(items_before
+ 1, mempool::buffer_anon::allocated_items());
345 ASSERT_LT(bytes_before
, mempool::buffer_anon::allocated_bytes());
348 bl
.reassign_to_mempool(mempool::mempool_osd
);
349 ASSERT_EQ(items_before
, mempool::buffer_anon::allocated_items());
350 ASSERT_EQ(bytes_before
, mempool::buffer_anon::allocated_bytes());
352 // additional appends should go to the same pool
353 items_before
= mempool::osd::allocated_items();
354 bytes_before
= mempool::osd::allocated_bytes();
355 cout
<< "anon b " << mempool::buffer_anon::allocated_bytes() << std::endl
;
356 for (unsigned i
= 0; i
< 1000; ++i
) {
357 bl
.append("asdfddddddddddddddddddddddasfdasdfasdfasdfasdfasdf");
359 cout
<< "anon a " << mempool::buffer_anon::allocated_bytes() << std::endl
;
360 ASSERT_LT(items_before
, mempool::osd::allocated_items());
361 ASSERT_LT(bytes_before
, mempool::osd::allocated_bytes());
364 items_before
= mempool::osd::allocated_items();
365 bytes_before
= mempool::osd::allocated_bytes();
366 bl
.try_assign_to_mempool(mempool::mempool_bloom_filter
);
367 ASSERT_EQ(items_before
, mempool::osd::allocated_items());
368 ASSERT_EQ(bytes_before
, mempool::osd::allocated_bytes());
371 TEST(mempool
, bufferlist_c_str
)
375 size_t before
= mempool::osd::allocated_bytes();
376 bl
.append(buffer::create_aligned(len
, 4096));
377 bl
.append(buffer::create_aligned(len
, 4096));
378 bl
.reassign_to_mempool(mempool::mempool_osd
);
379 size_t after
= mempool::osd::allocated_bytes();
380 ASSERT_GE(after
, before
+ len
* 2);
382 size_t after_c_str
= mempool::osd::allocated_bytes();
383 ASSERT_EQ(after
, after_c_str
);
386 TEST(mempool
, btree_map_test
)
388 typedef mempool::pool_allocator
<mempool::mempool_osd
,
389 pair
<const uint64_t,uint64_t>> allocator_t
;
390 typedef btree::btree_map
<uint64_t,uint64_t,std::less
<uint64_t>,allocator_t
> btree_t
;
394 ASSERT_EQ(0, mempool::osd::allocated_items());
395 ASSERT_EQ(0, mempool::osd::allocated_bytes());
396 for (size_t i
= 0; i
< 1000; ++i
) {
397 btree
[rand()] = rand();
399 ASSERT_LT(0, mempool::osd::allocated_items());
400 ASSERT_LT(0, mempool::osd::allocated_bytes());
403 ASSERT_EQ(0, mempool::osd::allocated_items());
404 ASSERT_EQ(0, mempool::osd::allocated_bytes());
407 TEST(mempool
, check_shard_select
)
409 const size_t samples
= mempool::num_shards
* 100;
410 std::atomic_int shards
[mempool::num_shards
] = {0};
411 std::vector
<std::thread
> workers
;
412 for (size_t i
= 0; i
< samples
; i
++) {
415 size_t i
= mempool::pool_t::pick_a_shard_int();
419 for (auto& t
:workers
) {
425 for (size_t i
= 0; i
< mempool::num_shards
; i
++) {
426 if (shards
[i
] == 0) {
431 // If more than half of the shards did not get anything,
432 // the distribution is bad enough to deserve a failure.
433 EXPECT_LT(missed
, mempool::num_shards
/ 2);
437 int main(int argc
, char **argv
)
439 auto args
= argv_to_vec(argc
, argv
);
441 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
442 CODE_ENVIRONMENT_UTILITY
,
443 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
444 common_init_finish(g_ceph_context
);
446 // enable debug mode for the tests
447 mempool::set_debug_mode(true);
449 ::testing::InitGoogleTest(&argc
, argv
);
450 return RUN_ALL_TESTS();
456 * compile-command: "cd ../../build ; make -j4 &&
457 * make unittest_mempool &&
458 * valgrind --tool=memcheck ./unittest_mempool --gtest_filter=*.*"