MPQC 3.0.0-alpha
Loading...
Searching...
No Matches
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
43namespace sc {
44
46 class ConsumableResources : virtual public SavableState {
47 public:
67
69
70 size_t max_memory() const;
71 size_t max_disk() const;
73
75
76 size_t memory() const;
77 size_t disk() const;
79
81
82 void consume_memory(size_t value);
83 void consume_disk(size_t value);
85
87
88 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
166 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
278 void consume_memory_(size_t value);
279 void consume_disk_(size_t value);
281
283
284 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
448 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
464 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:
ConsumableResources keeps track of consumable resources (memory, disk).
Definition consumableresources.h:46
static const Ref< ConsumableResources > & get_default_instance()
Returns the default ConsumableResources object.
void print_summary(std::ostream &os=ExEnv::out0(), bool print_state=true, bool print_stats=false) const
prints ConsumableResources
T * allocate(std::size_t size)
allocate array of T size elements long using operator new[] (keeps track of memory)
Definition consumableresources.h:116
static void set_default_instance(const Ref< ConsumableResources > &)
Specifies a new default ConsumableResources.
void deallocate(T *&array)
same as before, but will set array to 0 after deallocation
Definition consumableresources.h:195
void deallocate(T *const &array)
deallocate array of T that was allocated using ConsumableResources::allocate() using operator delete[...
Definition consumableresources.h:166
void consume_memory(size_t value)
consume resource, may throw LimitExceeded<size_t> if not enough available
void release_memory(size_t value)
release resouce, may throw ProgrammingError if releasing more resource than how much has been consume...
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
size_t memory() const
how much resource is currently available
std::string sprint() const
prints short definition to a string
ConsumableResources(const Ref< KeyVal > &kv)
A KeyVal constructor is used to generate a ConsumableResources object from the input.
const std::string & disk_location() const
UNIX path (absolute or relative) to the disk resource.
void save_data_state(StateOut &)
Save the base classes (with save_data_state) and the members in the same order that the StateIn CTOR ...
size_t max_memory() const
how much resource was given
void unmanage_array(T *const &array)
removes array to the list of managed arrays and increments the memory counter
Definition consumableresources.h:241
static Ref< ConsumableResources > initial_instance(int &argc, char **argv)
Create a ConsumableResources object.
ClassDesc * class_desc() const MPQC__NOEXCEPT
This returns the unique pointer to the ClassDesc corresponding to the given type_info object.
static std::ostream & out0()
Return an ostream that writes from node 0.
static std::ostream & err0()
Return an ostream for error messages that writes from node 0.
Definition exenv.h:87
This is thrown when a limit is exceeded.
Definition scexception.h:447
This is thrown when a memory allocation fails.
Definition scexception.h:221
This is thrown when a situations arises that should be impossible.
Definition scexception.h:92
A template class that maintains references counts.
Definition ref.h:361
Base class for objects that can save/restore state.
Definition state.h:45
Restores fundamental and user-defined types from images created with StateOut.
Definition statein.h:79
Serializes fundamental and user-defined types.
Definition stateout.h:71
Acquire a lock on creation and release it on destruction.
Definition thread.h:56
SpinCase1 other(SpinCase1 S)
given 1-spin return the other 1-spin
Contains all MPQC code up to version 3.
Definition mpqcin.h:14
void manage_array(T *const &array, std::size_t size)
manage or unmanaged array of data using default ConsumableResources object
Definition consumableresources.h:464
void deallocate(T *&array)
this version will set array to 0 upon return
Definition consumableresources.h:452
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

Generated at Wed Sep 25 2024 02:45:31 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.12.0.