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 350
  // 64MB,means when you need less than 64MB, get memory from BigMemory instead
  // of BigNode
  static const int BIGNODE_MEM_THRESHOLD = (64 * 1024 * 1024 + 1);
H
HexToString 已提交
351 352
  static const int COUNTER_SIZE =
      BIGNODE_MEM_THRESHOLD / BIG_MEM_THRESHOLD + 1;  // this is not used
W
wangguibao 已提交
353

W
wangguibao 已提交
354
 private:
H
HexToString 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
  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 已提交
370 371 372 373 374
  butil::atomic<uint32_t> _big_mem_size;
  butil::atomic<uint32_t> _big_mem_count;
};
}  // namespace memory
}  // namespace fugue
W
wangguibao 已提交
375 376

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

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

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

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

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

W
wangguibao 已提交
416 417 418 419 420 421 422
    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 已提交
423 424 425
        // old_data will copy to other structure
        // so _free_cursor rollback,means the memory used by old_data can be
        // used.
W
wangguibao 已提交
426 427 428
        _free_cursor = static_cast<char*>(old_data);
        _free_size += old_size;
      }
W
wangguibao 已提交
429 430
    }

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

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

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

  ~Mempool() { release_block(); }

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

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

W
wangguibao 已提交
463 464
 private:
  void* malloc_from_region(size_t size) {
H
HexToString 已提交
465 466 467 468
    // 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 已提交
469 470
    }

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

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

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

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

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

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

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

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

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

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

H
HexToString 已提交
537 538 539 540 541
// 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 已提交
542
class GlobalMempool : public mempool {
W
wangguibao 已提交
543 544 545 546
 public:
  GlobalMempool() {
    // do nothing;
  }
W
wangguibao 已提交
547

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

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

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

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

W
wangguibao 已提交
561 562 563
  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 已提交
564

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

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

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

H
HexToString 已提交
573 574 575 576 577
// 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 已提交
578
class MempoolGuard {
W
wangguibao 已提交
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
 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 已提交
599
};
H
HexToString 已提交
600
*/
W
wangguibao 已提交
601
inline std::string print_trace() {
W
wangguibao 已提交
602 603
  static const int BT_BUF_SIZE = 400;
  std::stringstream debug_stream;
W
wangguibao 已提交
604

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

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

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