00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00040 #ifndef MAT_ALLOCATORMANAGER_HEADER
00041 #define MAT_ALLOCATORMANAGER_HEADER
00042
00043 #include <stdexcept>
00044 #include <list>
00045 #include <string>
00046 #include <sstream>
00047 #include <iomanip>
00048 #include <iostream>
00049 #include <cstdlib>
00050 #include "Allocator.h"
00051
00052 namespace mat {
00053
00054 template<class Treal>
00055 class AllocatorManager
00056 {
00057 public:
00058 void init(size_t noOfRealsPerBuffer_,
00059 size_t noOfBuffers_) {
00060 if(noOfRealsPerBuffer != 0) {
00061
00062
00063 if(noOfRealsPerBuffer_ != noOfRealsPerBuffer || noOfBuffers_ != noOfBuffers)
00064 throw std::runtime_error("Error in AllocatorManager: "
00065 "attempt to re-initialize with different parameters.");
00066 }
00067 if(noOfRealsPerBuffer_ <= 0 || noOfBuffers_ <= 0)
00068 throw std::runtime_error("Error in AllocatorManager: bad input to init().");
00069 noOfRealsPerBuffer = noOfRealsPerBuffer_;
00070 noOfBuffers = noOfBuffers_;
00071 }
00072 static AllocatorManager & instance();
00073 Treal* alloc(size_t n) {
00074 if(n != noOfRealsPerBuffer)
00075 return new Treal[n];
00076 pthread_mutex_lock(&mutex);
00077
00078 typename std::list< Allocator<Treal>* >::iterator it = list.begin();
00079 while(it != list.end()) {
00080 if(!(*it)->isFull()) {
00081
00082 Treal* ptr = (*it)->alloc();
00083 pthread_mutex_unlock(&mutex);
00084 return ptr;
00085 }
00086 it++;
00087 }
00088
00089
00090
00091
00092
00093
00094
00095
00096 Allocator<Treal>* newAllocator;
00097 try {
00098 newAllocator = new Allocator<Treal>(noOfRealsPerBuffer,
00099 noOfBuffers);
00100 }
00101 catch (const std::bad_alloc & e) {
00102 size_t noOfBytesPerAllocator = noOfBuffers * noOfRealsPerBuffer * sizeof(Treal);
00103 size_t totNoOfBytesAllocated = list.size() * noOfBytesPerAllocator;
00104 std::cerr << "Error in AllocatorManager::alloc(): std::bad_alloc exception caught. Usage before error: list.size() = " << list.size()
00105 << " --> " << (double)totNoOfBytesAllocated/1000000000 << " GB used. peakListSize = " << peakListSize << std::endl;
00106 pthread_mutex_unlock(&mutex);
00107 throw e;
00108 }
00109 catch(...) {
00110 std::cerr << "Error in AllocatorManager::alloc(): exception caught (but not std::bad_alloc!?!)." << std::endl;
00111 pthread_mutex_unlock(&mutex);
00112 throw std::runtime_error("Error in AllocatorManager::alloc(): exception caught (but not std::bad_alloc!?!).");
00113 }
00114 list.push_back(newAllocator);
00115 if(list.size() > peakListSize)
00116 peakListSize = list.size();
00117 Treal* ptr = newAllocator->alloc();
00118 pthread_mutex_unlock(&mutex);
00119 return ptr;
00120 }
00121 void free(Treal* ptr) {
00122 pthread_mutex_lock(&mutex);
00123
00124 typename std::list< Allocator<Treal>* >::iterator it = list.begin();
00125 while(it != list.end()) {
00126 if((*it)->ownsPtr(ptr)) {
00127 (*it)->free(ptr);
00128
00129 if((*it)->isEmpty()) {
00130 delete *it;
00131 list.erase(it);
00132 }
00133 pthread_mutex_unlock(&mutex);
00134 return;
00135 }
00136 it++;
00137 }
00138 delete [] ptr;
00139 pthread_mutex_unlock(&mutex);
00140 }
00141 std::string getStatistics() {
00142
00143 if(noOfRealsPerBuffer == 0) return "AllocatorManager is not initialized.";
00144
00145 size_t noOfBytesPerAllocator = noOfBuffers * noOfRealsPerBuffer * sizeof(Treal);
00146 size_t totNoOfBytesAllocated = list.size() * noOfBytesPerAllocator;
00147 size_t peakNoOfBytesAllocated = peakListSize * noOfBytesPerAllocator;
00148 size_t totNoOfBytesUsed = 0;
00149
00150 typename std::list< Allocator<Treal>* >::iterator it = list.begin();
00151 while(it != list.end()) {
00152 totNoOfBytesUsed += (size_t)((*it)->getNoOfOccupiedSlots()) * noOfRealsPerBuffer * sizeof(Treal);
00153 it++;
00154 }
00155 std::stringstream ss;
00156 ss << "AllocatorManager statistics: ";
00157 ss << std::setprecision(3)
00158 << " noOfRealsPerBuffer: " << noOfRealsPerBuffer
00159 << " noOfBuffers: " << noOfBuffers
00160 << " list.size(): " << list.size()
00161 << ". "
00162 << "Allocated: " << (double)totNoOfBytesAllocated / 1e9 << " GB, "
00163 << "Used: " << (double)totNoOfBytesUsed / 1e9 << " GB, "
00164 << "Peak alloc: " << (double)peakNoOfBytesAllocated/ 1e9 << " GB.";
00165 return ss.str();
00166 }
00167 private:
00168 AllocatorManager() : noOfRealsPerBuffer(0), noOfBuffers(0), peakListSize(0) {
00169 pthread_mutex_init(&mutex, NULL);
00170 }
00171 ~AllocatorManager() {
00172 if(!list.empty()) {
00173 std::cerr << "Error in AllocatorManager destructor: not empty." << std::endl;
00174 abort();
00175 }
00176
00177 typename std::list< Allocator<Treal>* >::iterator it = list.begin();
00178 while(it != list.end()) {
00179 delete *it;
00180 it++;
00181 }
00182 }
00183 std::list< Allocator<Treal>* > list;
00184 size_t noOfRealsPerBuffer;
00185 size_t noOfBuffers;
00186 pthread_mutex_t mutex;
00187 size_t peakListSize;
00188 };
00189
00190 }
00191
00192 #endif