MemoryManager.h 21 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
// ============================================================================
// ==                                                                        ==
// == 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
     */
72
    virtual ~MemoryManagerBase() {}
73
74
75
76
77
78
79
80
81
82
83
84
85

    /** \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());
86
      std::vector<MemoryManagerBase*>::iterator it;
87
88
89
90
      MSG("================================================================\n");
      MSG("memory statistics:\n");
      MSG("==================\n");
      MSG("byte count: %ld\n", byteCount);
91
92
      for (it = memoryManagers.begin(); it != memoryManagers.end(); it++) {
	if ((*it)->instanceCount != 0) {
93
94
95
96
97
98
99
100
	  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");
101
    }
102
103
104
105
106
107

    /** \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>.
     */
108
    virtual std::string getName() = 0;
109
110
111
112
113
114

    /** \brief
     * Returns the number of currently allocated instances (\ref instanceCount).
     */
    inline unsigned long int getInstanceCount() {
      return instanceCount;
115
    }
116
117
118
119
120
121

    /** \brief
     * Returns the number of currently allocated bytes (\ref typedByteCount).
     */
    inline unsigned long int getTypedByteCount() {
      return typedByteCount;
122
    }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

    /** \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 
146
      : public std::binary_function<MemoryManagerBase*,MemoryManagerBase*, bool>
147
148
149
150
    {
    public:
      bool operator()(MemoryManagerBase *a, MemoryManagerBase *b) {
	return (a->getInstanceCount() > b->getInstanceCount());
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
    };

  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. 
     */
183
    static std::vector<MemoryManagerBase*> memoryManagers;
184
185
186
187

    /** \brief
     * List of all registered MemoryMonitors
     */
188
    static std::vector<MemoryMonitor*> memoryMonitors;
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

    /** \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
     */
234
    MemoryManager() {}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

  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
	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]);
272
    }
273
274
275
276
277
278
279

    /** \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()");
280
      TEST_EXIT_DBG(singleton)("not initialized\n");    
281
282
283
284
285
286
287
288
289
290
291
      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));
292
    }
293
294
295
296

    /** \brief
     * Returns name of T by demangle the mangled typeid of T.
     */
297
    inline std::string getName() {
298
      return typeid(T).name();
299
    }
300
301
302
303
304
305

    /** \brief
     * Sets \ref preallocatable
     */
    static void setPreallocatable(bool prealloc) {
      preallocatable = prealloc;
306
    }
307
308
309
310
311
312

    /** \brief
     * Sets \ref printInfo
     */
    static void setPrintInfo(bool p) {
      printInfo = p;
313
    }
314
315
316
317

    /** \brief
     * Returns \ref printInfo
     */
318
319
320
    static bool getPrintInfo() { 
      return printInfo; 
    }
321
322
323
324

    /** \brief
     * Returns the pointer to the \ref singleton instance of MemoryManager<T>
     */
325
326
327
    static MemoryManager<T>* getSingleton() { 
      return singleton; 
    }
328
329
330
331
332
333

    /** \brief
     * Implementation of \ref MemoryManagerBase::newInstanceCounter()
     */
    InstanceCounterBase* newInstanceCounter() {
      return new InstanceCounter<T>;
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

  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
     */
385
    virtual std::string getTypeName() = 0;
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

    /** \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()) 
415
    {}
416
417
418
419
420
421
422

    /** \brief
     * Sets \ref oldInstanceCount to the current number of instances in 
     * MemoryManager<T>
     */
    inline void reset() { 
      oldInstanceCount = MemoryManager<T>::getSingleton()->getInstanceCount();
423
    }
424
425
426
427
428
429
430
431

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

    /** \brief
     * Returns the name of T. Calls MemoryManager<T>::getName()
     */
437
    std::string getTypeName() {
438
      return MemoryManager<T>::getSingleton()->getName();
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

  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) 
471
472
      : name(name_), 
	filename(filename_)
473
474
    {
      MemoryManagerBase::addMemoryMonitor(this);
475
    }
476
477
478
479
480
481
482
483

    /** \brief
     * Destructor. Prints statistics and deregisters itself with 
     * MemoryManagerBase.
     */
    ~MemoryMonitor() {
      printStatistics();
      MemoryManagerBase::removeMemoryMonitor(this);
484
    }
485
486
487
488
489
490
491

    /** \brief
     * Prints a statistic for every data type with instanceCount - 
     * \ref oldInstanceCount != 0.
     */
    void printStatistics() {
      FUNCNAME("MemoryMonitor::printStatistics()");
492
      std::ostream *oldOut;
493
      static bool fileOpen = false;
494
      if (filename && !fileOpen) {
495
	oldOut = Msg::getOutStream();
496
	Msg::open_file(filename, std::ios::out);
497
498
	fileOpen = true;
      }
499
      std::vector<InstanceCounterBase*>::iterator it;
500
501
502
503
      sort(instanceCounters.begin(), 
	   instanceCounters.end(), 
	   orderInstanceCount());
      MSG("MemoryMonitor %s - statistics since creation:\n", name.c_str());
504
505
      for (it = instanceCounters.begin(); it != instanceCounters.end(); it++) {
	if ((*it)->getInstanceCount() != 0) {
506
507
508
	  MSG("%s : %d instance",
	      (*it)->getTypeName().c_str(),
	      static_cast<int>((*it)->getInstanceCount()));
509
	  if (static_cast<int>((*it)->getInstanceCount()) > 1)
510
511
512
513
	    Msg::print("s");
	  MSG("\n");
	}
      }
514
      if (filename) {
515
516
	Msg::change_out(oldOut);
      }
517
    }
518
519
520
521
522
523
524

    /** \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);
525
    }
526
527
528
529
530
531
532

  protected:
    /** \brief
     * Used in \ref printStatistics() to sort the InstanceCounters by the number
     * of currently allocated instances.
     */
    class orderInstanceCount 
533
      : public std::binary_function<InstanceCounterBase*,InstanceCounterBase*, bool>
534
535
536
537
    {
    public:
      bool operator()(InstanceCounterBase *a, InstanceCounterBase *b) {
	return (a->getInstanceCount() > b->getInstanceCount());
538
      }
539
540
541
542
543
544
    };

  protected:
    /** \brief
     * Name of the monitor
     */
545
    std::string name;
546
547
548
549
550
551
552
553
554

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

    /** \brief
     * List with InstanceCounters for every data type
     */
555
    std::vector<InstanceCounterBase*> instanceCounters;
556
557
558
559
560
561
562
563

    friend class MemoryManagerBase;
  };

  template<typename T>
  void MemoryManager<T>::init() 
  {
    FUNCNAME("MemoryManager<T>::init()");
564
    TEST_EXIT_DBG(singleton == NULL)("already initialized\n");
565
566
567
568
569

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

576
#if 0
577
578
579
580
581
582
583
584
585
586
587
588
589
  /** \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);		\
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  }									\
  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;								\
  }
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

  /** \brief
   * Calls the new operator with additional file name and line number information
   */
#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))

632
#endif
633

634

635
636
637
638
639
640
641
642
643
  // use these macros to deactivate memory management
#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 // AMDIS_MEMORYMANAGER_H