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