All Classes Namespaces Functions Typedefs Enumerations Pages
_memory.h
1 /* Copyright (C) 2003-2005 Martin Förg
2 
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16  *
17  * Contact:
18  * martin.o.foerg@googlemail.com
19  *
20  */
21 
22 #ifndef _memory_h
23 #define _memory_h
24 
25 // includes
26 #include <stdlib.h>
27 #include <vector>
28 
29 // include header given by ALLOCATORHEADER
30 #ifdef ALLOCATORHEADER
31 # define CPPBEGININCLUDE <
32 # define CPPENDINCLUDE >
33 # include CPPBEGININCLUDE./ALLOCATORHEADER CPPENDINCLUDE
34 # undef CPPBEGININCLUDE
35 # undef CPPENDINCLUDE
36 #endif
37 // use fmatvec::PoolAllocator if no allocator is defined (the default in the configure script)
38 #ifndef ALLOCATORCLASS
39 # define ALLOCATORCLASS fmatvec::PoolAllocator
40 #endif
41 
42 // create some locking and atomic operations dependent on the thread safety method
43 //
44 // FMATVEC_LOCKVAR(l) : create a locking/mutex named l
45 // FMATVEC_LOCKINIT(l) : initialize the locking/mutex named l
46 // FMATVEC_LOCK(l) : lock the locking/mutex l
47 // FMATVEC_UNLOCK(l) : unlock the locking/mutex l
48 //
49 // FMATVEC_SYNCVAR(l) : create a locking/mutex named l for a syncronized operation
50 // FMATVEC_SYNCINIT(l) : initialize a locking/mutex named l for a syncronized operation
51 // FMATVEC_SYNCINC(var, l) : var++ (syncronized by l)
52 // FMATVEC_SYNCPREDEC(ret, var, l) : ret=--(var) (syncronized by l)
53 #if defined FMATVEC_THREADSAFE_GCCBUILTIN
54  #define FMATVEC_LOCKVAR(l) short int l;
55  #define FMATVEC_LOCKINIT(l) l=0;
56  #define FMATVEC_LOCK(l) while(__sync_bool_compare_and_swap(&l, 0, 0xffff)==false);
57  #define FMATVEC_UNLOCK(l) __sync_bool_compare_and_swap(&l, 0xffff, 0);
58 
59  #define FMATVEC_SYNCVAR(l)
60  #define FMATVEC_SYNCINIT(l)
61  #define FMATVEC_SYNCINC(var, l) __sync_add_and_fetch(&(var), 1);
62  #define FMATVEC_SYNCPREDEC(ret, var, l) ret=__sync_sub_and_fetch(&(var), 1);
63 #elif defined FMATVEC_THREADSAFE_PTHREAD
64  #include <pthread.h> // pthread required a header file
65 
66  #define FMATVEC_LOCKVAR(l) pthread_mutex_t l;
67  #define FMATVEC_LOCKINIT(l) pthread_mutex_init(&l, NULL);
68  #define FMATVEC_LOCK(l) pthread_mutex_lock(&l);
69  #define FMATVEC_UNLOCK(l) pthread_mutex_unlock(&l);
70 
71  #define FMATVEC_SYNCVAR(l) pthread_mutex_t l;
72  #define FMATVEC_SYNCINIT(l) pthread_mutex_init(&l, NULL);
73  #define FMATVEC_SYNCINC(var, l) pthread_mutex_lock(&l); (var)++; pthread_mutex_unlock(&l);
74  #define FMATVEC_SYNCPREDEC(ret, var, l) pthread_mutex_lock(&l); ret=--(var); pthread_mutex_unlock(&l);
75 #elif defined FMATVEC_THREADSAFE_OPENMP
76  #define FMATVEC_PRAGMA(x) _Pragma(#x) // openmp required the _Pragma operator (defined by C99)
77 
78  #define FMATVEC_LOCKVAR(l)
79  #define FMATVEC_LOCKINIT(l)
80  #define FMATVEC_LOCK(l) FMATVEC_PRAGMA(omp critical (l)) {
81  #define FMATVEC_UNLOCK(l) }
82 
83  #define FMATVEC_SYNCVAR(l)
84  #define FMATVEC_SYNCINIT(l)
85  #define FMATVEC_SYNCINC(var, l) FMATVEC_PRAGMA(omp critical (l)) { (var)++; }
86  #define FMATVEC_SYNCPREDEC(ret, var, l) FMATVEC_PRAGMA(omp critical (l)) { ret=--(var); }
87 #else
88  #define FMATVEC_PRAGMA(l)
89  #define FMATVEC_LOCKVAR(l)
90  #define FMATVEC_LOCKINIT(l)
91  #define FMATVEC_LOCK(l)
92  #define FMATVEC_UNLOCK(l)
93 
94  #define FMATVEC_SYNCVAR(l)
95  #define FMATVEC_SYNCINIT(l)
96  #define FMATVEC_SYNCINC(var, l) (var)++;
97  #define FMATVEC_SYNCPREDEC(ret, var, l) ret=--(var);
98 #endif
99 
100 #if defined MEMORYCLASS_BOOST
101 # include <boost/shared_array.hpp>
102 #endif
103 
110 namespace fmatvec {
111 
113 
114  // A STL-like pool memory allocator (being fast)
115  template <class AT>
116  class PoolAllocator {
117  private:
118  // The minimal allocation size in power of 2: MINSIZE=2^MINEXP
119  static const size_t MINEXP=4;
120  // A pool of memory of allocation size 2^(MINEXP+0), 2^(MINEXP+1), 2^(MINEXP+2), ...
121  // stored at index 0, 1, 2, ... in memoryPool.
122  // The pointers stored here are already allocated but currently not used.
123  std::vector<std::vector<AT*> > memoryPool;
124  // Just a dummy variable used for zero size allocations.
125  AT sizeZero;
126  FMATVEC_LOCKVAR(fmatvec_memoryPoolLock)
127  public:
128  // Constructor: alloc memoryPool with at least size 1, since the size is doubled each time the size ran out.
129  PoolAllocator() : memoryPool(1) {
130  FMATVEC_LOCKINIT(fmatvec_memoryPoolLock)
131  }
132  // Destructor: delete all cached memory in the pool.
133  ~PoolAllocator() {
134  // loop over all pool sizes and free memory
135  for(typename std::vector<std::vector<AT*> >::iterator i=memoryPool.begin(); i!=memoryPool.end(); ++i)
136  for(typename std::vector<AT*>::iterator j=i->begin(); j!=i->end(); ++j)
137  delete[](*j);
138  }
139  // Allocate new memory of at least size size.
140  AT *allocate(size_t size) {
141  // do nothing for zero size, but return a valid memory pointer
142  if(size==0) return &sizeZero;
143  // calculate size index: size 0 to 2^MINEXP = index 0; size 2^MINEXP+1 to 2*2^MINEXP = index 1; ...
144  size_t index=0;
145  --size>>=MINEXP-1;
146  while(size>>=1) ++index;
147  AT* ret=NULL;
148  FMATVEC_LOCK(fmatvec_memoryPoolLock)
149  // increase (double) memoryPool if nessasary
150  if(index>=memoryPool.size()) memoryPool.resize(index<<1);
151  // try to use cached memory
152  std::vector<AT*> &memoryPoolIndex=memoryPool[index];
153  if(memoryPoolIndex.size()>0) {
154  ret=memoryPoolIndex.back(); // get last cached memory
155  memoryPoolIndex.pop_back(); // remove last cached memory
156  }
157  FMATVEC_UNLOCK(fmatvec_memoryPoolLock)
158  if(ret) return ret; // return chaced memory
159  // return new memory
160  return new AT[1<<(index+MINEXP)]; // allocate 2^(index+MINEXP) elements (max size for this index)
161  }
162  // Free memory and release it to the pool.
163  void deallocate(AT *p, size_t size) {
164  // do nothing for zero size, a dummy but valid pointer was returned by allocate
165  if(size==0) return;
166  // calculate size index: size 0 to 2^MINEXP = index 0; size 2^MINEXP+1 to 2*2^MINEXP = index 1; ...
167  size_t index=0;
168  --size>>=MINEXP-1;
169  while(size>>=1) ++index;
170  FMATVEC_LOCK(fmatvec_memoryPoolLock)
171  // release memory
172  memoryPool[index].push_back(p); // add to cached memory
173  FMATVEC_UNLOCK(fmatvec_memoryPoolLock)
174  }
175  };
176 
177 
178 
179 
180 
181 #ifdef MEMORYCLASS_FMATVEC
182 
183  // this is the old fmatvec Memory class which uses different allocators (using the std::allocator interface)
184  template <class AT> class Memory {
185  private:
186  typedef ALLOCATORCLASS<AT> allocator_type;
187  size_t sz;
188  AT *ele0;
189  static allocator_type ms;
190  size_t *ref;
191  FMATVEC_SYNCVAR(fmatvec_refLock)
192  void lock() {
193  FMATVEC_SYNCINC(*ref, fmatvec_refLock)
194  };
195  void unlock() {
196  size_t refLocal;
197  FMATVEC_SYNCPREDEC(refLocal, *ref, fmatvec_refLock)
198  if(!refLocal) {
199  ms.deallocate(ele0, sz);
200  delete ref;
201  }
202  };
203 
204  public:
205  Memory() : sz(0), ele0(0), ref(new size_t(1)) {
206  FMATVEC_SYNCINIT(fmatvec_refLock);
207  };
208 
209  Memory(size_t n) : sz(n), ele0(ms.allocate(sz)), ref(new size_t(1)){
210  FMATVEC_SYNCINIT(fmatvec_refLock);
211  };
212 
213  Memory(const Memory &memory) : sz(memory.sz), ele0(memory.ele0), ref(memory.ref) {
214  FMATVEC_SYNCINIT(fmatvec_refLock);
215  lock();
216  };
217 
218  ~Memory() {
219  unlock();
220  };
221 
222  Memory& operator=(const Memory &memory) {
223  if(this == &memory)
224  return *this;
225  unlock(); sz=memory.sz; ref=memory.ref; ele0=memory.ele0; lock();
226  return *this;
227  }
228 
229  void resize(size_t n) {
230  unlock();
231  ref=new size_t(1);
232  sz = n;
233  ele0 = ms.allocate(sz);
234  };
235 
236  AT* get() const {return ele0;};
237  };
238 
239 #elif defined MEMORYCLASS_BOOST
240 
241  // Just a wrapper class around boost::shared_array, since the Memory interface differs a little bit from the boost smart-ptr interface
242  // This wrapper is fully inlined by the compiler if optimization is used!
243  template <class AT> class Memory {
244  private:
245  boost::shared_array<AT> ele0;
246 
247  public:
248  Memory() : ele0() {};
249 
250  Memory(size_t n) : ele0(new AT[n]) {};
251 
252  Memory(const Memory &memory) : ele0(memory.ele0) {};
253 
254  ~Memory() {};
255 
256  Memory& operator=(const Memory &memory) {
257  if(this == &memory)
258  return *this;
259  ele0=memory.ele0;
260  return *this;
261  }
262 
263  void resize(size_t n) {
264  ele0.reset(new AT[n]);
265  };
266 
267  AT* get() const {return ele0.get();};
268  };
269 
270 #else
271 
272  // This class uses an "intrusive reference counting" mechanism for memory of n elements of type AT.
273  // The reference count is stored as the first element of allocate memory. The rest is used for the n element of type AT.
274  // Hence at least sizeof(size_t)+n*sizeof(AT) bytes are allocated.
275  // For correct memory alignment the memory is allocated as an array of AT.
276  template <class AT> class Memory {
277  private:
278  static const size_t ele0Start=(sizeof(size_t)-1)/sizeof(AT)+1; // the minimum number of AT elements such that one size_t fits into
279  size_t *ref; // a pointer to the reference count (this is also the address of the allocated memory)
280  AT *ele0; // a pointer to the allocated memory (this is also the address ((AT*)ref)+1)
281  FMATVEC_SYNCVAR(fmatvec_refLock)
282 
283  void lock() {
284  FMATVEC_SYNCINC(*ref, fmatvec_refLock)
285  };
286 
287  void unlock() {
288  size_t refLocal;
289  FMATVEC_SYNCPREDEC(refLocal, *ref, fmatvec_refLock)
290  if(!refLocal) {
291  delete[]reinterpret_cast<AT*>(ref);
292  }
293  };
294 
295  public:
296  Memory() : ref(reinterpret_cast<size_t*>(new AT[ele0Start])), ele0(NULL) {
297  *ref=1; // initialize the reference count to 1
298  FMATVEC_SYNCINIT(fmatvec_refLock);
299  };
300 
301  Memory(size_t n) : ref(reinterpret_cast<size_t*>(new AT[ele0Start+n])), ele0(reinterpret_cast<AT*>(ref)+ele0Start) {
302  *ref=1; // initialize the reference count to 1
303  FMATVEC_SYNCINIT(fmatvec_refLock);
304  };
305 
306  Memory(const Memory &memory) : ref(memory.ref), ele0(memory.ele0) {
307  FMATVEC_SYNCINIT(fmatvec_refLock);
308  lock();
309  };
310 
311  ~Memory() {
312  unlock();
313  };
314 
315  Memory& operator=(const Memory &memory) {
316  if(this == &memory)
317  return *this;
318  unlock(); ref=memory.ref; ele0=memory.ele0; lock();
319  return *this;
320  }
321 
322  void resize(size_t n) {
323  unlock();
324  ref=reinterpret_cast<size_t*>(new AT[ele0Start+n]);
325  ele0=reinterpret_cast<AT*>(ref)+ele0Start;
326  *ref=1; // initialize the reference count to 1
327  };
328 
329  AT* get() const {return ele0;};
330  };
331 
332 #endif
333 
334 }
335 
337 
338 #endif

Impressum / Disclaimer / Datenschutz Generated by doxygen 1.8.5 Valid HTML