ergo
AllocatorManager.h
Go to the documentation of this file.
1 /* Ergo, version 3.4, a program for linear scaling electronic structure
2  * calculations.
3  * Copyright (C) 2014 Elias Rudberg, Emanuel H. Rubensson, and Pawel Salek.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Primary academic reference:
19  * Kohn−Sham Density Functional Theory Electronic Structure Calculations
20  * with Linearly Scaling Computational Time and Memory Usage,
21  * Elias Rudberg, Emanuel H. Rubensson, and Pawel Salek,
22  * J. Chem. Theory Comput. 7, 340 (2011),
23  * <http://dx.doi.org/10.1021/ct100611z>
24  *
25  * For further information about Ergo, see <http://www.ergoscf.org>.
26  */
27 #ifndef MAT_ALLOCATORMANAGER_HEADER
28 #define MAT_ALLOCATORMANAGER_HEADER
29 
30 #include <stdexcept>
31 #include <list>
32 #include <string>
33 #include <sstream>
34 #include <iomanip> /* For setprecision */
35 #include "Allocator.h"
36 
37 namespace mat {
38 
39 template<class Treal>
41 {
42  public:
43  void init(size_t noOfRealsPerBuffer_,
44  size_t noOfBuffers_) {
45  if(noOfRealsPerBuffer != 0) {
46  // This means that the AllocatorManager has already been initialized.
47  // We allow this if the parameters are the same.
48  if(noOfRealsPerBuffer_ != noOfRealsPerBuffer || noOfBuffers_ != noOfBuffers)
49  throw std::runtime_error("Error in AllocatorManager: "
50  "attempt to re-initialize with different parameters.");
51  }
52  if(noOfRealsPerBuffer_ <= 0 || noOfBuffers_ <= 0)
53  throw std::runtime_error("Error in AllocatorManager: bad input to init().");
54  noOfRealsPerBuffer = noOfRealsPerBuffer_;
55  noOfBuffers = noOfBuffers_;
56  }
57  static AllocatorManager & instance();
58  Treal* alloc(size_t n) {
59  if(n != noOfRealsPerBuffer)
60  return new Treal[n];
61  pthread_mutex_lock(&mutex);
62  // Go through list to see if there is any free space.
63  typename std::list< Allocator<Treal>* >::iterator it = list.begin();
64  while(it != list.end()) {
65  if(!(*it)->isFull()) {
66  // OK, found allocator that is not full. Use it.
67  Treal* ptr = (*it)->alloc();
68  pthread_mutex_unlock(&mutex);
69  return ptr;
70  }
71  it++;
72  }
73  // We did not find any non-full existing allocator. Need to add a new one.
75  noOfBuffers);
76  list.push_back(newAllocator);
77  if(list.size() > peakListSize)
78  peakListSize = list.size();
79  Treal* ptr = newAllocator->alloc();
80  pthread_mutex_unlock(&mutex);
81  return ptr;
82  }
83  void free(Treal* ptr) {
84  pthread_mutex_lock(&mutex);
85  // Go through list to see if this ptr belongs to any allocator.
86  typename std::list< Allocator<Treal>* >::iterator it = list.begin();
87  while(it != list.end()) {
88  if((*it)->ownsPtr(ptr)) {
89  (*it)->free(ptr);
90  // Now check if allocator is empty; in that case we want to remove it.
91  if((*it)->isEmpty()) {
92  delete *it;
93  list.erase(it);
94  }
95  pthread_mutex_unlock(&mutex);
96  return;
97  }
98  it++;
99  }
100  delete [] ptr;
101  pthread_mutex_unlock(&mutex);
102  }
103  std::string getStatistics() {
104  size_t noOfBytesPerAllocator = noOfBuffers * noOfRealsPerBuffer * sizeof(Treal);
105  size_t totNoOfBytesAllocated = list.size() * noOfBytesPerAllocator;
106  size_t peakNoOfBytesAllocated = peakListSize * noOfBytesPerAllocator;
107  size_t totNoOfBytesUsed = 0;
108  // Go through list to compute totNoOfBytesUsed
109  typename std::list< Allocator<Treal>* >::iterator it = list.begin();
110  while(it != list.end()) {
111  totNoOfBytesUsed += (size_t)((*it)->getNoOfOccupiedSlots()) * noOfRealsPerBuffer * sizeof(Treal);
112  it++;
113  }
114  std::stringstream ss;
115  ss << "AllocatorManager statistics: ";
116  ss << std::setprecision(3)
117  << " noOfRealsPerBuffer: " << noOfRealsPerBuffer
118  << " noOfBuffers: " << noOfBuffers
119  << " list.size(): " << list.size()
120  << ". "
121  << "Allocated: " << (double)totNoOfBytesAllocated / 1e9 << " GB, "
122  << "Used: " << (double)totNoOfBytesUsed / 1e9 << " GB, "
123  << "Peak alloc: " << (double)peakNoOfBytesAllocated/ 1e9 << " GB.";
124  return ss.str();
125  }
126  private:
128  pthread_mutex_init(&mutex, NULL);
129  }
131  if(!list.empty())
132  throw std::runtime_error("Error in AllocatorManager destructor: "
133  "not empty.");
134  // Go through list to free any allocators that are left.
135  typename std::list< Allocator<Treal>* >::iterator it = list.begin();
136  while(it != list.end()) {
137  delete *it;
138  it++;
139  }
140  }
141  std::list< Allocator<Treal>* > list;
143  size_t noOfBuffers;
144  pthread_mutex_t mutex;
145  size_t peakListSize;
146 }; // end class AllocatorManager
147 
148 } /* end namespace mat */
149 
150 #endif
void init(size_t noOfRealsPerBuffer_, size_t noOfBuffers_)
Definition: AllocatorManager.h:43
AllocatorManager()
Definition: AllocatorManager.h:127
std::string getStatistics()
Definition: AllocatorManager.h:103
Treal * alloc()
Definition: Allocator.h:57
Definition: AllocatorManager.h:40
static AllocatorManager & instance()
pthread_mutex_t mutex
Definition: AllocatorManager.h:144
Definition: allocate.cc:30
void free(Treal *ptr)
Definition: AllocatorManager.h:83
Definition: Allocator.h:35
std::list< Allocator< Treal > * > list
Definition: AllocatorManager.h:141
size_t noOfBuffers
Definition: AllocatorManager.h:143
~AllocatorManager()
Definition: AllocatorManager.h:130
size_t noOfRealsPerBuffer
Definition: AllocatorManager.h:142
Treal * alloc(size_t n)
Definition: AllocatorManager.h:58
size_t peakListSize
Definition: AllocatorManager.h:145