]>
Commit | Line | Data |
---|---|---|
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 |
26 | using namespace std; |
27 | ||
7c673cae FG |
28 | void 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 | ||
47 | template<typename A, typename B> | |
48 | void 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 | ||
60 | template<typename A, typename B> | |
61 | void 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> \ | |
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); \ | |
80 | } \ | |
81 | } | |
82 | ||
83 | MAKE_INSERTER(push_back); | |
84 | MAKE_INSERTER(insert); | |
85 | ||
86 | template<typename A,typename B> | |
87 | void 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 | ||
96 | TEST(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 | ||
124 | TEST(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 | ||
154 | TEST(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 | ||
177 | struct 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 | 188 | MEMPOOL_DEFINE_OBJECT_FACTORY(obj, obj, osdmap); |
7c673cae FG |
189 | |
190 | TEST(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 | ||
210 | TEST(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 | ||
224 | TEST(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 | ||
235 | TEST(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 | ||
250 | TEST(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 | ||
265 | TEST(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 | ||
307 | TEST(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 |
314 | TEST(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 |
326 | TEST(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 | 338 | TEST(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 |
371 | TEST(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 |
386 | TEST(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 |
407 | TEST(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 |
437 | int 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 | */ |