]>
git.proxmox.com Git - ceph.git/blob - ceph/src/include/mempool.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 Allen Samuels <allen.samuels@sandisk.com>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #ifndef _CEPH_INCLUDE_MEMPOOL_H
16 #define _CEPH_INCLUDE_MEMPOOL_H
20 #include <unordered_map>
28 #include <common/Formatter.h>
29 #include "include/assert.h"
37 A memory pool is a method for accounting the consumption of memory of
40 Memory pools are statically declared (see pool_index_t).
42 Each memory pool tracks the number of bytes and items it contains.
44 Allocators can be declared and associated with a type so that they are
45 tracked independently of the pool total. This additional accounting
46 is optional and only incurs an overhead if the debugging is enabled at
47 runtime. This allows developers to see what types are consuming the
54 Using memory pools is very easy.
56 To create a new memory pool, simply add a new name into the list of
57 memory pools that's defined in "DEFINE_MEMORY_POOLS_HELPER". That's
60 For each memory pool that's created a C++ namespace is also
61 automatically created (name is same as in DEFINE_MEMORY_POOLS_HELPER).
62 That namespace contains a set of common STL containers that are predefined
63 with the appropriate allocators.
65 Thus for mempool "unittest_1" we have automatically available to us:
67 mempool::unittest_1::map
68 mempool::unittest_1::multimap
69 mempool::unittest_1::set
70 mempool::unittest_1::multiset
71 mempool::unittest_1::list
72 mempool::unittest_1::vector
73 mempool::unittest_1::unordered_map
76 Putting objects in a mempool
77 ----------------------------
79 In order to use a memory pool with a particular type, a few additional
80 declarations are needed.
85 MEMPOOL_CLASS_HELPERS();
89 Then, in an appropriate .cc file,
91 MEMPOOL_DEFINE_OBJECT_FACTORY(Foo, foo, unittest_1);
93 The second argument can generally be identical to the first, except
94 when the type contains a nested scope. For example, for
95 BlueStore::Onode, we need to do
97 MEMPOOL_DEFINE_OBJECT_FACTORY(BlueStore::Onode, bluestore_onode,
100 (This is just because we need to name some static variables and we
101 can't use :: in a variable name.)
103 In order to use the STL containers, simply use the namespaced variant
104 of the container type. For example,
106 mempool::unittest_1::map<int> myvec;
111 The simplest way to interrogate the process is with
116 This will dump information about *all* memory pools. When debug mode
117 is enabled, the runtime complexity of dump is O(num_shards *
118 num_types). When debug name is disabled it is O(num_shards).
120 You can also interrogate a specific pool programmatically with
122 size_t bytes = mempool::unittest_2::allocated_bytes();
123 size_t items = mempool::unittest_2::allocated_items();
125 The runtime complexity is O(num_shards).
127 Note that you cannot easily query per-type, primarily because debug
128 mode is optional and you should not rely on that information being
135 // --------------------------------------------------------------
136 // define memory pools
138 #define DEFINE_MEMORY_POOLS_HELPER(f) \
140 f(bluestore_meta_onode) \
141 f(bluestore_meta_other) \
154 // give them integer ids
155 #define P(x) mempool_##x,
157 DEFINE_MEMORY_POOLS_HELPER(P
)
158 num_pools
// Must be last.
162 extern bool debug_mode
;
163 extern void set_debug_mode(bool d
);
165 // --------------------------------------------------------------
168 // we shard pool stats across many shard_t's to reduce the amount
169 // of cacheline ping pong.
174 num_shards
= 1 << num_shard_bits
177 // align shard to a cacheline
179 std::atomic
<size_t> bytes
= {0};
180 std::atomic
<size_t> items
= {0};
181 char __padding
[128 - sizeof(std::atomic
<size_t>)*2];
182 } __attribute__ ((aligned (128)));
184 static_assert(sizeof(shard_t
) == 128, "shard_t should be cacheline-sized");
189 void dump(ceph::Formatter
*f
) const {
190 f
->dump_int("items", items
);
191 f
->dump_int("bytes", bytes
);
195 pool_t
& get_pool(pool_index_t ix
);
196 const char *get_pool_name(pool_index_t ix
);
199 const char *type_name
;
201 std::atomic
<ssize_t
> items
= {0}; // signed
204 struct type_info_hash
{
205 std::size_t operator()(const std::type_info
& k
) const {
206 return k
.hash_code();
211 shard_t shard
[num_shards
];
213 mutable std::mutex lock
; // only used for types list
214 std::unordered_map
<const char *, type_t
> type_map
;
218 // How much this pool consumes. O(<num_shards>)
220 size_t allocated_bytes() const;
221 size_t allocated_items() const;
223 shard_t
* pick_a_shard() {
225 // http://fossies.org/dox/glibc-2.24/pthread__self_8c_source.html
226 size_t me
= (size_t)pthread_self();
227 size_t i
= (me
>> 3) & ((1 << num_shard_bits
) - 1);
231 type_t
*get_type(const std::type_info
& ti
, size_t size
) {
232 std::lock_guard
<std::mutex
> l(lock
);
233 auto p
= type_map
.find(ti
.name());
234 if (p
!= type_map
.end()) {
237 type_t
&t
= type_map
[ti
.name()];
238 t
.type_name
= ti
.name();
243 // get pool stats. by_type is not populated if !debug
244 void get_stats(stats_t
*total
,
245 std::map
<std::string
, stats_t
> *by_type
) const;
247 void dump(ceph::Formatter
*f
) const;
250 void dump(ceph::Formatter
*f
);
253 // STL allocator for use with containers. All actual state
254 // is stored in the static pool_allocator_base_t, which saves us from
255 // passing the allocator to container constructors.
257 template<pool_index_t pool_ix
, typename T
>
258 class pool_allocator
{
260 type_t
*type
= nullptr;
263 typedef pool_allocator
<pool_ix
, T
> allocator_type
;
264 typedef T value_type
;
265 typedef value_type
*pointer
;
266 typedef const value_type
* const_pointer
;
267 typedef value_type
& reference
;
268 typedef const value_type
& const_reference
;
269 typedef std::size_t size_type
;
270 typedef std::ptrdiff_t difference_type
;
272 template<typename U
> struct rebind
{
273 typedef pool_allocator
<pool_ix
,U
> other
;
276 void init(bool force_register
) {
277 pool
= &get_pool(pool_ix
);
278 if (debug_mode
|| force_register
) {
279 type
= pool
->get_type(typeid(T
), sizeof(T
));
283 pool_allocator(bool force_register
=false) {
284 init(force_register
);
287 pool_allocator(const pool_allocator
<pool_ix
,U
>&) {
291 T
* allocate(size_t n
, void *p
= nullptr) {
292 size_t total
= sizeof(T
) * n
;
293 shard_t
*shard
= pool
->pick_a_shard();
294 shard
->bytes
+= total
;
299 T
* r
= reinterpret_cast<T
*>(new char[total
]);
303 void deallocate(T
* p
, size_t n
) {
304 size_t total
= sizeof(T
) * n
;
305 shard_t
*shard
= pool
->pick_a_shard();
306 shard
->bytes
-= total
;
311 delete[] reinterpret_cast<char*>(p
);
314 T
* allocate_aligned(size_t n
, size_t align
, void *p
= nullptr) {
315 size_t total
= sizeof(T
) * n
;
316 shard_t
*shard
= pool
->pick_a_shard();
317 shard
->bytes
+= total
;
323 int rc
= ::posix_memalign((void**)(void*)&ptr
, align
, total
);
325 throw std::bad_alloc();
326 T
* r
= reinterpret_cast<T
*>(ptr
);
330 void deallocate_aligned(T
* p
, size_t n
) {
331 size_t total
= sizeof(T
) * n
;
332 shard_t
*shard
= pool
->pick_a_shard();
333 shard
->bytes
-= total
;
350 void construct(T
* p
, const T
& val
) {
351 ::new ((void *)p
) T(val
);
354 template<class U
, class... Args
> void construct(U
* p
,Args
&&... args
) {
355 ::new((void *)p
) U(std::forward
<Args
>(args
)...);
358 bool operator==(const pool_allocator
&) const { return true; }
359 bool operator!=(const pool_allocator
&) const { return false; }
367 static const mempool::pool_index_t id = mempool::mempool_##x; \
368 template<typename v> \
369 using pool_allocator = mempool::pool_allocator<id,v>; \
371 using string = std::basic_string<char,std::char_traits<char>, \
372 pool_allocator<char>>; \
374 template<typename k,typename v, typename cmp = std::less<k> > \
375 using map = std::map<k, v, cmp, \
376 pool_allocator<std::pair<const k,v>>>; \
378 template<typename k,typename v, typename cmp = std::less<k> > \
379 using multimap = std::multimap<k,v,cmp, \
380 pool_allocator<std::pair<const k, \
383 template<typename k, typename cmp = std::less<k> > \
384 using set = std::set<k,cmp,pool_allocator<k>>; \
386 template<typename v> \
387 using list = std::list<v,pool_allocator<v>>; \
389 template<typename v> \
390 using vector = std::vector<v,pool_allocator<v>>; \
392 template<typename k, typename v, \
393 typename h=std::hash<k>, \
394 typename eq = std::equal_to<k>> \
395 using unordered_map = \
396 std::unordered_map<k,v,h,eq,pool_allocator<std::pair<const k,v>>>;\
398 inline size_t allocated_bytes() { \
399 return mempool::get_pool(id).allocated_bytes(); \
401 inline size_t allocated_items() { \
402 return mempool::get_pool(id).allocated_items(); \
406 DEFINE_MEMORY_POOLS_HELPER(P
)
414 // Use this for any type that is contained by a container (unless it
415 // is a class you defined; see below).
416 #define MEMPOOL_DECLARE_FACTORY(obj, factoryname, pool) \
417 namespace mempool { \
419 extern pool_allocator<obj> alloc_##factoryname; \
423 #define MEMPOOL_DEFINE_FACTORY(obj, factoryname, pool) \
424 namespace mempool { \
426 pool_allocator<obj> alloc_##factoryname = {true}; \
430 // Use this for each class that belongs to a mempool. For example,
433 // MEMPOOL_CLASS_HELPERS();
437 #define MEMPOOL_CLASS_HELPERS() \
438 void *operator new(size_t size); \
439 void *operator new[](size_t size) noexcept { \
440 assert(0 == "no array new"); \
442 void operator delete(void *); \
443 void operator delete[](void *) { assert(0 == "no array delete"); }
446 // Use this in some particular .cc file to match each class with a
447 // MEMPOOL_CLASS_HELPERS().
448 #define MEMPOOL_DEFINE_OBJECT_FACTORY(obj,factoryname,pool) \
449 MEMPOOL_DEFINE_FACTORY(obj, factoryname, pool) \
450 void *obj::operator new(size_t size) { \
451 return mempool::pool::alloc_##factoryname.allocate(1); \
453 void obj::operator delete(void *p) { \
454 return mempool::pool::alloc_##factoryname.deallocate((obj*)p, 1); \