MemoryManager.h 21.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// ============================================================================
// ==                                                                        ==
// == AMDiS - Adaptive multidimensional simulations                          ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  crystal growth group                                                  ==
// ==                                                                        ==
// ==  Stiftung caesar                                                       ==
// ==  Ludwig-Erhard-Allee 2                                                 ==
// ==  53175 Bonn                                                            ==
// ==  germany                                                               ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  http://www.caesar.de/cg/AMDiS                                         ==
// ==                                                                        ==
// ============================================================================

/** \file MemoryManager.h */

/** \defgroup Memory Memory management module
 * @{ <img src="memory.png"> @}
 *
 * \brief
 * Memory monitoring and preallocation.
 */

#ifndef AMDIS_MEMORYMANAGER_H
#define AMDIS_MEMORYMANAGER_H

#include "Global.h"
#include "MemoryPool.h"
#include <vector>
#include <string>
#include <typeinfo>
#include <algorithm>
#include <functional>
#include <fstream>

namespace AMDiS {

  class MemoryMonitor;
  class InstanceCounterBase;
  template<typename T> class InstanceCounter;

  // ============================================================================
  // ===== class MemoryManagerBase ==============================================
  // ============================================================================

  /** \ingroup Memory
   * \brief
   * MemoryManagerBase is the template type independent base class of
   * MemoryManager. It holds a static vector of all concrete MemoryManagers,
   * so a memory statistic for all managed types can be printed by 
   * \ref printStatistics(). A concrete MemoryManager class in general is
   * a static class, so memory operations can be done without an instance of
   * a MemoryManager. But MemoryManagerBase should be able to handle 
   * different concrete MemoryManagers without knowing their exact types.
   * Therefore a concrete MemoryManager must have a singleton instance too,
   * which gives MemoryManagerBase access to its static members by pointing
   * to this singleton instance.
   *
   * <img src = "memory.png">
   */
  class MemoryManagerBase
  {
  public:
    /**  \brief
     * Destructor does nothing
     */
    virtual ~MemoryManagerBase() {};

    /** \brief
     * Prints the number of currently allocated bytes (\ref byteCount) and for 
     * all MemoryManagers in \ref memoryManagers the number of currently 
     * allocated instances. 
     */
    static void printStatistics() {
      FUNCNAME("MemoryManagerBase::printStatistics()");

      const char* pl="s\n";
      const char* sg="\n";

      sort(memoryManagers.begin(), memoryManagers.end(), orderInstanceCount());
      ::std::vector<MemoryManagerBase*>::iterator it;
      MSG("================================================================\n");
      MSG("memory statistics:\n");
      MSG("==================\n");
      MSG("byte count: %ld\n", byteCount);
      for(it = memoryManagers.begin(); it != memoryManagers.end(); it++) {
	if((*it)->instanceCount != 0) {
	  MSG("%s, id = %ld : %ld instance%s",
	      (*it)->getName().c_str(), (*it)->typeId, (*it)->instanceCount,((*it)->instanceCount > 1)?pl:sg);
	  //	if((*it)->instanceCount > 1)
	  //  MSG("s");
	  // MSG("\n");
	}
      }
      MSG("================================================================\n");
    };

    /** \brief
     * Must be overriden for concrete MemoryManagers. Returns the name of
     * the managed data type. Can be accessed via the singleton pointer of
     * MemoryManager<T>.
     */
    virtual ::std::string getName() = 0;

    /** \brief
     * Returns the number of currently allocated instances (\ref instanceCount).
     */
    inline unsigned long int getInstanceCount() {
      return instanceCount;
    };

    /** \brief
     * Returns the number of currently allocated bytes (\ref typedByteCount).
     */
    inline unsigned long int getTypedByteCount() {
      return typedByteCount;
    };

    /** \brief
     * Returns a new InstanceCounter for concrete type
     * Must be overloaded by a concrete MemoryManager<T>.
     */
    virtual InstanceCounterBase* newInstanceCounter() = 0;

    /** \brief
     * Register a new MemoryMonitor
     */
    static void addMemoryMonitor(MemoryMonitor* monitor); 

    /** \brief
     * Remove a registered MemoryMonitor
     */
    static void removeMemoryMonitor(MemoryMonitor* monitor);
  
  protected:
    /** \brief
     * Used in \ref printStatistics() to sort the MemoryManagers by the number
     * of currently allocated instances.
     */
    class orderInstanceCount 
      : public ::std::binary_function<MemoryManagerBase*,MemoryManagerBase*, bool>
    {
    public:
      bool operator()(MemoryManagerBase *a, MemoryManagerBase *b) {
	return (a->getInstanceCount() > b->getInstanceCount());
      };
    };

  protected:
    /** \brief
     * Number of currently allocated instances in a concrete MemoryManager<T>.
     * Note that this member is not static, so every MemoryManager<T> has
     * its own instanceCount which can be accessed via the singleton pointer.
     */
    unsigned long int instanceCount;

    /** \brief
     * byte count for a special type
     */
    unsigned long int typedByteCount;

    /** \brief
     * ID of the managed data type. Usefull if no typeid is accessable. Note 
     * that this member is not static, so every MemoryManager<T> has
     * its own typeId which can be accessed via the singleton pointer.
     */
    unsigned long int typeId;

    /** \brief
     * Number of totally allocated bytes by all managers in \ref memoryManagers.
     */
    static unsigned long int byteCount;

    /** \brief
     * Vector of all MemoryManagers. Every concrete MemoryManager must add
     * a pointer to itself to this vector when constructed. 
     */
    static ::std::vector<MemoryManagerBase*> memoryManagers;

    /** \brief
     * List of all registered MemoryMonitors
     */
    static ::std::vector<MemoryMonitor*> memoryMonitors;

    /** \brief
     * Used to create unique IDs for every concrete MemoryManager
     */
    static unsigned long int idCounter;
  };


  // ============================================================================
  // ===== class MemoryManager ==================================================
  // ============================================================================

  /** \ingroup Memory
   * \brief
   * The main task of a MemoryManager is to count the number of instances
   * of the managed type T. Every instance of T then must be allocated
   * by \ref MemoryManager<T>::getMemory().
   * The memory is freed by \ref MemoryManager<T>::freeMemory() 
   * If a class is \ref MEMORY_MANAGED
   * the operators new, delete, new[] and delete[] are overloaded, so that
   * the corresponding MemoryManager calls are performed. If you use then the 
   * \ref NEW and \ref DELETE macros additionally file name and line number
   * of the macro call are passed to the MemoryManager and will be printed
   * on every call of \ref getMemory() if \ref printInfo is true. if you
   * allocate and deallocate memory for a MEMORY_MANAGED class by new and delete
   * this information will not be present, but the calls are still passed
   * through MemoryManager.
   * If you want to allocate memory for scalar data types with MemoryManager
   * you can use the macros \ref GET_MEMORY and \ref FREE_MEMORY which
   * will call \ref MemoryManager<T>::getMemory()/
   * \ref MemoryManager<T>::freeMemory() with file name and line number 
   * information. In this case no new- or delete-operators are called, so
   * even no constructors or destructors are called.
   * If \ref preallocated is true, all memory allocation and deallocation
   * operations are deligated to MemoryPool.
   *
   * <img src = "memory.png">
   */
  template<typename T>
  class MemoryManager : public MemoryManagerBase
  {
  protected:
    /** \brief
     * Constructor
     */
    MemoryManager() {};

  public:
    /** \brief
     * Initialisation of the MemoryManager. Creates the \ref singleton instance
     * with initialized typeId and instanceCount (see \ref MemoryManagerBase),
     * and adds a pointer to \ref singleton to 
     * \ref MemoryManagerBase::memoryManagers
     */
    static void init();

    /** \brief
     * Returns memory for one instance of T. If MemoryManager<T> is not yet
     * initialized, \ref init() will be called. The byte and instance counter
     * are incremented and if \ref printInfo is true, information about this
     * memory allocation are printed. If \ref preallocatable is true, the
     * allocation is deligated to MemoryPool, otherwise it is done here.
     */
    static T* getMemory(size_t s, const char* filename, int line) {
      FUNCNAME("MemoryManager<T>::getMemory()");
Thomas Witkowski's avatar
Thomas Witkowski committed
254
255
      if (!singleton) 
	init();
256
257
258
      byteCount += s;
      singleton->instanceCount += s/sizeof(T);
      singleton->typedByteCount += s;
Thomas Witkowski's avatar
Thomas Witkowski committed
259
260
      if (printInfo) {
	if (filename && line) {
261
	  MSG("FILE: %s, LINE: %d  -  ", filename, line);
Thomas Witkowski's avatar
Thomas Witkowski committed
262
263
	}

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
	Msg::print("%s::getMemory : %d instances, total : %d instances\n", 
		   singleton->getName().c_str(), s/sizeof(T), 
		   static_cast<int>(singleton->instanceCount));
      }
      return 
	preallocatable ? 
	reinterpret_cast<T*>(MemoryPool::getMemory(s)) :
	reinterpret_cast<T*>(new char[s]);
    };

    /** \brief
     * Frees memory which was allocated by \ref getMemory(). If \ref printInfo
     * is true, information about this deallocation is printed
     */
    static void freeMemory(T* mem, size_t s) {
      FUNCNAME("MemoryManager<T>::freeMemory()");
      TEST_EXIT(singleton)("not initialized\n");    
      byteCount -= s;
      singleton->instanceCount -= s/sizeof(T);
      singleton->typedByteCount -= s;
      if(printInfo) {
	MSG("%s::freeMemory : %d instances, total : %d instances\n", 
	    singleton->getName().c_str(), s/sizeof(T), 
	    static_cast<int>(singleton->instanceCount));
      }
      preallocatable ?
	MemoryPool::freeMemory(mem, s) :
	delete [] (reinterpret_cast<char*>(mem));
    };

    /** \brief
     * Returns name of T by demangle the mangled typeid of T.
     */
    inline ::std::string getName() {
#if 0
      char result[100];
      //     demangle(typeid(T).name(), result);
      int status;
      size_t length;
      abi::__cxa_demangle(typeid(T).name(), result, &length, &status);
      TEST_EXIT(status == 0)("demangling failed\n");
      return ::std::string(result);
#endif
      return typeid(T).name();
    };

    /** \brief
     * Sets \ref preallocatable
     */
    static void setPreallocatable(bool prealloc) {
      preallocatable = prealloc;
    };

    /** \brief
     * Sets \ref printInfo
     */
    static void setPrintInfo(bool p) {
      printInfo = p;
    };

    /** \brief
     * Returns \ref printInfo
     */
    static bool getPrintInfo() { return printInfo; };

    /** \brief
     * Returns the pointer to the \ref singleton instance of MemoryManager<T>
     */
    static MemoryManager<T>* getSingleton() { return singleton; };

    /** \brief
     * Implementation of \ref MemoryManagerBase::newInstanceCounter()
     */
    InstanceCounterBase* newInstanceCounter() {
      return new InstanceCounter<T>;
    };

  protected:
    /** \brief
     * The one and only instance of a MemoryManager for this type T
     */
    static MemoryManager<T> *singleton;

    /** \brief
     * Determines whether memory allocation is deligated to MemoryPool
     */
    static bool preallocatable;

    /** \brief
     * Determines whether information should be printed when allocating and
     * deallocationg memory.
     */
    static bool printInfo;
  }; 

  template<typename T>
  MemoryManager<T> *MemoryManager<T>::singleton = NULL;

  template<typename T>
  bool MemoryManager<T>::preallocatable = false;

  template<typename T>
  bool MemoryManager<T>::printInfo = false;

  // ============================================================================
  // ===== class InstanceCounterBase ============================================
  // ============================================================================

  /** \ingroup Memory
   * \brief
   * Template type independent interface for InstanceCounter. A MemoryMonitor
   * holds a list of InstanceCounters for the different data types.
   *
   * <img src = "memory.png">
   */
  class InstanceCounterBase
  {
  public:
    /** \brief
     * To be overloaded by a concrete InstanceCounter
     */
    virtual long int getInstanceCount() = 0;

    /** \brief
     * To be overloaded by a concrete InstanceCounter
     */
    virtual ::std::string getTypeName() = 0;

    /** \brief
     * Destructor
     */
    virtual ~InstanceCounterBase() {};
  };

  // ============================================================================
  // ===== class InstanceCounter ================================================
  // ============================================================================

  /** \ingroup Memory
   * \brief
   * When an InstanceCounter<T> is created, it remembers the current number
   * of T instances in MemoryManager<T>. After that one can get the difference
   * between this remembered number and the current number in MemoryManager<T>
   * by \ref getInstanceCount() at every time. A MemoryMonitor holds a list
   * of InstanceCounters for the different data types.
   */
  template<typename T>
  class InstanceCounter : public InstanceCounterBase
  {
  public:
    /** \brief
     * Creates an InstanceCounter and stores the current instanceCount of
     * MemoryManager<T> in \ref oldInstanceCount.
     */
    InstanceCounter() 
      : oldInstanceCount(MemoryManager<T>::getSingleton()->getInstanceCount()) 
    {};

    /** \brief
     * Sets \ref oldInstanceCount to the current number of instances in 
     * MemoryManager<T>
     */
    inline void reset() { 
      oldInstanceCount = MemoryManager<T>::getSingleton()->getInstanceCount();
    };

    /** \brief
     * Returns the difference between the current instanceCount and
     * \ref oldInstanceCount
     */
    long int getInstanceCount() {
      return (MemoryManager<T>::getSingleton()->getInstanceCount() - 
	      oldInstanceCount);
    };

    /** \brief
     * Returns the name of T. Calls MemoryManager<T>::getName()
     */
    ::std::string getTypeName() {
      return MemoryManager<T>::getSingleton()->getName();
    };

  protected:
    /** \brief
     * Number of instances in MemoryManager<T> at creation time of this
     * InstanceCounter. Can be reseted by \ref reset()
     */
    long int oldInstanceCount;
  };

  // ============================================================================
  // ===== class MemoryMonitor ==================================================
  // ============================================================================

  /** \ingroup Memory
   * \brief
   * A MemoryMonitor counts from its construction time the number of allocated 
   * instances for every memory managed data type. It holds a list with one
   * InstanceCounter for every managed data type. This list is updated by
   * MemoryManagerBase. Herefore MemoryManagerBase needs a list of all
   * MemoryMonitors. So a MemoryMonitor must register itself when constructed
   * and deregister when deleted.
   *
   * <img src = "memory.png">
   */
  class MemoryMonitor
  {
  public:
    /** \brief
     * Constructor. Registers itself with MemoryMonitorBase.
     */
    MemoryMonitor(const char *name_, const char *filename_=NULL) 
      : name(name_), filename(filename_)
    {
      MemoryManagerBase::addMemoryMonitor(this);
    };

    /** \brief
     * Destructor. Prints statistics and deregisters itself with 
     * MemoryManagerBase.
     */
    ~MemoryMonitor() {
      printStatistics();
      MemoryManagerBase::removeMemoryMonitor(this);
    };

    /** \brief
     * Prints a statistic for every data type with instanceCount - 
     * \ref oldInstanceCount != 0.
     */
    void printStatistics() {
      FUNCNAME("MemoryMonitor::printStatistics()");
      ::std::ostream *oldOut;
      static bool fileOpen = false;
      if(filename && !fileOpen) {
	oldOut = Msg::getOutStream();
	Msg::open_file(filename, ::std::ios::out);
	fileOpen = true;
      }
      ::std::vector<InstanceCounterBase*>::iterator it;
      sort(instanceCounters.begin(), 
	   instanceCounters.end(), 
	   orderInstanceCount());
      MSG("MemoryMonitor %s - statistics since creation:\n", name.c_str());
      for(it = instanceCounters.begin(); it != instanceCounters.end(); it++) {
	if((*it)->getInstanceCount() != 0) {
	  MSG("%s : %d instance",
	      (*it)->getTypeName().c_str(),
	      static_cast<int>((*it)->getInstanceCount()));
	  if(static_cast<int>((*it)->getInstanceCount()) > 1)
	    Msg::print("s");
	  MSG("\n");
	}
      }
      if(filename) {
	Msg::change_out(oldOut);
      }
    };

    /** \brief
     * Adds a InstanceCounter to \ref instanceCounters. Used by MemoryManagerBase
     * to update the list of InstanceCounters
     */
    inline void addInstanceCounter(InstanceCounterBase* counter) {
      instanceCounters.push_back(counter);
    };

  protected:
    /** \brief
     * Used in \ref printStatistics() to sort the InstanceCounters by the number
     * of currently allocated instances.
     */
    class orderInstanceCount 
      : public ::std::binary_function<InstanceCounterBase*,InstanceCounterBase*, bool>
    {
    public:
      bool operator()(InstanceCounterBase *a, InstanceCounterBase *b) {
	return (a->getInstanceCount() > b->getInstanceCount());
      };
    };

  protected:
    /** \brief
     * Name of the monitor
     */
    ::std::string name;

    /** \brief
     * Filename
     */
    const char *filename;

    /** \brief
     * List with InstanceCounters for every data type
     */
    ::std::vector<InstanceCounterBase*> instanceCounters;

    friend class MemoryManagerBase;
  };

  template<typename T>
  void MemoryManager<T>::init() 
  {
    FUNCNAME("MemoryManager<T>::init()");
    TEST_EXIT(singleton == NULL)("already initialized\n");

    singleton = new MemoryManager<T>;
    singleton->typeId = idCounter++;
    singleton->instanceCount = 0;
    memoryManagers.push_back(singleton);
    ::std::vector<MemoryMonitor*>::iterator it;
    for(it = memoryMonitors.begin(); it != memoryMonitors.end(); it++) {
      (*it)->addInstanceCounter(new InstanceCounter<T>);
    }
  }

  /** \brief
   * If MEMORY_MANAGED(T) is called in the public declaration of class T
   * the operators new, delete, new[], and delete[] are overloaded:
   * new and new[] calls \ref MemoryManager<T>::getMemory(), 
   * delete and delete[] calls \ref MemoryManager<T>::freeMemory().
   * If you use the macro \ref NEW for memory allocation, additional information
   * about the file name and line number are given to the new operators which
   * are printed if \ref MemoryManager<T>::printInfo is true.
   */
#define MEMORY_MANAGED(className)					\
  void *operator new(size_t s)						\
  {									\
    return MemoryManager<className>::getMemory(s, NULL, 0);		\
  };									\
    void *operator new(size_t s, const char *filename, int line)	\
    {									\
      return MemoryManager<className>::getMemory(s, filename, line);	\
    };									\
    void operator delete(void *mem, size_t s)				\
    { MemoryManager<className>::freeMemory(static_cast<className*>(mem), s);}; \
    void *operator new[](size_t s, const char *filename=NULL, int line=0) \
    {									\
      return MemoryManager<className>::getMemory(s, filename, line);	\
    };									\
    void operator delete[](void *mem, size_t s)				\
    { MemoryManager<className>::freeMemory(static_cast<className*>(mem), s); };	\
    void *operator new(size_t, void *ptr) {				\
      return ptr;							\
    }

  /** \brief
   * Calls the new operator with additional file name and line number information
   */
  //#define NEW new (__FILE__,__LINE__) // leads to internal compiler error in some cases
#define NEW new

  /** \brief
   * Calls the delete operator.
   */
#define DELETE delete

  /** \brief
   * Allocates memory for number instances of the given type. Additionally
   * file name and line number information are given to the MemoryManager.
   * Use this macro to allocate scalar data types with a MemoryManager.
   */
#define GET_MEMORY(typename, number)					\
  MemoryManager<typename>::getMemory((number) * sizeof(typename),	\
                                     __FILE__,__LINE__)

  /** \brief
   * Deallocation of memory allocated with \ref GET_MEMORY
   */
#define FREE_MEMORY(ptr, typename, number)				\
  MemoryManager<typename>::freeMemory(ptr, (number) * sizeof(typename))


  // use these macros to deactivate memory management
#if 0
#define MEMORY_MANAGED(className) ;
#define NEW new
#define DELETE delete
#define GET_MEMORY(typename, number) new typename[number]
#define FREE_MEMORY(ptr, typename, number) delete [] ptr
#endif

}

#endif // AMDIS_MEMORYMANAGER_H