MPQC  3.0.0-alpha
consumableresources.h
1 //
2 // consumableresources.h
3 //
4 // Copyright (C) 2010 Edward Valeev
5 //
6 // Author: Edward Valeev <evaleev@vt.edu>
7 // Maintainer: EV
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27 
28 #ifndef _mpqc_src_lib_util_misc_consumableresources_h
29 #define _mpqc_src_lib_util_misc_consumableresources_h
30 
31 #include <map>
32 #include <limits>
33 #include <assert.h>
34 #include <iterator>
35 #include <mpqc_config.h>
36 #include <util/keyval/keyval.h>
37 #include <util/state/statein.h>
38 #include <util/state/stateout.h>
39 #include <util/misc/scexception.h>
40 #include <util/group/thread.h>
41 #include <util/misc/bug.h>
42 
43 namespace sc {
44 
46  class ConsumableResources : virtual public SavableState {
47  public:
67 
69  size_t max_memory() const;
71  size_t max_disk() const;
73 
75  size_t memory() const;
77  size_t disk() const;
79 
81  void consume_memory(size_t value);
83  void consume_disk(size_t value);
85 
87  void release_memory(size_t value);
89  void release_disk(size_t value);
91 
93  const std::string& disk_location() const;
94 
98  static Ref<ConsumableResources> initial_instance(int &argc, char **argv);
103 
109  void print_summary(std::ostream& os = ExEnv::out0(),
110  bool print_state = true,
111  bool print_stats = false) const;
113  std::string sprint() const;
114 
116  template <typename T> T* allocate(std::size_t size) {
117  if (size == 0) return 0;
118 
119  ThreadLockHolder lh(lock_);
120 
121  T* array = 0;
122  try {
123  array = (size > 1) ? new T[size] : new T;
124  }
125  catch (std::bad_alloc&) {
126  std::ostringstream oss;
127  oss << "ConsumableResources::allocate(size=" << size << "): allocation failed";
128  this->print_summary(ExEnv::out0(), true, true);
129  throw MemAllocFailed(oss.str().c_str(),__FILE__,__LINE__,size*sizeof(T));
130  }
131 
132  if (do_profile()) {
133  size *= sizeof(T);
134  try {
135  consume_memory_(size);
136  }
137  catch (LimitExceeded<size_t>&) {
138  if (size > sizeof(T)) delete[] array;
139  else delete array;
140  this->print_summary(ExEnv::out0(), true, true);
141  throw;
142  }
143 
144  void* array_ptr = static_cast<void*>(array);
145  if (debug()) {
146  ExEnv::out0() << indent << "ConsumableResources::allocate(size="
147  << size << ") => array=" << array_ptr << std::endl;
148  // make sure the pointer is not managed (may happen if delete was called directly, not deallocate on a managed buffer before)
149  std::map<void*, ResourceAttribites>::iterator pos =
150  managed_arrays_.find(array_ptr);
151  if (pos != managed_arrays_.end()) {
152  ExEnv::out0() << indent << "WARNING: " << array_ptr
153  << " is on the list of managed buffers. size="
154  << managed_arrays_[array_ptr].size << std::endl;
155  }
156  }
157  ResourceAttribites attr(size);
158  managed_arrays_[array_ptr] = attr;
159  }
160 
161  return array;
162  }
164  template <typename T> void deallocate(T* const & array) {
167  if (object_is_gone()) return;
168 
169  if (not do_profile()) {
170  delete[] array;
171  return;
172  }
173 
174  if (array != 0) {
175  ThreadLockHolder lh(lock_);
176  void* array_ptr = static_cast<void*>(array);
177  // make sure it's managed by me
178  std::map<void*, ResourceAttribites>::iterator pos = managed_arrays_.find(array_ptr);
179  if (pos != managed_arrays_.end()) {
180  const size_t size = pos->second.size;
181  if (size > sizeof(T)) delete[] array;
182  else delete array;
183  release_memory_(size);
184  if (debug()) {
185  ExEnv::out0() << indent << "ConsumableResources::deallocate(array=" << array_ptr << "): size=" << size << std::endl;
186  }
187  managed_arrays_.erase(pos);
188  }
189  else
190  throw ProgrammingError("ConsumableResources::deallocate() -- non-managed array given",
191  __FILE__, __LINE__, class_desc());
192  }
193  }
195  template <typename T> void deallocate(T*& array) {
196  if (object_is_gone()) return;
197 
198  if (array != 0) {
199  deallocate<T>(const_cast<T* const &>(array));
200  array = 0;
201  }
202  }
204 
205 
207 
209  template <typename T> void manage_array(T* const & array, std::size_t size) {
210  if (not do_profile()) return;
211 
212  if (array != 0) {
213  ThreadLockHolder lh(lock_);
214  size *= sizeof(T);
215  void* array_ptr = static_cast<void*>(array);
216  // make sure it's NOT managed by me
217  std::map<void*, ResourceAttribites>::iterator pos = managed_arrays_.find(array_ptr);
218  if (pos != managed_arrays_.end()) {
219  std::ostringstream oss;
220  oss << indent << "ConsumableResources::manage_array() -- given managed array (ptr="
221  << array_ptr << " size=" << size << ")";
222  throw ProgrammingError(oss.str().c_str(), __FILE__, __LINE__, class_desc());
223  }
224 
225  try {
226  consume_memory_(size);
227  }
228  catch (LimitExceeded<size_t>&) {
229  this->print_summary(ExEnv::out0(), true, true);
230  throw;
231  }
232 
233  ResourceAttribites attr(size);
234  managed_arrays_[array_ptr] = attr;
235  if (debug()) {
236  ExEnv::out0() << indent << "ConsumableResources::manage_array(array=" << array_ptr << ", size=" << size << ")" << std::endl;
237  }
238  }
239  }
241  template <typename T> void unmanage_array(T* const & array) {
242  if (object_is_gone()) return;
243  if (not do_profile()) return;
244 
245  if (array != 0) {
246  ThreadLockHolder lh(lock_);
247  void* array_ptr = static_cast<void*>(array);
248  // make sure it's managed by me
249  std::map<void*, ResourceAttribites>::iterator pos = managed_arrays_.find(array_ptr);
250  if (pos != managed_arrays_.end()) {
251  const size_t size = pos->second.size;
252  release_memory_(size);
253  if (debug()) {
254  ExEnv::out0() << indent << "ConsumableResources::unmanage_array(array=" << array_ptr << ": size=" << size << ")" << std::endl;
255  }
256  managed_arrays_.erase(pos);
257  }
258  else {
259  void* array_ptr = static_cast<void*>(array);
260  std::ostringstream oss;
261  oss << "ConsumableResources::unmanage_array() -- given non-managed array (ptr="
262  << array_ptr << " size=" << pos->second.size << ")";
263  throw ProgrammingError(oss.str().c_str(), __FILE__, __LINE__, class_desc());
264  }
265  }
266  }
267 
268  // need to check and report any anomalous events?
269  static bool debug() { return MPQC_MEMORY_CHECK >= 3; }
270  // need to profile resource usage?
271  static bool do_profile() { return MPQC_MEMORY_CHECK >= 1; }
272 
273  private:
274  static ClassDesc class_desc_;
275 
277  void consume_memory_(size_t value);
279  void consume_disk_(size_t value);
281 
283  void release_memory_(size_t value);
285  void release_disk_(size_t value);
287 
289  bool object_is_gone();
291  static bool default_object_is_gone();
292 
297  void summarize_unreleased_resources(std::ostream& os = sc::ExEnv::err0()) const;
298 
299  struct defaults {
300  static size_t memory;
301  static std::pair<std::string,size_t> disk;
302  };
303 
304  template <typename T> class ResourceCounter {
305  public:
306  ResourceCounter() :
307  max_value_(),
308  value_(),
309  lowest_value_()
310  {
311  }
312  ResourceCounter(const T& max_value) :
313  max_value_(max_value),
314  value_(max_value),
315  lowest_value_(max_value)
316  {
317  }
318  ResourceCounter(const T& max_value, const T& value) :
319  max_value_(max_value),
320  value_(value),
321  lowest_value_(value)
322  {
323  MPQC_ASSERT(value <= max_value);
324  }
325  ResourceCounter(const ResourceCounter& other) :
326  max_value_(other.max_value_),
327  value_(other.value_),
328  lowest_value_(other.lowest_value_)
329  {
330  }
331  ResourceCounter& operator=(const ResourceCounter& other) {
332  max_value_ = other.max_value_;
333  value_ = other.value_;
334  lowest_value_ = other.lowest_value_;
335  return *this;
336  }
337  operator T() const { return value_; }
338  ResourceCounter& operator+=(const T& val) { value_ = std::min(max_value_, value_ + val); return *this; }
339  // nonthrowing
340  ResourceCounter& operator-=(const T& val) {
341  value_ = std::max(T(0), value_ - val);
342  lowest_value_ = std::min(value_,lowest_value_);
343  return *this;
344  }
345 
346  const T& max_value() const { return max_value_; }
347  const T& value() const { return value_; }
348  const T& lowest_value() const { return lowest_value_; }
349 
350  static std::string value_to_string(T value) {
351  return to_string(value, true);
352  }
353  static std::string difference_to_string(T value) {
354  return to_string(value, false);
355  }
356 
357  void operator &(StateIn& s) {
358  s.get(max_value_);
359  s.get(value_);
360  s.get(lowest_value_);
361  }
362  void operator &(StateOut& s) {
363  s.put(max_value_);
364  s.put(value_);
365  s.put(lowest_value_);
366  }
367 
368  private:
369  T max_value_;
370  T value_;
371  T lowest_value_; //< keeps track of the lowest value of the resource
372 
373  static std::string to_string(T t, bool may_be_unlimited) {
374  const int prec = 3; // print this many digits
375 
376  if (may_be_unlimited && t == std::numeric_limits<T>::max())
377  return "unlimited";
378 
379  // determine m such that 1000^m <= t <= 1000^(m+1)
380  char m = 0;
381  double thousand_m = 1;
382  double thousand_mp1 = 1000;
383  while (t >= thousand_mp1) {
384  ++m;
385  thousand_m = thousand_mp1;
386  thousand_mp1 *= 1000;
387  }
388 
389  // determine units
390  std::string unit;
391  switch (m) {
392  case 0: unit = "B"; break;
393  case 1: unit = "kB"; break;
394  case 2: unit = "MB"; break;
395  case 3: unit = "GB"; break;
396  case 4: unit = "TB"; break;
397  case 5: unit = "PB"; break;
398  case 6: unit = "EB"; break;
399  case 7: unit = "ZB"; break;
400  case 8: unit = "YB"; break;
401  default: MPQC_ASSERT(false); break;
402  }
403 
404  // compute normalized mantissa
405  std::ostringstream oss;
406  oss.precision(prec);
407  oss << (double)t/(double)thousand_m << unit;
408  return oss.str();
409  }
410  };
411 
412  typedef ResourceCounter<size_t> rsize;
413  rsize memory_;
414  std::pair<std::string, rsize> disk_;
415 
417  struct ResourceAttribites {
418  ResourceAttribites() : size(0) {
419  }
420  ResourceAttribites(std::size_t s) : size(s) {
421  }
422  std::size_t size;
423 #if MPQC_MEMORY_CHECK >= 2
424  Debugger::Backtrace backtrace;
425 #endif
426  operator std::string() const {
427  std::ostringstream oss;
428  oss << "size=" << size;
429 #if MPQC_MEMORY_CHECK >= 2
430  const size_t nframes_to_skip = 1;
431  oss << " allocated at:" << std::endl << backtrace.str(nframes_to_skip);
432 #endif
433  return oss.str();
434  }
435  };
436 
439  std::map<void*, ResourceAttribites> managed_arrays_;
440  Ref<ThreadLock> lock_; // the lock used to protect the map and resource counters
441 
442  static Ref<ConsumableResources> default_instance_;
443 
444  };
445 
447  template <typename T> T* allocate(std::size_t size) {
449  return ConsumableResources::get_default_instance()->allocate<T>(size);
450  }
452  template <typename T> void deallocate(T*& array) {
453  // deallocation after this is gone is OK, .pointer() ensures that dereferencing does not abort
454  ConsumableResources::get_default_instance().pointer()->deallocate(array);
455  }
456  template <typename T> void deallocate(T* const & array) {
457  // deallocation after this is gone is OK, .pointer() ensures that dereferencing does not abort
458  ConsumableResources::get_default_instance().pointer()->deallocate(array);
459  }
461 
463  template <typename T> void manage_array(T* const & array, std::size_t size) {
465  ConsumableResources::get_default_instance()->manage_array(array, size);
466  }
467  template <typename T> void unmanage_array(T* const & array) {
468  ConsumableResources::get_default_instance()->unmanage_array(array);
469  }
470 
471 
472 } // end of namespace sc
473 
474 #endif // end of header guard
475 
476 
477 // Local Variables:
478 // mode: c++
479 // c-file-style: "CLJ-CONDENSED"
480 // End:
sc::ConsumableResources
ConsumableResources keeps track of consumable resources (memory, disk).
Definition: consumableresources.h:46
sc::ConsumableResources::disk_location
const std::string & disk_location() const
UNIX path (absolute or relative) to the disk resource.
sc::MemAllocFailed
This is thrown when a memory allocation fails.
Definition: scexception.h:221
sc::ConsumableResources::deallocate
void deallocate(T *const &array)
deallocate array of T that was allocated using ConsumableResources::allocate() using operator delete[...
Definition: consumableresources.h:166
sc::Ref
A template class that maintains references counts.
Definition: ref.h:361
sc::ConsumableResources::deallocate
void deallocate(T *&array)
same as before, but will set array to 0 after deallocation
Definition: consumableresources.h:195
sc::ConsumableResources::memory
size_t memory() const
how much resource is currently available
sc::ConsumableResources::sprint
std::string sprint() const
prints short definition to a string
sc::StateIn
Definition: statein.h:79
sc::ConsumableResources::set_default_instance
static void set_default_instance(const Ref< ConsumableResources > &)
Specifies a new default ConsumableResources.
sc::ExEnv::err0
static std::ostream & err0()
Return an ostream for error messages that writes from node 0.
Definition: exenv.h:87
sc::ConsumableResources::print_summary
void print_summary(std::ostream &os=ExEnv::out0(), bool print_state=true, bool print_stats=false) const
prints ConsumableResources
sc::LimitExceeded
This is thrown when a limit is exceeded.
Definition: scexception.h:447
mpqc::operator&
range operator&(const range &a, const range &b)
Range intersection.
Definition: range.hpp:70
sc::ConsumableResources::release_memory
void release_memory(size_t value)
release resouce, may throw ProgrammingError if releasing more resource than how much has been consume...
sc::ConsumableResources::allocate
T * allocate(std::size_t size)
allocate array of T size elements long using operator new[] (keeps track of memory)
Definition: consumableresources.h:116
sc::ConsumableResources::unmanage_array
void unmanage_array(T *const &array)
removes array to the list of managed arrays and increments the memory counter
Definition: consumableresources.h:241
sc::other
SpinCase1 other(SpinCase1 S)
given 1-spin return the other 1-spin
sc::ConsumableResources::initial_instance
static Ref< ConsumableResources > initial_instance(int &argc, char **argv)
Create a ConsumableResources object.
sc::StateOut
Definition: stateout.h:71
sc::DescribedClass::class_desc
ClassDesc * class_desc() const MPQC__NOEXCEPT
This returns the unique pointer to the ClassDesc corresponding to the given type_info object.
sc::allocate
T * allocate(std::size_t size)
allocate and deallocate array of data using new or new[] (delete or delete[]) and using default Consu...
Definition: consumableresources.h:448
sc::ConsumableResources::manage_array
void manage_array(T *const &array, std::size_t size)
adds array to the list of managed arrays and decrements the memory counter
Definition: consumableresources.h:209
sc::ProgrammingError
This is thrown when a situations arises that should be impossible.
Definition: scexception.h:92
sc::ExEnv::out0
static std::ostream & out0()
Return an ostream that writes from node 0.
sc::ConsumableResources::consume_memory
void consume_memory(size_t value)
consume resource, may throw LimitExceeded<size_t> if not enough available
sc::SavableState
Base class for objects that can save/restore state.
Definition: state.h:45
sc::deallocate
void deallocate(T *&array)
this version will set array to 0 upon return
Definition: consumableresources.h:452
sc::ThreadLockHolder
Acquire a lock on creation and release it on destruction.
Definition: thread.h:56
sc::ConsumableResources::max_memory
size_t max_memory() const
how much resource was given
sc
Contains all MPQC code up to version 3.
Definition: mpqcin.h:14
sc::ConsumableResources::get_default_instance
static const Ref< ConsumableResources > & get_default_instance()
Returns the default ConsumableResources object.
sc::ConsumableResources::save_data_state
void save_data_state(StateOut &)
Save the base classes (with save_data_state) and the members in the same order that the StateIn CTOR ...
sc::manage_array
void manage_array(T *const &array, std::size_t size)
manage or unmanaged array of data using default ConsumableResources object
Definition: consumableresources.h:464

Generated at Sun Jan 26 2020 23:24:01 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.8.16.