SST  11.0.0
StructuralSimulationToolkit
mempool.h
1 // Copyright 2009-2021 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2021, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_MEMPOOL_H
13 #define SST_CORE_MEMPOOL_H
14 
15 #include <list>
16 #include <deque>
17 
18 #include <cstddef>
19 #include <cstdlib>
20 #include <cinttypes>
21 #include <cstdint>
22 #include <sys/mman.h>
23 
24 #include "sst/core/threadsafe.h"
25 
26 namespace SST {
27 namespace Core {
28 
29 /**
30  * Simple Memory Pool class
31  */
32 class MemPool
33 {
34  template <typename LOCK_t>
35  class FreeList {
36  LOCK_t mtx;
37  std::vector<void*> list;
38  public:
39  inline void insert(void *ptr) {
40  std::lock_guard<LOCK_t> lock(mtx);
41  list.push_back(ptr);
42  }
43 
44  inline void* try_remove() {
45  std::lock_guard<LOCK_t> lock(mtx);
46  if ( list.empty() ) return nullptr;
47  void *p = list.back();
48  list.pop_back();
49  return p;
50  }
51 
52  size_t size() const { return list.size(); }
53  };
54 
55 
56 public:
57  /** Create a new Memory Pool.
58  * @param elementSize - Size of each Element
59  * @param initialSize - Size of the memory pool (in bytes)
60  */
61  MemPool(size_t elementSize, size_t initialSize=(2<<20)) :
62  numAlloc(0), numFree(0),
63  elemSize(elementSize), arenaSize(initialSize),
64  allocating(false)
65  {
66  allocPool();
67  }
68 
69  ~MemPool()
70  {
71  for ( std::list<uint8_t*>::iterator i = arenas.begin() ; i != arenas.end() ; ++i ) {
72  ::free(*i);
73  }
74  }
75 
76  /** Allocate a new element from the memory pool */
77  inline void* malloc()
78  {
79  void *ret = freeList.try_remove();
80  while ( !ret ) {
81  bool ok = allocPool();
82  if ( !ok ) return nullptr;
83  sst_pause();
84  ret = freeList.try_remove();
85  }
86  ++numAlloc;
87  return ret;
88  }
89 
90  /** Return an element to the memory pool */
91  inline void free(void *ptr)
92  {
93  // TODO: Make sure this is in one of our arenas
94  freeList.insert(ptr);
95 // #ifdef __SST_DEBUG_EVENT_TRACKING__
96 // *((uint64_t*)ptr) = 0xFFFFFFFFFFFFFFFF;
97 // #endif
98  ++numFree;
99  }
100 
101  /**
102  Approximates the current memory usage of the mempool. Some
103  overheads are not taken into account.
104  */
105  uint64_t getBytesMemUsed() {
106  uint64_t bytes_in_arenas = arenas.size() * arenaSize;
107  uint64_t bytes_in_free_list = freeList.size() * sizeof(void*);
108  return bytes_in_arenas + bytes_in_free_list;
109  }
110 
111  uint64_t getUndeletedEntries() {
112  return numAlloc - numFree;
113  }
114 
115  /** Counter: Number of times elements have been allocated */
116  std::atomic<uint64_t> numAlloc;
117  /** Counter: Number times elements have been freed */
118  std::atomic<uint64_t> numFree;
119 
120  size_t getArenaSize() const { return arenaSize; }
121  size_t getElementSize() const { return elemSize; }
122 
123  const std::list<uint8_t*>& getArenas() { return arenas; }
124 
125 private:
126 
127  bool allocPool()
128  {
129  /* If already in progress, return */
130  if ( allocating.exchange(1, std::memory_order_acquire) ) {
131  return true;
132  }
133 
134  uint8_t *newPool = (uint8_t*)mmap(nullptr, arenaSize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
135  if ( MAP_FAILED == newPool ) {
136  allocating.store(0, std::memory_order_release);
137  return false;
138  }
139  std::memset(newPool, 0xFF, arenaSize);
140  arenas.push_back(newPool);
141  size_t nelem = arenaSize / elemSize;
142  for ( size_t i = 0 ; i < nelem ; i++ ) {
143  uint64_t* ptr = (uint64_t*)(newPool + (elemSize*i));
144 // #ifdef __SST_DEBUG_EVENT_TRACKING__
145 // *ptr = 0xFFFFFFFFFFFFFFFF;
146 // #endif
147  freeList.insert(ptr);
148  // freeList.push_back(newPool + (elemSize*i));
149  }
150  allocating.store(0, std::memory_order_release);
151  return true;
152  }
153 
154  size_t elemSize;
155  size_t arenaSize;
156 
157  std::atomic<unsigned int> allocating;
158  FreeList<ThreadSafe::Spinlock> freeList;
159  std::list<uint8_t*> arenas;
160 
161 };
162 
163 }
164 }
165 
166 #endif
MemPool(size_t elementSize, size_t initialSize=(2<< 20))
Create a new Memory Pool.
Definition: mempool.h:61
void free(void *ptr)
Return an element to the memory pool.
Definition: mempool.h:91
void * malloc()
Allocate a new element from the memory pool.
Definition: mempool.h:77
std::atomic< uint64_t > numAlloc
Counter: Number of times elements have been allocated.
Definition: mempool.h:116
uint64_t getBytesMemUsed()
Approximates the current memory usage of the mempool.
Definition: mempool.h:105
std::atomic< uint64_t > numFree
Counter: Number times elements have been freed.
Definition: mempool.h:118
Simple Memory Pool class.
Definition: mempool.h:32