]>
Commit | Line | Data |
---|---|---|
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" | |
23 | #include "include/mempool.h" | |
24 | ||
25 | void check_usage(mempool::pool_index_t ix) | |
26 | { | |
27 | mempool::pool_t *pool = &mempool::get_pool(ix); | |
28 | mempool::stats_t total; | |
29 | map<std::string,mempool::stats_t> m; | |
30 | pool->get_stats(&total, &m); | |
31 | size_t usage = pool->allocated_bytes(); | |
32 | size_t sum = 0; | |
33 | for (auto& p : m) { | |
34 | sum += p.second.bytes; | |
35 | } | |
36 | if (sum != usage) { | |
37 | ceph::TableFormatter jf; | |
38 | pool->dump(&jf); | |
39 | jf.flush(std::cout); | |
40 | } | |
41 | EXPECT_EQ(sum, usage); | |
42 | } | |
43 | ||
44 | template<typename A, typename B> | |
45 | void eq_elements(const A& a, const B& b) | |
46 | { | |
47 | auto lhs = a.begin(); | |
48 | auto rhs = b.begin(); | |
49 | while (lhs != a.end()) { | |
50 | EXPECT_EQ(*lhs,*rhs); | |
51 | lhs++; | |
52 | rhs++; | |
53 | } | |
54 | EXPECT_EQ(rhs,b.end()); | |
55 | } | |
56 | ||
57 | template<typename A, typename B> | |
58 | void eq_pairs(const A& a, const B& b) | |
59 | { | |
60 | auto lhs = a.begin(); | |
61 | auto rhs = b.begin(); | |
62 | while (lhs != a.end()) { | |
63 | EXPECT_EQ(lhs->first,rhs->first); | |
64 | EXPECT_EQ(lhs->second,rhs->second); | |
65 | lhs++; | |
66 | rhs++; | |
67 | } | |
68 | EXPECT_EQ(rhs,b.end()); | |
69 | } | |
70 | ||
71 | #define MAKE_INSERTER(inserter) \ | |
72 | template<typename A,typename B> \ | |
73 | void do_##inserter(A& a, B& b, int count, int base) { \ | |
74 | for (int i = 0; i < count; ++i) { \ | |
75 | a.inserter(base + i); \ | |
76 | b.inserter(base + i); \ | |
77 | } \ | |
78 | } | |
79 | ||
80 | MAKE_INSERTER(push_back); | |
81 | MAKE_INSERTER(insert); | |
82 | ||
83 | template<typename A,typename B> | |
84 | void do_insert_key(A& a, B& b, int count, int base) | |
85 | { | |
86 | for (int i = 0; i < count; ++i) { | |
87 | a.insert(make_pair(base+i,base+i)); | |
88 | b.insert(make_pair(base+i,base+i)); | |
89 | check_usage(mempool::osd::id); | |
90 | } | |
91 | } | |
92 | ||
93 | TEST(mempool, vector_context) | |
94 | { | |
95 | check_usage(mempool::osd::id); | |
96 | EXPECT_EQ(mempool::osd::allocated_bytes(), 0u); | |
97 | EXPECT_EQ(mempool::osd::allocated_items(), 0u); | |
98 | for (unsigned i = 0; i < 10; ++i) { | |
99 | vector<int> a; | |
100 | mempool::osd::vector<int> b,c; | |
101 | eq_elements(a,b); | |
102 | do_push_back(a,b,i,i); | |
103 | eq_elements(a,b); | |
104 | check_usage(mempool::osd::id); | |
105 | ||
106 | mempool::stats_t total; | |
107 | map<std::string,mempool::stats_t> by_type; | |
108 | mempool::get_pool(mempool::osd::id).get_stats(&total, &by_type); | |
109 | EXPECT_GE(mempool::osd::allocated_bytes(), i * 4u); | |
110 | EXPECT_GE(mempool::osd::allocated_items(), i); | |
111 | ||
112 | c.swap(b); | |
113 | eq_elements(a,c); | |
114 | check_usage(mempool::osd::id); | |
115 | a.clear(); | |
116 | b.clear(); | |
117 | c.clear(); | |
118 | } | |
119 | } | |
120 | ||
121 | TEST(mempool, list_context) | |
122 | { | |
123 | for (unsigned i = 1; i < 10; ++i) { | |
124 | list<int> a; | |
125 | mempool::osd::list<int> b,c; | |
126 | eq_elements(a,b); | |
127 | do_push_back(a,b,i,i); | |
128 | eq_elements(a,b); | |
129 | c.swap(b); | |
130 | eq_elements(a,c); | |
131 | a.erase(a.begin()); | |
132 | c.erase(c.begin()); | |
133 | eq_elements(a,c); | |
134 | a.clear(); | |
135 | b.clear(); | |
136 | c.clear(); | |
137 | do_push_back(a,b,i,i); | |
138 | c.splice(c.begin(),b,b.begin(),b.end()); | |
139 | ||
140 | mempool::stats_t total; | |
141 | map<std::string,mempool::stats_t> by_type; | |
142 | mempool::get_pool(mempool::osd::id).get_stats(&total, &by_type); | |
143 | EXPECT_GE(mempool::osd::allocated_bytes(), i * 4u); | |
144 | EXPECT_EQ(mempool::osd::allocated_items(), i); | |
145 | ||
146 | eq_elements(a,c); | |
147 | check_usage(mempool::osd::id); | |
148 | } | |
149 | } | |
150 | ||
151 | TEST(mempool, set_context) | |
152 | { | |
153 | for (int i = 0; i < 10; ++i) { | |
154 | set<int> a; | |
155 | mempool::osd::set<int> b; | |
156 | do_insert(a,b,i,i); | |
157 | eq_elements(a,b); | |
158 | check_usage(mempool::osd::id); | |
159 | } | |
160 | ||
161 | for (int i = 1; i < 10; ++i) { | |
162 | set<int> a; | |
163 | mempool::osd::set<int> b; | |
164 | do_insert(a,b,i,0); | |
165 | EXPECT_NE(a.find(i/2),a.end()); | |
166 | EXPECT_NE(b.find(i/2),b.end()); | |
167 | a.erase(a.find(i/2)); | |
168 | b.erase(b.find(i/2)); | |
169 | eq_elements(a,b); | |
170 | check_usage(mempool::osd::id); | |
171 | } | |
172 | } | |
173 | ||
174 | struct obj { | |
175 | MEMPOOL_CLASS_HELPERS(); | |
176 | int a; | |
177 | int b; | |
178 | obj() : a(1), b(1) {} | |
179 | obj(int _a) : a(_a), b(2) {} | |
180 | obj(int _a,int _b) : a(_a), b(_b) {} | |
181 | friend inline bool operator<(const obj& l, const obj& r) { | |
182 | return l.a < r.a; | |
183 | } | |
184 | }; | |
185 | MEMPOOL_DEFINE_OBJECT_FACTORY(obj, obj, osdmap); | |
186 | ||
187 | TEST(mempool, test_factory) | |
188 | { | |
189 | obj *o1 = new obj(); | |
190 | obj *o2 = new obj(10); | |
191 | obj *o3 = new obj(20,30); | |
192 | check_usage(mempool::osdmap::id); | |
193 | EXPECT_NE(o1,nullptr); | |
194 | EXPECT_EQ(o1->a,1); | |
195 | EXPECT_EQ(o1->b,1); | |
196 | EXPECT_EQ(o2->a,10); | |
197 | EXPECT_EQ(o2->b,2); | |
198 | EXPECT_EQ(o3->a,20); | |
199 | EXPECT_EQ(o3->b,30); | |
200 | ||
201 | delete o1; | |
202 | delete o2; | |
203 | delete o3; | |
204 | check_usage(mempool::osdmap::id); | |
205 | } | |
206 | ||
207 | TEST(mempool, vector) | |
208 | { | |
209 | { | |
210 | mempool::osd::vector<int> v; | |
211 | v.push_back(1); | |
212 | v.push_back(2); | |
213 | } | |
214 | { | |
215 | mempool::osdmap::vector<obj> v; | |
216 | v.push_back(obj()); | |
217 | v.push_back(obj(1)); | |
218 | } | |
219 | } | |
220 | ||
221 | TEST(mempool, set) | |
222 | { | |
223 | mempool::osd::set<int> set_int; | |
224 | set_int.insert(1); | |
225 | set_int.insert(2); | |
226 | mempool::osdmap::set<obj> set_obj; | |
227 | set_obj.insert(obj()); | |
228 | set_obj.insert(obj(1)); | |
229 | set_obj.insert(obj(1, 2)); | |
230 | } | |
231 | ||
232 | TEST(mempool, map) | |
233 | { | |
234 | { | |
235 | mempool::osd::map<int,int> v; | |
236 | v[1] = 2; | |
237 | v[3] = 4; | |
238 | } | |
239 | { | |
240 | mempool::osdmap::map<int,obj> v; | |
241 | v[1] = obj(); | |
242 | v[2] = obj(2); | |
243 | v[3] = obj(2, 3); | |
244 | } | |
245 | } | |
246 | ||
247 | TEST(mempool, list) | |
248 | { | |
249 | { | |
250 | mempool::osd::list<int> v; | |
251 | v.push_back(1); | |
252 | v.push_back(2); | |
253 | } | |
254 | { | |
255 | mempool::osdmap::list<obj> v; | |
256 | v.push_back(obj()); | |
257 | v.push_back(obj(1)); | |
258 | } | |
259 | } | |
260 | ||
261 | TEST(mempool, unordered_map) | |
262 | { | |
263 | mempool::osdmap::unordered_map<int,obj> h; | |
264 | h[1] = obj(); | |
265 | h[2] = obj(1); | |
266 | } | |
267 | ||
268 | TEST(mempool, string_test) | |
269 | { | |
270 | mempool::osdmap::string s; | |
271 | s.reserve(100); | |
272 | EXPECT_GE(mempool::osdmap::allocated_items(), s.capacity() + 1u); // +1 for zero-byte termination : | |
273 | for (size_t i = 0; i < 10; ++i) { | |
274 | s += '1'; | |
275 | s.append(s); | |
276 | EXPECT_GE(mempool::osdmap::allocated_items(), s.capacity() + 1u); | |
277 | } | |
278 | } | |
279 | ||
280 | TEST(mempool, bufferlist) | |
281 | { | |
282 | bufferlist bl; | |
283 | int len = 1048576; | |
284 | size_t before = mempool::buffer_anon::allocated_bytes(); | |
285 | cout << "before " << before << std::endl; | |
286 | bl.append(buffer::create_aligned(len, 4096)); | |
287 | size_t after = mempool::buffer_anon::allocated_bytes(); | |
288 | cout << "after " << after << std::endl; | |
289 | ASSERT_GE(after, before + len); | |
290 | } | |
291 | ||
292 | TEST(mempool, bufferlist_reassign) | |
293 | { | |
294 | bufferlist bl; | |
295 | size_t items_before = mempool::buffer_anon::allocated_items(); | |
296 | size_t bytes_before = mempool::buffer_anon::allocated_bytes(); | |
297 | bl.append("fooo"); | |
298 | ASSERT_EQ(items_before + 1, mempool::buffer_anon::allocated_items()); | |
299 | ASSERT_LT(bytes_before, mempool::buffer_anon::allocated_bytes()); | |
300 | ||
301 | // move existing bl | |
302 | bl.reassign_to_mempool(mempool::mempool_osd); | |
303 | ASSERT_EQ(items_before, mempool::buffer_anon::allocated_items()); | |
304 | ASSERT_EQ(bytes_before, mempool::buffer_anon::allocated_bytes()); | |
305 | ||
306 | // additional appends should go to the same pool | |
307 | items_before = mempool::osd::allocated_items(); | |
308 | bytes_before = mempool::osd::allocated_bytes(); | |
309 | cout << "anon b " << mempool::buffer_anon::allocated_bytes() << std::endl; | |
310 | for (unsigned i = 0; i < 1000; ++i) { | |
311 | bl.append("asdfddddddddddddddddddddddasfdasdfasdfasdfasdfasdf"); | |
312 | } | |
313 | cout << "anon a " << mempool::buffer_anon::allocated_bytes() << std::endl; | |
314 | ASSERT_LT(items_before, mempool::osd::allocated_items()); | |
315 | ASSERT_LT(bytes_before, mempool::osd::allocated_bytes()); | |
316 | ||
317 | // try_.. won't | |
318 | items_before = mempool::osd::allocated_items(); | |
319 | bytes_before = mempool::osd::allocated_bytes(); | |
320 | bl.try_assign_to_mempool(mempool::mempool_bloom_filter); | |
321 | ASSERT_EQ(items_before, mempool::osd::allocated_items()); | |
322 | ASSERT_EQ(bytes_before, mempool::osd::allocated_bytes()); | |
323 | } | |
324 | ||
325 | int main(int argc, char **argv) | |
326 | { | |
327 | vector<const char*> args; | |
328 | argv_to_vec(argc, (const char **)argv, args); | |
329 | ||
330 | auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, | |
331 | CODE_ENVIRONMENT_UTILITY, 0); | |
332 | common_init_finish(g_ceph_context); | |
333 | ||
334 | // enable debug mode for the tests | |
335 | mempool::set_debug_mode(true); | |
336 | ||
337 | ::testing::InitGoogleTest(&argc, argv); | |
338 | return RUN_ALL_TESTS(); | |
339 | } | |
340 | ||
341 | ||
342 | /* | |
343 | * Local Variables: | |
344 | * compile-command: "cd ../../build ; make -j4 && | |
345 | * make unittest_mempool && | |
346 | * valgrind --tool=memcheck ./unittest_mempool --gtest_filter=*.*" | |
347 | * End: | |
348 | */ |