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