mempool.h 17.1 KB
Newer Older
W
wangguibao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once
W
wangguibao 已提交
16 17 18 19 20

#ifdef BCLOUD
#include <base/atomicops.h>
#include <base/logging.h>
#else
W
wangguibao 已提交
21 22
#include <butil/atomicops.h>
#include <butil/logging.h>
W
wangguibao 已提交
23 24
#endif

W
wangguibao 已提交
25 26
#include <execinfo.h>
#include <pthread.h>
W
wangguibao 已提交
27
#include <iostream>
W
wangguibao 已提交
28 29 30
#include <new>
#include <sstream>
#include <string>
W
wangguibao 已提交
31 32 33 34

namespace im {
namespace fugue {

W
wangguibao 已提交
35 36 37 38
#ifdef BCLOUD
namespace butil = base;
#endif

W
wangguibao 已提交
39 40
namespace lockfree {

H
HexToString 已提交
41 42 43 44 45 46 47 48 49 50
/*
struct BigNode {
    BigNode* next;
    char data[0];
  };
*/
// template T is BigNode
// which is a node of variable length memory linked list
// _head is a BigNode* ptr, always points to the head node of the Stack.
// so PushOnlyStack is the head node of the Stack with some member function.
W
wangguibao 已提交
51 52
template <class T>
class PushOnlyStack {
W
wangguibao 已提交
53 54
 public:
  PushOnlyStack() { _head.store(NULL, butil::memory_order_relaxed); }
W
wangguibao 已提交
55

W
wangguibao 已提交
56 57 58 59 60 61
  void push(T* node) {
    T* head = _head.load(butil::memory_order_relaxed);
    node->next = head;
    while (
        !_head.compare_exchange_weak(head, node, butil::memory_order_relaxed)) {
      node->next = head;
W
wangguibao 已提交
62
    }
W
wangguibao 已提交
63
  }
W
wangguibao 已提交
64

H
HexToString 已提交
65 66 67
  T* releaseAndGetHeadPtr() {
    return _head.exchange(NULL, butil::memory_order_relaxed);
  }
W
wangguibao 已提交
68

W
wangguibao 已提交
69 70
 private:
  butil::atomic<T*> _head;
W
wangguibao 已提交
71 72
};

H
HexToString 已提交
73 74 75 76 77 78
// T can be class Block or class BlockReference
// class Block is 2M bytes memory
// class BlockReference is class Block* ptr.
// so the main member of FreeListNode is 2M bytes or class Block* ptr
// int 'id' is the index of itself in a FreeList.
// int 'next' is the index of next FreeListNode<T> in a FreeList.
W
wangguibao 已提交
79 80
template <class T>
struct FreeListNode {
W
wangguibao 已提交
81 82 83
  uint64_t id;
  uint64_t next;
  T data;
W
wangguibao 已提交
84 85
};

H
HexToString 已提交
86 87 88 89 90
// T can be class Block or class BlockReference
// CAP means capicity
// the main member of FreeList is FreeListNode<T>* [CAP].
// FreeList doesn`t realse the block data, it`s only an array of
// FreeListNode<T>* ptr.
W
wangguibao 已提交
91 92
template <class T, int CAP>
class FreeList {
W
wangguibao 已提交
93 94 95
 public:
  typedef FreeListNode<T> Node;
  static const uint64_t EMPTY = 0xFFFFFFFFFFFFFFFF;
W
wangguibao 已提交
96

H
HexToString 已提交
97
  // get the head Node`s member data ptr(T*)
W
wangguibao 已提交
98 99 100 101
  T* get() {
    uint64_t head = _head.load(butil::memory_order_acquire);
    if (head == EMPTY) {
      return new_node();
W
wangguibao 已提交
102 103
    }

H
HexToString 已提交
104 105 106 107 108 109 110 111 112 113
    // _head is atomic<int>, which means the head index.
    // head is the tempValue of _head.
    // maybe _head is not equals head anymore.
    // cause other thread may change the _head.
    /*compare_exchange_weak
    When the current value is equal to the expected value, modify the current
    value to the set value and return true
    When the current value is not equal to the expected value, modify the
    expected value to the current value and return false
    */
W
wangguibao 已提交
114 115 116 117 118 119 120 121 122 123
    Node* node = address(head);
    while (!_head.compare_exchange_weak(
        head, node->next, butil::memory_order_acquire)) {
      if (head == EMPTY) {
        return new_node();
      }
      node = address(head);
    }
    return &node->data;
  }
W
wangguibao 已提交
124

W
wangguibao 已提交
125
  void put(T* value) {
H
HexToString 已提交
126 127 128 129 130 131
    /*
    container_of
    according to the member(pointer type) of a Class
    to get the class Pointer
    for example
    T is the member of class Node, T data, 'data' is the name.
132
    T* value is the member(pointer type) of class Node
H
HexToString 已提交
133 134
    so we can get the Node* by calling container_of(value, Node, data)
    */
W
wangguibao 已提交
135
    Node* node = container_of(value, Node, data);
W
wangguibao 已提交
136

W
wangguibao 已提交
137
    uint64_t head = _head.load(butil::memory_order_acquire);
H
HexToString 已提交
138 139 140 141 142

    // node->id is int64. slot index is int32.
    // address(): slot = static_cast<uint32_t>(node->id)
    // will this be wrong?
    // add version? maybe this is different from new node?
W
wangguibao 已提交
143 144
    node->id += (1UL << 32);
    node->next = head;
W
wangguibao 已提交
145

W
wangguibao 已提交
146 147 148 149 150 151
    // NOTE: we MUST use a temp var *head* to call compare_exchange_weak
    // because Boost.Atomic will update the *expected* even success
    // std::atomic do not have this limitation
    while (!_head.compare_exchange_weak(
        head, node->id, butil::memory_order_release)) {
      node->next = head;
W
wangguibao 已提交
152
    }
W
wangguibao 已提交
153
  }
W
wangguibao 已提交
154

H
HexToString 已提交
155 156 157
  // F is callable class, class PutBlockByReference.
  // actually, F is the function put.
  // this function put the reuse the used block or blockReference
W
wangguibao 已提交
158 159 160 161 162
  template <class F>
  void unsafe_foreach() {
    uint32_t used_blk_cnt = _slot_index.load(butil::memory_order_relaxed);
    for (uint32_t i = 0; i < used_blk_cnt; ++i) {
      F()(&_node[i]->data);
W
wangguibao 已提交
163
    }
W
wangguibao 已提交
164
  }
W
wangguibao 已提交
165

W
wangguibao 已提交
166 167 168 169 170
  uint32_t real_used_size() const {
    uint32_t used_blk_cnt = _slot_index.load(butil::memory_order_relaxed);
    uint64_t used_bytes = 0;
    for (uint32_t i = 0; i < used_blk_cnt; ++i) {
      used_bytes += _node[i]->data.offset;
W
wangguibao 已提交
171
    }
H
HexToString 已提交
172
    // used_bytes/1024 = KB
W
wangguibao 已提交
173 174
    return used_bytes >> 10;
  }
W
wangguibao 已提交
175

H
HexToString 已提交
176
  uint32_t get_number_of_allocate_blocks() const {
W
wangguibao 已提交
177 178
    return _slot_index.load(butil::memory_order_relaxed);
  }
W
wangguibao 已提交
179

H
HexToString 已提交
180
  uint32_t get_number_of_free_blocks() const {
W
wangguibao 已提交
181 182 183 184 185 186
    uint64_t head = _head.load(butil::memory_order_relaxed);
    uint32_t size = 0;
    while (head != FreeList::EMPTY) {
      const Node* head_ptr = address(head);
      head = head_ptr->next;
      ++size;
W
wangguibao 已提交
187
    }
W
wangguibao 已提交
188 189
    return size;
  }
W
wangguibao 已提交
190

W
wangguibao 已提交
191 192 193 194
  void reset() {
    _head.store(FreeList::EMPTY, butil::memory_order_relaxed);
    _slot_index.store(0, butil::memory_order_relaxed);
  }
W
wangguibao 已提交
195

W
wangguibao 已提交
196 197 198
  FreeList() {
    for (int i = 0; i < CAP; ++i) {
      _node[i] = NULL;
W
wangguibao 已提交
199
    }
W
wangguibao 已提交
200 201
    reset();
  }
W
wangguibao 已提交
202

W
wangguibao 已提交
203 204
 private:
  uint32_t slot(uint64_t id) const { return static_cast<uint32_t>(id); }
W
wangguibao 已提交
205

W
wangguibao 已提交
206 207 208 209 210
  T* new_node() {
    uint32_t index = _slot_index.fetch_add(1, butil::memory_order_relaxed);
    if (index >= CAP) {
      return NULL;
    }
W
wangguibao 已提交
211

W
wangguibao 已提交
212 213 214
    if (_node[index] != NULL) {
      return &(_node[index]->data);
    }
W
wangguibao 已提交
215

W
wangguibao 已提交
216 217
    Node* node = reinterpret_cast<Node*>(malloc(sizeof(Node)));
    new (node) Node;
W
wangguibao 已提交
218

W
wangguibao 已提交
219 220
    node->id = index;
    _node[index] = node;
W
wangguibao 已提交
221

W
wangguibao 已提交
222 223
    return &node->data;
  }
W
wangguibao 已提交
224

W
wangguibao 已提交
225
  Node* address(uint64_t id) { return _node[slot(id)]; }
W
wangguibao 已提交
226

W
wangguibao 已提交
227
  const Node* address(uint64_t id) const { return _node[slot(id)]; }
W
wangguibao 已提交
228

W
wangguibao 已提交
229 230 231 232 233
  butil::atomic<uint64_t> _head;
  butil::atomic<uint32_t> _slot_index;
  Node* _node[CAP];
};
}  // namespace lockfree
W
wangguibao 已提交
234 235 236

namespace memory {

H
HexToString 已提交
237
// Memory is 2M bytes
W
wangguibao 已提交
238
struct Block {
H
HexToString 已提交
239
  static const int BLOCK_SIZE = 2 * 1024 * 1024;  // 2MB
W
wangguibao 已提交
240
  char data[BLOCK_SIZE];
W
wangguibao 已提交
241 242
};

H
HexToString 已提交
243
// Block* and offset
W
wangguibao 已提交
244
struct BlockReference {
W
wangguibao 已提交
245 246 247
  BlockReference() : offset(0), block(NULL) {
    // do nothing
  }
W
wangguibao 已提交
248

W
wangguibao 已提交
249 250 251 252
  void reset() {
    offset = 0;
    block = NULL;
  }
W
wangguibao 已提交
253

W
wangguibao 已提交
254 255
  uint32_t offset;
  Block* block;
W
wangguibao 已提交
256 257
};

H
HexToString 已提交
258 259 260 261 262 263
// This is a real singleton class FreeList<Block,MAX_BLOCK_COUNT>
// FreeList is always an array of FreeListNode<Block>* ptr.
// Block(2MB) is created when get() is called.

// because BlockFreeList is a threal-safe Singleton.
// so we don`t release Block, it is global memory.
264 265 266 267 268
// total number is 256*1024.
// the MAX_BLOCK_COUNT of Region(one thread one Region) is 1024.
// so BlockFreeList allow 256 Region(means 256 thread).
// the memory used by BlockFreeListType is sizeof(void*)*256*1024.
// Block(2MB) memory is created only when get() is called.
H
HexToString 已提交
269 270
class BlockFreeList {
 public:
H
HexToString 已提交
271
  static const int MAX_BLOCK_COUNT = 256 * 1024;
H
HexToString 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284
  typedef lockfree::FreeList<Block, MAX_BLOCK_COUNT> BlockFreeListType;
  static BlockFreeListType* instance() {
    static BlockFreeListType singleton;
    return &singleton;
  }
};

// _big_mem_capacity: a large memory is owned by Region.
// _bigNode_Stack: A list of bigNode(variable length memory)is owned by
// Region,the number is unlimit.
// _blockReference_FreeList: a FreeList of Block(2MB) is owned by singleton
// BlockFreeList, which is global.
// we can borrow 1024*Block from BlockFreeList.
W
wangguibao 已提交
285
class Region {
W
wangguibao 已提交
286
 public:
H
HexToString 已提交
287
  struct PutBlockByReference {
W
wangguibao 已提交
288 289
    void operator()(BlockReference* block_ref) {
      if (block_ref->block != NULL) {
H
HexToString 已提交
290
        BlockFreeList::instance()->put(block_ref->block);
W
wangguibao 已提交
291 292 293 294
      }
      block_ref->reset();
    }
  };
W
wangguibao 已提交
295

H
HexToString 已提交
296
  // this is a variable length memory node.
W
wangguibao 已提交
297 298 299 300
  struct BigNode {
    BigNode* next;
    char data[0];
  };
W
wangguibao 已提交
301

W
wangguibao 已提交
302 303 304 305 306
  ~Region() {
    reset();
    delete[] _big_mem_start;
    _big_mem_start = NULL;
  }
W
wangguibao 已提交
307

W
wangguibao 已提交
308
  char const* debug_str() const {
H
HexToString 已提交
309 310 311 312
    uint32_t alloc_blocks =
        _blockReference_FreeList.get_number_of_allocate_blocks();
    uint32_t free_blocks = _blockReference_FreeList.get_number_of_free_blocks();
    uint32_t used_mem_mb = _blockReference_FreeList.real_used_size();
W
wangguibao 已提交
313 314
    uint32_t big_buf_size = _big_mem_size.load(butil::memory_order_relaxed);
    uint32_t big_buf_count = _big_mem_count.load(butil::memory_order_relaxed);
H
HexToString 已提交
315 316 317 318
    uint32_t mlc_mem_size =
        _total_bigNode_size.load(butil::memory_order_relaxed);
    uint32_t mlc_mem_count =
        _total_bigNode_count.load(butil::memory_order_relaxed);
W
wangguibao 已提交
319

W
wangguibao 已提交
320 321 322 323 324 325 326
    std::ostringstream oss;
    oss << "[alloc_blks:" << alloc_blocks << ",free_blks:" << free_blocks
        << ",used_mem_kb:" << used_mem_mb
        << ",big_mem_kb:" << (big_buf_size >> 10)
        << ",big_buf_cnt:" << big_buf_count
        << ",mlc_mem_kb:" << (mlc_mem_size >> 10)
        << ",mlc_cnt:" << mlc_mem_count << "]";
W
wangguibao 已提交
327

W
wangguibao 已提交
328 329
    return oss.str().c_str();
  }
W
wangguibao 已提交
330

W
wangguibao 已提交
331
  Region();
W
wangguibao 已提交
332

W
wangguibao 已提交
333
  void init();
W
wangguibao 已提交
334

W
wangguibao 已提交
335
  void reset();
W
wangguibao 已提交
336

W
wangguibao 已提交
337
  BlockReference* get();
W
wangguibao 已提交
338

W
wangguibao 已提交
339
  void* malloc(size_t size);
W
wangguibao 已提交
340

H
HexToString 已提交
341
  void put(BlockReference* blockReference);
W
wangguibao 已提交
342

H
HexToString 已提交
343 344 345 346
  static const int MAX_BLOCK_COUNT = 1024;  // each Block is 2MB
  static const int BIG_MEM_THRESHOLD =
      2 * 1024 *
      1024;  // 2MB,means when you need less than 2M, get memory from Block.
H
HexToString 已提交
347

H
HexToString 已提交
348 349
  // 128MB,means when you need less than 128MB, get memory from BigMemory
  // instead
H
HexToString 已提交
350
  // of BigNode
H
HexToString 已提交
351
  static const int BIGNODE_MEM_THRESHOLD = (128 * 1024 * 1024 + 1);
H
HexToString 已提交
352 353
  static const int COUNTER_SIZE =
      BIGNODE_MEM_THRESHOLD / BIG_MEM_THRESHOLD + 1;  // this is not used
W
wangguibao 已提交
354

W
wangguibao 已提交
355
 private:
H
HexToString 已提交
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
  lockfree::FreeList<BlockReference, MAX_BLOCK_COUNT> _blockReference_FreeList;

  // _total_bigNode_size is the total size of BigNodeStack.
  // _total_bigNode_count is the total count of BigNodeStack.
  // BigNode is variable length memory.
  lockfree::PushOnlyStack<BigNode> _bigNode_Stack;
  butil::atomic<uint32_t> _total_bigNode_size;
  butil::atomic<uint32_t> _total_bigNode_count;

  // '_big_mem_start' points to a single big memory belong to Region.
  // _big_mem_capacity is the size of single big memory.
  // _big_mem_size is the already used size.
  // _big_mem_count is the used count.
  char* _big_mem_start;
  uint32_t _big_mem_capacity;  // 32M
W
wangguibao 已提交
371 372 373 374 375
  butil::atomic<uint32_t> _big_mem_size;
  butil::atomic<uint32_t> _big_mem_count;
};
}  // namespace memory
}  // namespace fugue
W
wangguibao 已提交
376 377

class Mempool {
W
wangguibao 已提交
378 379 380
 public:
  void* malloc(size_t size) {
    size = _align(size);
H
HexToString 已提交
381
    // It does not enter the if statement the first time.
382 383
    // The if statement may enter after the block is created.
    // If the block has not been used up, it will enter.
W
wangguibao 已提交
384 385 386 387 388
    if (size <= _free_size) {
      void* p = _free_cursor;
      _free_size -= size;
      _free_cursor += size;
      return p;
W
wangguibao 已提交
389 390
    }

W
wangguibao 已提交
391 392
    return malloc_from_region(size);
  }
W
wangguibao 已提交
393

W
wangguibao 已提交
394
  void free(void* p, size_t size) {
H
HexToString 已提交
395 396 397
    // size>Block(2M)
    // other memory is managed by Region,no need to release here.
    if (size > fugue::memory::Region::BIG_MEM_THRESHOLD) {
W
wangguibao 已提交
398
      return;
W
wangguibao 已提交
399 400
    }

401
    // memory in _block,update the pointer.
W
wangguibao 已提交
402
    if (_free_cursor - size == static_cast<char*>(p)) {
H
HexToString 已提交
403 404
      // for example, you need to release -(8+1)bytes
      // you can only release -8bytes,cause -(8+2)byte is used by other.
W
wangguibao 已提交
405 406 407 408 409
      size_t down_aligned = _down_align(size);
      _free_cursor -= down_aligned;
      _free_size += down_aligned;
    }
  }
W
wangguibao 已提交
410

W
wangguibao 已提交
411
  void* realloc(void* old_data, size_t old_size, size_t new_size) {
H
HexToString 已提交
412
    // Return the pointer directly and reuse it without expansion.
W
wangguibao 已提交
413 414 415
    if (old_size >= new_size) {
      return old_data;
    }
W
wangguibao 已提交
416

W
wangguibao 已提交
417 418 419 420 421 422 423
    size_t required = new_size - old_size;
    if (_free_cursor == static_cast<char*>(old_data) + old_size) {
      if (_free_size >= required) {
        _free_cursor += required;
        _free_size -= required;
        return old_data;
      } else {
H
HexToString 已提交
424 425 426
        // old_data will copy to other structure
        // so _free_cursor rollback,means the memory used by old_data can be
        // used.
W
wangguibao 已提交
427 428 429
        _free_cursor = static_cast<char*>(old_data);
        _free_size += old_size;
      }
W
wangguibao 已提交
430 431
    }

H
HexToString 已提交
432
    // 可能返回的是单独Region中malloc的内存。
433 434
    // 也可能是Block,例如new_size=1M, old_data原本的指针头就在1.2M处
    // old_size = 0.5M
H
HexToString 已提交
435 436
    // 此时,_free_size = 0.3M,new_size<2M,但是required = 1-0.5 >0.3
    // 分配出来的就是Block,但是该Block没有并很完美的利用完全。
W
wangguibao 已提交
437 438 439 440
    void* p = this->malloc_from_region(new_size);
    if (p != NULL) {
      memcpy(p, old_data, old_size);
      return p;
W
wangguibao 已提交
441 442
    }

W
wangguibao 已提交
443 444 445
    return NULL;
  }

H
HexToString 已提交
446 447 448
  explicit Mempool(fugue::memory::Region* region)
      : _free_size(0), _free_cursor(NULL), _region(region) {
    _blockReference = NULL;
W
wangguibao 已提交
449 450 451 452 453
  }

  ~Mempool() { release_block(); }

  void release_block() {
H
HexToString 已提交
454 455 456
    if (_blockReference) {
      _blockReference->offset = fugue::memory::Block::BLOCK_SIZE - _free_size;
      _region->put(_blockReference);
W
wangguibao 已提交
457 458
    }

W
wangguibao 已提交
459 460
    _free_size = 0;
    _free_cursor = NULL;
H
HexToString 已提交
461
    _blockReference = NULL;
W
wangguibao 已提交
462
  }
W
wangguibao 已提交
463

W
wangguibao 已提交
464 465
 private:
  void* malloc_from_region(size_t size) {
H
HexToString 已提交
466 467 468 469
    // if greater than BIG_MEM_THRESHOLD, _region->malloc
    // else get the memory from the Block.
    if (size > fugue::memory::Region::BIG_MEM_THRESHOLD) {
      return _region->malloc(size);
W
wangguibao 已提交
470 471
    }

W
wangguibao 已提交
472
    while (true) {
H
HexToString 已提交
473 474
      fugue::memory::BlockReference* blockReference = _region->get();
      if (blockReference == NULL) {
W
wangguibao 已提交
475 476
        return NULL;
      }
W
wangguibao 已提交
477

H
HexToString 已提交
478 479 480
      uint32_t free_size =
          fugue::memory::Block::BLOCK_SIZE - blockReference->offset;
      // 若未能满足要求,则while下一次循环,那么上次的block必然成为野值。
W
wangguibao 已提交
481
      if (size <= free_size) {
H
HexToString 已提交
482 483 484 485 486 487 488
        // 试图更新该节点的offset,但是该结点已经变成了野值,无法被再次使用了,只有等待归还。
        // 应将该节点put进队列,进入该判断语句内,证明本来get已肯定可以return.
        // 此时,上次没用完的值,应该更新offset后,还回去,下次没准还能用,不至于浪费。
        if (_blockReference) {
          _blockReference->offset =
              fugue::memory::Block::BLOCK_SIZE - _free_size;
          _region->put(_blockReference);
W
wangguibao 已提交
489
        }
W
wangguibao 已提交
490

H
HexToString 已提交
491
        char* p = blockReference->block->data + blockReference->offset;
W
wangguibao 已提交
492 493
        _free_size = free_size - size;
        _free_cursor = p + size;
H
HexToString 已提交
494
        _blockReference = blockReference;
W
wangguibao 已提交
495 496
        return p;
      }
W
wangguibao 已提交
497
    }
H
HexToString 已提交
498 499
    // It's not executed at all, for the sake of syntax.
    return _region->malloc(size);
W
wangguibao 已提交
500
  }
W
wangguibao 已提交
501

W
wangguibao 已提交
502
  static const int ALIGN_SIZE = sizeof(void*);
W
wangguibao 已提交
503

H
HexToString 已提交
504
  // align to the 8bytes, if (8+1), it will be (8+8)bytes.
W
wangguibao 已提交
505 506 507
  inline size_t _align(size_t size) const {
    return (size + (ALIGN_SIZE - 1)) & ~(ALIGN_SIZE - 1);
  }
W
wangguibao 已提交
508

H
HexToString 已提交
509
  // down_align to 8bytes, if (8+1), it will be (8+0)bytes.
W
wangguibao 已提交
510 511 512
  inline size_t _down_align(size_t size) const {
    return size & ~(ALIGN_SIZE - 1);
  }
W
wangguibao 已提交
513

W
wangguibao 已提交
514 515
  size_t _free_size;
  char* _free_cursor;
W
wangguibao 已提交
516

H
HexToString 已提交
517 518
  fugue::memory::Region* _region;
  fugue::memory::BlockReference* _blockReference;
W
wangguibao 已提交
519 520
};

H
HexToString 已提交
521 522 523
// use threal-local key instead of __thread.
// it`s not referenced.
/*
W
wangguibao 已提交
524
extern __thread Mempool* g_mempool;
H
HexToString 已提交
525 526 527 528 529
*/

// class mempool is a Interface.
// it`s not necessary at all.
/*
W
wangguibao 已提交
530
class mempool {
W
wangguibao 已提交
531 532 533 534
 public:
  virtual void* malloc(size_t size) = 0;
  virtual void free(void* p, size_t size) = 0;
  inline virtual ~mempool() {}
W
wangguibao 已提交
535
};
H
HexToString 已提交
536
*/
W
wangguibao 已提交
537

H
HexToString 已提交
538 539 540 541 542
// GlobalMempool is a Singleton-RAII class.
// It`s propose is to manage the thread-local pointer 'g_mempool'(class
// Mempool*)
// It`s not referenced, so it`s useless.
/*
W
wangguibao 已提交
543
class GlobalMempool : public mempool {
W
wangguibao 已提交
544 545 546 547
 public:
  GlobalMempool() {
    // do nothing;
  }
W
wangguibao 已提交
548

W
wangguibao 已提交
549 550 551
  virtual ~GlobalMempool() {
    // do nothing;
  }
W
wangguibao 已提交
552

W
wangguibao 已提交
553 554 555 556
  static GlobalMempool* instance() {
    static GlobalMempool singleton;
    return &singleton;
  }
W
wangguibao 已提交
557

W
wangguibao 已提交
558
  void reset(Mempool* mempool) { g_mempool = mempool; }
W
wangguibao 已提交
559

W
wangguibao 已提交
560
  void* malloc(size_t size) { return g_mempool->malloc(size); }
W
wangguibao 已提交
561

W
wangguibao 已提交
562 563 564
  void* realloc(void* old_data, size_t old_size, size_t new_size) {
    return g_mempool->realloc(old_data, old_size, new_size);
  }
W
wangguibao 已提交
565

W
wangguibao 已提交
566
  void free(void* p, size_t s) { g_mempool->free(p, s); }
W
wangguibao 已提交
567

W
wangguibao 已提交
568
  void clear() { g_mempool->release_block(); }
W
wangguibao 已提交
569

W
wangguibao 已提交
570
  Mempool* get() { return g_mempool; }
W
wangguibao 已提交
571
};
H
HexToString 已提交
572
*/
W
wangguibao 已提交
573

H
HexToString 已提交
574 575 576 577 578
// MempoolGuard is a RAII class.
// It`s propose is to manage the thread-local pointer 'g_mempool'(class
// Mempool*)
// It`s not referenced, so it`s useless.
/*
W
wangguibao 已提交
579
class MempoolGuard {
W
wangguibao 已提交
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
 public:
  explicit MempoolGuard(fugue::memory::Region* region) : _mempool(region) {
    acquire();
  }

  void acquire() {
    _saved_mempool = g_mempool;
    g_mempool = &_mempool;
  }

  void release() {
    _mempool.release_block();
    g_mempool = _saved_mempool;
  }

  ~MempoolGuard() { release(); }

 private:
  Mempool _mempool;
  Mempool* _saved_mempool;
W
wangguibao 已提交
600
};
H
HexToString 已提交
601
*/
W
wangguibao 已提交
602
inline std::string print_trace() {
W
wangguibao 已提交
603 604
  static const int BT_BUF_SIZE = 400;
  std::stringstream debug_stream;
W
wangguibao 已提交
605

W
wangguibao 已提交
606 607 608
  void* buffer[BT_BUF_SIZE];
  int nptrs = backtrace(buffer, BT_BUF_SIZE);
  char** strings = backtrace_symbols(buffer, nptrs);
W
wangguibao 已提交
609

W
wangguibao 已提交
610 611 612
  for (int j = 0; j < nptrs; j++) {
    debug_stream << strings[j] << "\t";
  }
W
wangguibao 已提交
613

W
wangguibao 已提交
614
  return debug_stream.str();
W
wangguibao 已提交
615
}
W
wangguibao 已提交
616
}  // namespace im