TPIE

11a2c2d
memory.h
Go to the documentation of this file.
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 //
4 // Copyright 2011, The TPIE development team
5 //
6 // This file is part of TPIE.
7 //
8 // TPIE is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License as published by the
10 // Free Software Foundation, either version 3 of the License, or (at your
11 // option) any later version.
12 //
13 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
14 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 // License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public License
19 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
20 
24 
25 #ifndef __TPIE_MEMORY_H__
26 #define __TPIE_MEMORY_H__
27 
28 #include <tpie/tpie_export.h>
29 #include <tpie/config.h>
30 #include <tpie/util.h>
31 #include <tpie/resource_manager.h>
32 #include <mutex>
33 #include <unordered_map>
34 #include <type_traits>
35 #include <utility>
36 #include <memory>
37 #include <atomic>
38 #include <typeindex>
39 
40 namespace tpie {
41 
43  std::string name;
44  size_t count;
45  size_t bytes;
46  std::type_info * ti;
47 };
48 
50  std::atomic_size_t bytes;
51  std::atomic_size_t count;
52  type_allocations() noexcept: bytes(0), count(0) {}
53  type_allocations(const type_allocations & o) noexcept {bytes = (size_t)o.bytes; count = (size_t)o.count;}
54  type_allocations(type_allocations && o) noexcept {bytes = (size_t)o.bytes; count = (size_t)o.count;}
55  type_allocations & operator=(const type_allocations & o) noexcept {bytes = (size_t)o.bytes; count = (size_t)o.count; return *this;}
56  type_allocations & operator=(type_allocations && o) noexcept {bytes = (size_t)o.bytes; count = (size_t)o.count; return *this;}
57 };
58 
62 class TPIE_EXPORT memory_manager final : public resource_manager {
63 public:
68  memory_manager();
69 
74  std::pair<uint8_t *, size_t> __allocate_consecutive(size_t upper_bound, size_t granularity);
75 
76  void register_typed_allocation(size_t bytes, const std::type_info & t);
77  void register_typed_deallocation(size_t bytes, const std::type_info & t);
78 
79  void register_allocation(size_t bytes, const std::type_info & t) {
80  register_increased_usage(bytes);
81 #ifndef TPIE_NDEBUG
82  register_typed_allocation(bytes, t);
83 #else
84  unused(t);
85 #endif
86  }
87 
88  void register_deallocation(size_t bytes, const std::type_info & t) {
89  register_decreased_usage(bytes);
90 #ifndef TPIE_NDEBUG
91  register_typed_deallocation(bytes, t);
92 #else
93  unused(t);
94 #endif
95  }
96 
97  std::string amount_with_unit(size_t amount) const override {
98  return pretty_print_size(amount);
99  }
100 
101  void complain_about_unfreed_memory();
102  std::unordered_map<std::type_index, memory_digest_item> memory_digest();
103 protected:
104  void throw_out_of_resource_error(const std::string & s) override;
105 
106  std::atomic_size_t m_mutex;
107  std::unordered_map<std::type_index, type_allocations> m_allocations;
108 };
109 
113 void init_memory_manager();
114 
118 void finish_memory_manager();
119 
125 TPIE_EXPORT memory_manager & get_memory_manager();
126 
127 #ifndef DOXYGEN
128 template <typename T,
132  bool x=std::is_polymorphic<T>::value
133 >
134 struct __object_addr {
135  void * operator()(T * o) {return const_cast<void*>(static_cast<const void*>(o));}
136 };
137 
141 template <typename T>
142 struct __object_addr<T, true> {
143  void * operator()(T * o) {return const_cast<void*>(dynamic_cast<const void *>(o));}
144 };
145 #endif
146 
154 template <typename D, typename T>
155 inline D ptr_cast(T * t) { return reinterpret_cast<D>(__object_addr<T>()(t)); }
156 
157 
158 template <typename T>
159 inline T * __allocate() {
160  if(!std::is_polymorphic<T>::value) return reinterpret_cast<T *>(new uint8_t[sizeof(T)]);
161  uint8_t * x = new uint8_t[sizeof(T)+sizeof(size_t)];
162  *reinterpret_cast<size_t*>(x) = sizeof(T);
163  return reinterpret_cast<T*>(x + sizeof(size_t));
164 }
165 
166 template <typename T>
167 inline size_t tpie_size(T * p) {
168  if(!std::is_polymorphic<T>::value) return sizeof(T);
169  uint8_t * x = ptr_cast<uint8_t *>(p);
170  return * reinterpret_cast<size_t *>(x - sizeof(size_t));
171 }
172 
173 
178 template <typename T>
180  size_t size;
181  T * data;
182  array_allocation_scope_magic(size_t s): size(0), data(0) {
183  get_memory_manager().register_allocation(s * sizeof(T), typeid(T) );
184  size=s;
185  }
186 
187  T * allocate() {
188  data = new T[size];
189  return data;
190  }
191 
192  T * finalize() {
193  T * d = data;
194  size = 0;
195  data = 0;
196  return d;
197  }
198 
200  if(size) get_memory_manager().register_deallocation(size*sizeof(T), typeid(T) );
201  }
202 };
203 
208 template <typename T>
210  size_t deregister;
211  T * data;
212  allocation_scope_magic(): deregister(0), data(0) {}
213 
214  T * allocate() {
215  get_memory_manager().register_allocation(sizeof(T), typeid(T));
216  deregister = sizeof(T);
217  data = __allocate<T>();
218  return data;
219  }
220 
221  T * finalize() {
222  T * d = data;
223  deregister = 0;
224  data = 0;
225  return d;
226  }
227 
229  delete[] reinterpret_cast<uint8_t*>(data);
230  if (deregister) get_memory_manager().register_deallocation(deregister, typeid(T));
231  }
232 };
233 
239 template <typename T>
240 inline T * tpie_new_array(size_t size) {
242  m.allocate();
243  return m.finalize();
244 }
245 
259 template <typename T, typename ... Args>
260 inline T * tpie_new(Args &&... args) {
262  new(m.allocate()) T(std::forward<Args>(args)...);
263  return m.finalize();
264 }
265 
270 template <typename T>
271 inline void tpie_delete(T * p) throw() {
272  if (p == 0) return;
273  get_memory_manager().register_deallocation(tpie_size(p), typeid(*p));
274  uint8_t * pp = ptr_cast<uint8_t *>(p);
275  p->~T();
276  if(!std::is_polymorphic<T>::value)
277  delete[] pp;
278  else
279  delete[] (pp - sizeof(size_t));
280 }
281 
287 template <typename T>
288 inline void tpie_delete_array(T * a, size_t size) throw() {
289  if (a == 0) return;
290  get_memory_manager().register_deallocation(sizeof(T) * size, typeid(T));
291  delete[] a;
292 }
293 
294 struct tpie_deleter {
295  template <typename T>
296  void operator()(T * t) {
297  tpie_delete(t);
298  }
299 };
300 
305 template <typename T>
306 using unique_ptr=std::unique_ptr<T, tpie_deleter>;
307 
312 template <typename T, typename ... TT>
313 inline unique_ptr<T> make_unique(TT && ... tt) {
314  return unique_ptr<T>(tpie_new<T>(std::forward<TT>(tt)...));
315 }
316 
321 public:
322  memory_bucket(): count(0) {}
323 
324  std::atomic_size_t count;
325  std::string name;
326 };
327 
335 public:
336  explicit memory_bucket_ref(memory_bucket * b=nullptr) noexcept: bucket(b) {}
337  explicit operator bool() const noexcept {return bucket != nullptr;}
338  memory_bucket_ref(const memory_bucket_ref & o) = default;
339  memory_bucket_ref(memory_bucket_ref && o) = default;
340  memory_bucket_ref & operator=(const memory_bucket_ref & o) = default;
341  memory_bucket_ref & operator=(memory_bucket_ref && o) = default;
342  memory_bucket & operator*() noexcept {return *bucket;}
343  const memory_bucket & operator*() const noexcept {return *bucket;}
344  memory_bucket * operator->() noexcept {return bucket;}
345  const memory_bucket * operator->() const noexcept {return bucket;}
346  friend bool operator ==(const memory_bucket_ref & l, const memory_bucket_ref & r) noexcept {return l.bucket == r.bucket;}
347  friend bool operator !=(const memory_bucket_ref & l, const memory_bucket_ref & r) noexcept {return l.bucket != r.bucket;}
348 private:
349  memory_bucket * bucket;
350 };
351 
357 template <class T>
358 class allocator {
359 private:
360  typedef std::allocator<T> a_t;
361  a_t a;
362 public:
363  memory_bucket_ref bucket;
364 
365  typedef typename a_t::size_type size_type;
366  typedef typename a_t::difference_type difference_type;
367  typedef typename a_t::pointer pointer;
368  typedef typename a_t::const_pointer const_pointer;
369  typedef typename a_t::reference reference;
370  typedef typename a_t::const_reference const_reference;
371  typedef typename a_t::value_type value_type;
372 
373  typedef std::true_type propagate_on_container_copy_assignment;
374  typedef std::true_type propagate_on_container_move_assignment;
375  typedef std::true_type propagate_on_container_swap;
376 
377  allocator() = default;
378  allocator(memory_bucket_ref bucket) noexcept : bucket(bucket) {}
379  allocator(const allocator & o) noexcept : bucket(o.bucket) {}
380  template <typename T2>
381  allocator(const allocator<T2> & o) noexcept : bucket(o.bucket) {}
382  allocator(allocator && o) noexcept : bucket(std::move(o.bucket)) {}
383  template <typename T2>
384  allocator(allocator<T2> && o) noexcept : bucket(std::move(o.bucket)) {}
385 
386  allocator & operator=(const allocator & o) noexcept {bucket = o.bucket; return *this;}
387  template <typename T2>
388  allocator & operator=(const allocator<T2> & o) noexcept {bucket = o.bucket; return *this;}
389  allocator & operator=(allocator && o) noexcept {bucket = std::move(o.bucket); return *this;}
390  template <typename T2>
391  allocator & operator=(allocator<T2> && o) noexcept {bucket = std::move(o.bucket); return *this;}
392 
393  template <class U> struct rebind {typedef allocator<U> other;};
394 
395  T * allocate(size_t size, const void * hint=0) {
396  get_memory_manager().register_allocation(size * sizeof(T), typeid(T));
397  if (bucket) bucket->count += size * sizeof(T);
398  T * res = a.allocate(size, hint);
399  return res;
400  }
401 
402  void deallocate(T * p, size_t n) {
403  if (p == 0) return;
404  if (bucket) bucket->count -= n * sizeof(T);
405  get_memory_manager().register_deallocation(n * sizeof(T), typeid(T));
406  return a.deallocate(p, n);
407  }
408  size_t max_size() const noexcept {return a.max_size();}
409 
410  template <typename U, typename ...TT>
411  void construct(U * p, TT &&...x) {a.construct(p, std::forward<TT>(x)...);}
412 
413  // void construct(T * p) {
414  // new(p) T();
415  // }
416  // void construct(T * p, const T& val) {a.construct(p, val);}
417  template <typename U>
418  void destroy(U * p) {
419  p->~U();
420  }
421  pointer address(reference x) const noexcept {return &x;}
422  const_pointer address(const_reference x) const noexcept {return &x;}
423 
424 
425  friend bool operator==(const allocator & l, const allocator & r) noexcept {return l.bucket == r.bucket;}
426  friend bool operator!=(const allocator & l, const allocator & r) noexcept {return l.bucket != r.bucket;}
427 
428  template <typename U>
429  friend class allocator;
430 
431 
432 };
433 
438 TPIE_EXPORT size_t consecutive_memory_available(size_t granularity=5*1024*1024);
439 
440 } //namespace tpie
441 
442 #endif //__TPIE_MEMORY_H__
tpie::tpie_deleter
Definition: memory.h:294
tpie::memory_digest_item
Definition: memory.h:42
tpie::get_memory_manager
TPIE_EXPORT memory_manager & get_memory_manager()
Return a reference to the memory manager.
tpie::consecutive_memory_available
TPIE_EXPORT size_t consecutive_memory_available(size_t granularity=5 *1024 *1024)
Find the largest amount of memory that can be allocated as a single chunk.
tpie::finish_memory_manager
void finish_memory_manager()
Used by tpie_finish to deinitialize the memory manager.
tpie::ptr_cast
D ptr_cast(T *t)
Cast between pointer types.
Definition: memory.h:155
tpie::unique_ptr
std::unique_ptr< T, tpie_deleter > unique_ptr
like std::unique_ptr, but delete the object with tpie_delete.
Definition: memory.h:306
tpie::resource_manager
Resource management object used to track resource usage.
Definition: resource_manager.h:38
tpie::tpie_new_array
T * tpie_new_array(size_t size)
Allocate a new array and register its memory usage.
Definition: memory.h:240
tpie::allocation_scope_magic
Definition: memory.h:209
tpie::memory_bucket
Bucket used for memory counting.
Definition: memory.h:320
tpie::memory_bucket_ref
Class storring a reference to a memory bucket.
Definition: memory.h:334
tpie::type_allocations
Definition: memory.h:49
tpie::array_allocation_scope_magic
Definition: memory.h:179
tpie::unused
void unused(const T &x)
Declare that a variable is unused on purpose.
Definition: util.h:42
tpie::tpie_new
T * tpie_new(Args &&... args)
Allocate an element of the type given as template parameter, and register its memory usage with TPIE.
Definition: memory.h:260
tpie::pretty_print_size
TPIE_EXPORT std::string pretty_print_size(stream_size_type size)
pretty print a size
tpie::memory_manager
Memory management object used to track memory usage.
Definition: memory.h:62
tpie::tpie_delete
void tpie_delete(T *p)
Delete an object allocated with tpie_new.
Definition: memory.h:271
tpie::make_unique
unique_ptr< T > make_unique(TT &&... tt)
Create a new unique object using tpie::new.
Definition: memory.h:313
tpie::tpie_delete_array
void tpie_delete_array(T *a, size_t size)
Delete an array allocated with tpie_new_array.
Definition: memory.h:288
tpie::init_memory_manager
void init_memory_manager()
Used by tpie_init to initialize the memory manager.
util.h
tpie::allocator
A allocator object usable in STL containers, using the TPIE memory manager.
Definition: memory.h:358
tpie
Definition: access_type.h:26
tpie::allocator::rebind
Definition: memory.h:393