FACT++  1.0
MemoryManager.h
Go to the documentation of this file.
1 #ifndef MARS_MemoryManager
2 #define MARS_MemoryManager
3 
4 #ifndef __CINT__
5 #include <forward_list>
6 #else
7 namespace std
8 {
9  class mutex;
10  class condition_variable;
11  template<class T> class shared_ptr<T>;
12  template<class T> class forward_list<T>;
13 }
14 #endif
15 
17 {
18  friend class MemoryChunk;
19  friend class MemoryManager;
20 
21  size_t fChunkSize;
22  size_t fMaxMemory;
23 
24  size_t fInUse;
25  size_t fAllocated;
26 
27  size_t fMaxInUse;
28 
29  std::mutex fMutexMem;
30  std::mutex fMutexCond;
31  std::condition_variable fCond;
32 
33  std::forward_list<std::shared_ptr<char>> fMemoryStock;
34 
35 public:
36  MemoryStock(size_t chunk, size_t max) : fChunkSize(chunk), fMaxMemory(max<chunk?chunk:max),
37  fInUse(0), fAllocated(0), fMaxInUse(0)
38  {
39  }
40 
41 private:
42  std::shared_ptr<char> pop(bool block)
43  {
44  if (block)
45  {
46  // No free slot available, next alloc would exceed max memory:
47  // block until a slot is available
48  std::unique_lock<std::mutex> lock(fMutexCond);
49  while (fMemoryStock.empty() && fAllocated+fChunkSize>fMaxMemory)
50  fCond.wait(lock);
51  }
52  else
53  {
54  // No free slot available, next alloc would exceed max memory
55  // return an empty pointer
56  if (fMemoryStock.empty() && fAllocated+fChunkSize>fMaxMemory)
57  return std::shared_ptr<char>();
58  }
59 
60  // We will return this amount of memory
61  // This is not 100% thread safe, but it is not a super accurate measure anyway
62  fInUse += fChunkSize;
63  if (fInUse>fMaxInUse)
64  fMaxInUse = fInUse;
65 
66  if (fMemoryStock.empty())
67  {
68  // No free slot available, allocate a new one
69  fAllocated += fChunkSize;
70  return std::shared_ptr<char>(new char[fChunkSize]);
71  }
72 
73  // Get the next free slot from the stack and return it
74  const std::lock_guard<std::mutex> lock(fMutexMem);
75 
76  const auto mem = fMemoryStock.front();
77  fMemoryStock.pop_front();
78  return mem;
79  };
80 
81  void push(const std::shared_ptr<char> &mem)
82  {
83  if (!mem)
84  return;
85 
86  // Decrease the amont of memory in use accordingly
87  fInUse -= fChunkSize;
88 
89  // If the maximum memory has changed, we might be over the limit.
90  // In this case: free a slot
91  if (fAllocated>fMaxMemory)
92  {
93  fAllocated -= fChunkSize;
94  return;
95  }
96 
97  {
98  const std::lock_guard<std::mutex> lock(fMutexMem);
99  fMemoryStock.emplace_front(mem);
100  }
101 
102  {
103  const std::lock_guard<std::mutex> lock(fMutexCond);
104  fCond.notify_one();
105  }
106  }
107 };
108 
110 {
111  friend class MemoryManager;
112 
113  std::shared_ptr<MemoryStock> fMemoryStock;
114  std::shared_ptr<char> fPointer;
115 
116  MemoryChunk(const std::shared_ptr<MemoryStock> &mem, bool block)
117  : fMemoryStock(mem)
118  {
119  fPointer = fMemoryStock->pop(block);
120  }
121 
122 public:
124  {
125  fMemoryStock->push(fPointer);
126  }
127 };
128 
130 {
131  std::shared_ptr<MemoryStock> fMemoryStock;
132 
133 public:
134  MemoryManager(size_t chunk, size_t max) : fMemoryStock(std::make_shared<MemoryStock>(chunk, max))
135  {
136  }
137 
138  std::shared_ptr<char> malloc(bool block=true)
139  {
140  const std::shared_ptr<MemoryChunk> chunk(new MemoryChunk(fMemoryStock, block));
141  return std::shared_ptr<char>(chunk, chunk->fPointer.get());
142  }
143 
144  size_t getChunkSize() const { return fMemoryStock->fChunkSize; }
145  bool setChunkSize(const size_t size)
146  {
147 #ifdef __EXCEPTIONS
148  if (getInUse())
149  throw std::runtime_error("Cannot change the chunk size while there is memory in use");
150  if (getMaxMemory()<size)
151  throw std::runtime_error("Chunk size ("+std::to_string((long long int)size)+") larger than allowed memory ("+std::to_string((long long int)getMaxMemory())+")");
152 #else
153  if (getInUse() || getMaxMemory()<size)
154  return false;
155 #endif
156 
157  fMemoryStock->fChunkSize = size;
158  return true;
159  }
160 
161  size_t getMaxMemory() const { return fMemoryStock->fMaxMemory; }
162  size_t getInUse() const { return fMemoryStock->fInUse; }
163  size_t getAllocated() const { return fMemoryStock->fAllocated; }
164  size_t getMaxInUse() const { return fMemoryStock->fMaxInUse; }
165 };
166 
167 #endif
std::shared_ptr< char > malloc(bool block=true)
std::mutex fMutexMem
Definition: MemoryManager.h:29
size_t getMaxInUse() const
std::shared_ptr< MemoryStock > fMemoryStock
MemoryChunk(const std::shared_ptr< MemoryStock > &mem, bool block)
MemoryStock(size_t chunk, size_t max)
Definition: MemoryManager.h:36
STL namespace.
size_t getAllocated() const
std::shared_ptr< MemoryStock > fMemoryStock
size_t fMaxInUse
Definition: MemoryManager.h:27
std::condition_variable fCond
Definition: MemoryManager.h:31
std::shared_ptr< char > pop(bool block)
Definition: MemoryManager.h:42
size_t getInUse() const
size_t fMaxMemory
Definition: MemoryManager.h:22
size_t getMaxMemory() const
size_t getChunkSize() const
int size
Definition: db_dim_server.c:17
MemoryManager(size_t chunk, size_t max)
size_t fInUse
Definition: MemoryManager.h:24
std::forward_list< std::shared_ptr< char > > fMemoryStock
Definition: MemoryManager.h:33
bool setChunkSize(const size_t size)
std::shared_ptr< char > fPointer
size_t fAllocated
Definition: MemoryManager.h:25
void push(const std::shared_ptr< char > &mem)
Definition: MemoryManager.h:81
size_t fChunkSize
Definition: MemoryManager.h:21
std::mutex fMutexCond
Definition: MemoryManager.h:30