1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2007 - 2019 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_vector_memory_templates_h
17 #define dealii_vector_memory_templates_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/memory_consumption.h>
23 
24 #include <deal.II/lac/vector_memory.h>
25 
26 #include <memory>
27 
28 DEAL_II_NAMESPACE_OPEN
29 
30 
31 template <typename VectorType>
32 typename GrowingVectorMemory<VectorType>::Pool &
get_pool()33 GrowingVectorMemory<VectorType>::get_pool()
34 {
35   static GrowingVectorMemory<VectorType>::Pool pool;
36   return pool;
37 }
38 
39 
40 
41 template <typename VectorType>
42 Threads::Mutex GrowingVectorMemory<VectorType>::mutex;
43 
44 
45 
46 template <typename VectorType>
Pool()47 inline GrowingVectorMemory<VectorType>::Pool::Pool()
48   : data(nullptr)
49 {}
50 
51 
52 
53 template <typename VectorType>
~Pool()54 inline GrowingVectorMemory<VectorType>::Pool::~Pool()
55 {
56   // Nothing to do if memory was unused.
57   if (data == nullptr)
58     return;
59 
60   // delete the 'data' object. this also releases all vectors
61   // that are pointed to by the std::unique_ptrs
62   data->clear();
63   delete data;
64 }
65 
66 
67 template <typename VectorType>
68 inline void
initialize(const size_type size)69 GrowingVectorMemory<VectorType>::Pool::initialize(const size_type size)
70 {
71   if (data == nullptr)
72     {
73       data = new std::vector<entry_type>(size);
74 
75       for (typename std::vector<entry_type>::iterator i = data->begin();
76            i != data->end();
77            ++i)
78         {
79           i->first  = false;
80           i->second = std::make_unique<VectorType>();
81         }
82     }
83 }
84 
85 
86 template <typename VectorType>
GrowingVectorMemory(const size_type initial_size,const bool log_statistics)87 inline GrowingVectorMemory<VectorType>::GrowingVectorMemory(
88   const size_type initial_size,
89   const bool      log_statistics)
90 
91   : total_alloc(0)
92   , current_alloc(0)
93   , log_statistics(log_statistics)
94 {
95   std::lock_guard<std::mutex> lock(mutex);
96   get_pool().initialize(initial_size);
97 }
98 
99 
100 template <typename VectorType>
~GrowingVectorMemory()101 inline GrowingVectorMemory<VectorType>::~GrowingVectorMemory()
102 {
103   AssertNothrow(current_alloc == 0,
104                 StandardExceptions::ExcMemoryLeak(current_alloc));
105   if (log_statistics)
106     {
107       deallog << "GrowingVectorMemory:Overall allocated vectors: "
108               << total_alloc << std::endl;
109       deallog << "GrowingVectorMemory:Maximum allocated vectors: "
110               << get_pool().data->size() << std::endl;
111     }
112 }
113 
114 
115 
116 template <typename VectorType>
117 inline VectorType *
alloc()118 GrowingVectorMemory<VectorType>::alloc()
119 {
120   std::lock_guard<std::mutex> lock(mutex);
121 
122   ++total_alloc;
123   ++current_alloc;
124   // see if there is a free vector
125   // available in our list
126   for (typename std::vector<entry_type>::iterator i = get_pool().data->begin();
127        i != get_pool().data->end();
128        ++i)
129     {
130       if (i->first == false)
131         {
132           i->first = true;
133           return i->second.get();
134         }
135     }
136 
137   // no free vector found, so let's just allocate a new one
138   get_pool().data->emplace_back(true, std::make_unique<VectorType>());
139 
140   return get_pool().data->back().second.get();
141 }
142 
143 
144 
145 template <typename VectorType>
146 inline void
free(const VectorType * const v)147 GrowingVectorMemory<VectorType>::free(const VectorType *const v)
148 {
149   std::lock_guard<std::mutex> lock(mutex);
150 
151   for (typename std::vector<entry_type>::iterator i = get_pool().data->begin();
152        i != get_pool().data->end();
153        ++i)
154     {
155       if (v == i->second.get())
156         {
157           i->first = false;
158           --current_alloc;
159           return;
160         }
161     }
162   Assert(false, typename VectorMemory<VectorType>::ExcNotAllocatedHere());
163 }
164 
165 
166 
167 template <typename VectorType>
168 inline void
release_unused_memory()169 GrowingVectorMemory<VectorType>::release_unused_memory()
170 {
171   std::lock_guard<std::mutex> lock(mutex);
172 
173   if (get_pool().data != nullptr)
174     get_pool().data->clear();
175 }
176 
177 
178 
179 template <typename VectorType>
180 inline std::size_t
memory_consumption()181 GrowingVectorMemory<VectorType>::memory_consumption() const
182 {
183   std::lock_guard<std::mutex> lock(mutex);
184 
185   std::size_t                                            result = sizeof(*this);
186   const typename std::vector<entry_type>::const_iterator end =
187     get_pool().data->end();
188   for (typename std::vector<entry_type>::const_iterator i =
189          get_pool().data->begin();
190        i != end;
191        ++i)
192     result += sizeof(*i) + MemoryConsumption::memory_consumption(i->second);
193 
194   return result;
195 }
196 
197 
198 DEAL_II_NAMESPACE_CLOSE
199 
200 #endif
201