]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/test_mempool.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / test_mempool.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph distributed storage system
5 *
6 * Copyright (C) 2016 Western Digital Corporation
7 *
8 * Author: Allen Samuels <allen.samuels@sandisk.com>
9 *
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.
14 *
15 */
16
17#include <stdio.h>
18
19#include "global/global_init.h"
20#include "common/ceph_argparse.h"
21#include "global/global_context.h"
22#include "gtest/gtest.h"
9f95a23c 23#include "include/btree_map.h"
7c673cae
FG
24#include "include/mempool.h"
25
20effc67
TL
26using namespace std;
27
7c673cae
FG
28void check_usage(mempool::pool_index_t ix)
29{
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();
35 size_t sum = 0;
36 for (auto& p : m) {
37 sum += p.second.bytes;
38 }
39 if (sum != usage) {
40 ceph::TableFormatter jf;
41 pool->dump(&jf);
42 jf.flush(std::cout);
43 }
44 EXPECT_EQ(sum, usage);
45}
46
47template<typename A, typename B>
48void eq_elements(const A& a, const B& b)
49{
50 auto lhs = a.begin();
51 auto rhs = b.begin();
52 while (lhs != a.end()) {
53 EXPECT_EQ(*lhs,*rhs);
54 lhs++;
55 rhs++;
56 }
57 EXPECT_EQ(rhs,b.end());
58}
59
60template<typename A, typename B>
61void eq_pairs(const A& a, const B& b)
62{
63 auto lhs = a.begin();
64 auto rhs = b.begin();
65 while (lhs != a.end()) {
66 EXPECT_EQ(lhs->first,rhs->first);
67 EXPECT_EQ(lhs->second,rhs->second);
68 lhs++;
69 rhs++;
70 }
71 EXPECT_EQ(rhs,b.end());
72}
73
74#define MAKE_INSERTER(inserter) \
75 template<typename A,typename B> \
76void 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); \
80 } \
81}
82
83MAKE_INSERTER(push_back);
84MAKE_INSERTER(insert);
85
86template<typename A,typename B>
87void do_insert_key(A& a, B& b, int count, int base)
88{
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));
31f18b77 92 check_usage(mempool::osd::id);
7c673cae
FG
93 }
94}
95
96TEST(mempool, vector_context)
97{
31f18b77
FG
98 check_usage(mempool::osd::id);
99 EXPECT_EQ(mempool::osd::allocated_bytes(), 0u);
100 EXPECT_EQ(mempool::osd::allocated_items(), 0u);
7c673cae
FG
101 for (unsigned i = 0; i < 10; ++i) {
102 vector<int> a;
31f18b77 103 mempool::osd::vector<int> b,c;
7c673cae
FG
104 eq_elements(a,b);
105 do_push_back(a,b,i,i);
106 eq_elements(a,b);
31f18b77 107 check_usage(mempool::osd::id);
7c673cae
FG
108
109 mempool::stats_t total;
110 map<std::string,mempool::stats_t> by_type;
31f18b77
FG
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);
7c673cae
FG
114
115 c.swap(b);
116 eq_elements(a,c);
31f18b77 117 check_usage(mempool::osd::id);
7c673cae
FG
118 a.clear();
119 b.clear();
120 c.clear();
121 }
122}
123
124TEST(mempool, list_context)
125{
126 for (unsigned i = 1; i < 10; ++i) {
127 list<int> a;
31f18b77 128 mempool::osd::list<int> b,c;
7c673cae
FG
129 eq_elements(a,b);
130 do_push_back(a,b,i,i);
131 eq_elements(a,b);
132 c.swap(b);
133 eq_elements(a,c);
134 a.erase(a.begin());
135 c.erase(c.begin());
136 eq_elements(a,c);
137 a.clear();
138 b.clear();
139 c.clear();
140 do_push_back(a,b,i,i);
141 c.splice(c.begin(),b,b.begin(),b.end());
142
143 mempool::stats_t total;
144 map<std::string,mempool::stats_t> by_type;
31f18b77
FG
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);
7c673cae
FG
148
149 eq_elements(a,c);
31f18b77 150 check_usage(mempool::osd::id);
7c673cae
FG
151 }
152}
153
154TEST(mempool, set_context)
155{
156 for (int i = 0; i < 10; ++i) {
157 set<int> a;
31f18b77 158 mempool::osd::set<int> b;
7c673cae
FG
159 do_insert(a,b,i,i);
160 eq_elements(a,b);
31f18b77 161 check_usage(mempool::osd::id);
7c673cae
FG
162 }
163
164 for (int i = 1; i < 10; ++i) {
165 set<int> a;
31f18b77 166 mempool::osd::set<int> b;
7c673cae
FG
167 do_insert(a,b,i,0);
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));
172 eq_elements(a,b);
31f18b77 173 check_usage(mempool::osd::id);
7c673cae
FG
174 }
175}
176
177struct obj {
178 MEMPOOL_CLASS_HELPERS();
179 int a;
180 int b;
181 obj() : a(1), b(1) {}
11fdf7f2 182 explicit obj(int _a) : a(_a), b(2) {}
7c673cae
FG
183 obj(int _a,int _b) : a(_a), b(_b) {}
184 friend inline bool operator<(const obj& l, const obj& r) {
185 return l.a < r.a;
186 }
187};
31f18b77 188MEMPOOL_DEFINE_OBJECT_FACTORY(obj, obj, osdmap);
7c673cae
FG
189
190TEST(mempool, test_factory)
191{
192 obj *o1 = new obj();
193 obj *o2 = new obj(10);
194 obj *o3 = new obj(20,30);
31f18b77 195 check_usage(mempool::osdmap::id);
7c673cae
FG
196 EXPECT_NE(o1,nullptr);
197 EXPECT_EQ(o1->a,1);
198 EXPECT_EQ(o1->b,1);
199 EXPECT_EQ(o2->a,10);
200 EXPECT_EQ(o2->b,2);
201 EXPECT_EQ(o3->a,20);
202 EXPECT_EQ(o3->b,30);
203
204 delete o1;
205 delete o2;
206 delete o3;
31f18b77 207 check_usage(mempool::osdmap::id);
7c673cae
FG
208}
209
210TEST(mempool, vector)
211{
212 {
31f18b77 213 mempool::osd::vector<int> v;
7c673cae
FG
214 v.push_back(1);
215 v.push_back(2);
216 }
217 {
31f18b77 218 mempool::osdmap::vector<obj> v;
7c673cae
FG
219 v.push_back(obj());
220 v.push_back(obj(1));
221 }
222}
223
224TEST(mempool, set)
225{
31f18b77 226 mempool::osd::set<int> set_int;
7c673cae
FG
227 set_int.insert(1);
228 set_int.insert(2);
31f18b77 229 mempool::osdmap::set<obj> set_obj;
7c673cae
FG
230 set_obj.insert(obj());
231 set_obj.insert(obj(1));
232 set_obj.insert(obj(1, 2));
233}
234
235TEST(mempool, map)
236{
237 {
31f18b77 238 mempool::osd::map<int,int> v;
7c673cae
FG
239 v[1] = 2;
240 v[3] = 4;
241 }
242 {
31f18b77 243 mempool::osdmap::map<int,obj> v;
7c673cae
FG
244 v[1] = obj();
245 v[2] = obj(2);
246 v[3] = obj(2, 3);
247 }
248}
249
250TEST(mempool, list)
251{
252 {
31f18b77 253 mempool::osd::list<int> v;
7c673cae
FG
254 v.push_back(1);
255 v.push_back(2);
256 }
257 {
31f18b77 258 mempool::osdmap::list<obj> v;
7c673cae
FG
259 v.push_back(obj());
260 v.push_back(obj(1));
261 }
11fdf7f2
TL
262
263}
264
265TEST(mempool, dump)
266{
267 ostringstream ostr;
268
269 Formatter* f = Formatter::create("xml-pretty", "xml-pretty", "xml-pretty");
270 mempool::dump(f);
271 f->flush(ostr);
272
273 delete f;
274 ASSERT_NE(ostr.str().find(mempool::get_pool_name((mempool::pool_index_t)0)),
275 std::string::npos);
276
277 ostr.str("");
278
279 f = Formatter::create("html-pretty", "html-pretty", "html-pretty");
280 mempool::dump(f);
281 f->flush(ostr);
282
283 delete f;
284 ASSERT_NE(ostr.str().find(mempool::get_pool_name((mempool::pool_index_t)0)),
285 std::string::npos);
286
287 ostr.str("");
288 f = Formatter::create("table", "table", "table");
289 mempool::dump(f);
290 f->flush(ostr);
291
292 delete f;
293 ASSERT_NE(ostr.str().find(mempool::get_pool_name((mempool::pool_index_t)0)),
294 std::string::npos);
295
296 ostr.str("");
297
298 f = Formatter::create("json-pretty", "json-pretty", "json-pretty");
299 mempool::dump(f);
300 f->flush(ostr);
301 delete f;
302
303 ASSERT_NE(ostr.str().find(mempool::get_pool_name((mempool::pool_index_t)0)),
304 std::string::npos);
7c673cae
FG
305}
306
307TEST(mempool, unordered_map)
308{
31f18b77 309 mempool::osdmap::unordered_map<int,obj> h;
7c673cae
FG
310 h[1] = obj();
311 h[2] = obj(1);
312}
313
31f18b77
FG
314TEST(mempool, string_test)
315{
316 mempool::osdmap::string s;
317 s.reserve(100);
318 EXPECT_GE(mempool::osdmap::allocated_items(), s.capacity() + 1u); // +1 for zero-byte termination :
319 for (size_t i = 0; i < 10; ++i) {
320 s += '1';
321 s.append(s);
322 EXPECT_GE(mempool::osdmap::allocated_items(), s.capacity() + 1u);
323 }
324}
325
7c673cae
FG
326TEST(mempool, bufferlist)
327{
328 bufferlist bl;
329 int len = 1048576;
31f18b77 330 size_t before = mempool::buffer_anon::allocated_bytes();
7c673cae
FG
331 cout << "before " << before << std::endl;
332 bl.append(buffer::create_aligned(len, 4096));
31f18b77 333 size_t after = mempool::buffer_anon::allocated_bytes();
7c673cae
FG
334 cout << "after " << after << std::endl;
335 ASSERT_GE(after, before + len);
336}
337
31f18b77 338TEST(mempool, bufferlist_reassign)
7c673cae 339{
31f18b77
FG
340 bufferlist bl;
341 size_t items_before = mempool::buffer_anon::allocated_items();
342 size_t bytes_before = mempool::buffer_anon::allocated_bytes();
343 bl.append("fooo");
344 ASSERT_EQ(items_before + 1, mempool::buffer_anon::allocated_items());
345 ASSERT_LT(bytes_before, mempool::buffer_anon::allocated_bytes());
346
347 // move existing bl
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());
351
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");
7c673cae 358 }
31f18b77
FG
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());
362
363 // try_.. won't
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());
7c673cae
FG
369}
370
adb31ebb
TL
371TEST(mempool, bufferlist_c_str)
372{
373 bufferlist bl;
374 int len = 1048576;
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);
381 bl.c_str();
382 size_t after_c_str = mempool::osd::allocated_bytes();
383 ASSERT_EQ(after, after_c_str);
384}
385
9f95a23c
TL
386TEST(mempool, btree_map_test)
387{
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;
391
392 {
393 btree_t btree;
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();
398 }
399 ASSERT_LT(0, mempool::osd::allocated_items());
400 ASSERT_LT(0, mempool::osd::allocated_bytes());
401 }
402
403 ASSERT_EQ(0, mempool::osd::allocated_items());
404 ASSERT_EQ(0, mempool::osd::allocated_bytes());
405}
406
f67539c2
TL
407TEST(mempool, check_shard_select)
408{
b3b6e05e 409 const size_t samples = mempool::num_shards * 100;
f67539c2
TL
410 std::atomic_int shards[mempool::num_shards] = {0};
411 std::vector<std::thread> workers;
412 for (size_t i = 0; i < samples; i++) {
413 workers.push_back(
414 std::thread([&](){
415 size_t i = mempool::pool_t::pick_a_shard_int();
416 shards[i]++;
417 }));
418 }
419 for (auto& t:workers) {
420 t.join();
421 }
422 workers.clear();
423
b3b6e05e 424 size_t missed = 0;
f67539c2 425 for (size_t i = 0; i < mempool::num_shards; i++) {
b3b6e05e
TL
426 if (shards[i] == 0) {
427 missed++;
428 }
f67539c2 429 }
b3b6e05e
TL
430
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);
f67539c2 434}
9f95a23c
TL
435
436
7c673cae
FG
437int main(int argc, char **argv)
438{
20effc67 439 auto args = argv_to_vec(argc, argv);
7c673cae
FG
440
441 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
11fdf7f2
TL
442 CODE_ENVIRONMENT_UTILITY,
443 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
7c673cae
FG
444 common_init_finish(g_ceph_context);
445
446 // enable debug mode for the tests
447 mempool::set_debug_mode(true);
448
449 ::testing::InitGoogleTest(&argc, argv);
450 return RUN_ALL_TESTS();
451}
452
453
454/*
455 * Local Variables:
456 * compile-command: "cd ../../build ; make -j4 &&
457 * make unittest_mempool &&
458 * valgrind --tool=memcheck ./unittest_mempool --gtest_filter=*.*"
459 * End:
460 */