TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
TRUSTTravPool.cpp
1/****************************************************************************
2* Copyright (c) 2025, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <TRUSTTravPool.h>
17#include <TRUSTArray.h>
18#include <unordered_map>
19#include <list>
20#include <iostream>
21#include <cassert>
22#include <Process.h>
23#include <EntreeSortie.h>
24#include <Device.h>
25#include <DeviceMemory.h>
26
27/*! The shared pools of memory - visibility: here only.
28 *
29 * Implementation is done as a map of lists. Key is the array size, and the list simply contains pointers to
30 * available free blocks. So a block is only registered in the list when it is released.
31 *
32 */
33template<typename _TYPE_>
35{
36 using ptr_t = std::shared_ptr<typename TRUSTArray<_TYPE_,int>::Vector_>;
37 using list_t = std::list<ptr_t>;
38 using pool_t = std::unordered_map<size_t, list_t>;
39
40 /*! A pool is a map of lists:
41 * - key is the size of the block,
42 * - value is a list giving all free blocks (the last one is picked when requesting a free block)
43 */
45
46#ifndef NDEBUG
47 //! Total allocation requests:
48 static size_t req_sz_;
49 //! Actual alloc performed:
50 static size_t actual_sz_;
51 //! Total number of blocks in the pool:
52 static int num_items_;
53#endif
54};
55
56//
57// Instanciations of the static pools themselves (protect your eyes, it hurts :-) )
58//
62#if INT_is_64_ == 2
64#endif
65
66#ifndef NDEBUG
67// Need C++17 to have this inline in the class def directly ...
68template<> size_t PoolImpl_<int>::req_sz_ = 0;
69template<> size_t PoolImpl_<float>::req_sz_ = 0;
70template<> size_t PoolImpl_<double>::req_sz_ = 0;
71
72template<> size_t PoolImpl_<int>::actual_sz_ = 0;
73template<> size_t PoolImpl_<float>::actual_sz_ = 0;
74template<> size_t PoolImpl_<double>::actual_sz_ = 0;
75
76template<> int PoolImpl_<int>::num_items_ = 0;
77template<> int PoolImpl_<float>::num_items_ = 0;
78template<> int PoolImpl_<double>::num_items_ = 0;
79
80#if INT_is_64_ == 2
81template<> size_t PoolImpl_<trustIdType>::req_sz_ = 0;
82template<> size_t PoolImpl_<trustIdType>::actual_sz_ = 0;
83template<> int PoolImpl_<trustIdType>::num_items_ = 0;
84#endif
85
86#endif
87
88/*! Handy method to get the proper list corresponding to a given size.
89 * The list is created if this is the first time the corresponding key (=size) is encountered
90 */
91template<typename _TYPE_>
92typename PoolImpl_<_TYPE_>::list_t& GetOrCreateList(size_t sz)
93{
94 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
95 auto& ze_pool = PoolImpl_<_TYPE_>::Free_blocks_;
96
97 auto it = ze_pool.find(sz);
98 if (it == ze_pool.end())
99 {
100 auto pr = ze_pool.emplace(sz, lst_t());
101 // emplace returns a pair { iterator, bool } - the iterator itself is a pair (since this is a map) whose 'second' is the value.
102 return pr.first->second;
103 }
104 else
105 return it->second;
106}
107
108
109/*! Retrieve a free block of size sz.
110 *
111 * This takes the last available block from the list of the corresponding size, or returns a newly allocated block if none is available in the
112 * block.
113 */
114template<typename _TYPE_>
116{
117 using vec_t = typename TRUSTArray<_TYPE_,int>::Vector_;
118 using ptr_t = typename PoolImpl_<_TYPE_>::ptr_t;
119 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
120
121#ifndef NDEBUG
123#endif
124
125 lst_t& lst = GetOrCreateList<_TYPE_>(sz);
126 // Is there an available block?
127 if (lst.size())
128 {
129 // Yes - pop it from the list and returns it:
130 ptr_t ret = lst.back();
131 lst.pop_back();
132#ifndef NDEBUG
134#endif
135 return ret;
136 }
137 else // No, must create a new one - it will be registered in the pool when released in ~TRUSTArray()
138 {
139#ifndef NDEBUG
141#endif
142 return std::make_shared<vec_t>(vec_t(sz));
143 }
144}
145
146/*! "Resize" a temporary Trav block - two possible strategies:
147 * Strategy 1
148 * - get a new free block of the new size
149 * - copy the former data into it
150 * - release the former small block (and so make it available for future potential use by another Trav)
151 * - danger: can lead to clottering of the pool if many incremental resize() are done (typically append_line() in a for loop...)
152 * -> mitigation: when the number of elements in the pool becomes too large, raise a warning
153 * Strategy 2
154 * - simply resize the underlying vector, hence completely forgetting the previous block which is never registered in the pool.
155 * - danger: can also lead to clottering of the pool if doing
156 * { DoubleTrav a(1);
157 * a.resize(10);
158 * }
159 * many times -> the array of size 10 is registered at each destruction (because it was always arrays of size 1 that were
160 * requested ...) -> same mitigation as above.
161 *
162 */
163template<typename _TYPE_>
165{
166 assert(p != nullptr);
167 assert(p->size() > 0);
168 assert(new_sz > 0); // new_sz == 0 should never happen, see TRUSTArray::resize_array_()
169
170 bool first_strategy = true;
171 // Second strategy may increase memory with a growing pool if DoubleTrav resized several times
172 // in a loop as in Op_Grad_PolyMAC_MPFA_Face::ajouter_blocs
173 if (first_strategy)
174 {
175 // Strategy 1
176 // Get new bigger block
178 // Copy data
179 std::copy(p->begin(), p->end(), new_blk->begin());
180 // Release small block
182 return new_blk;
183 }
184 else
185 {
186 // Strategy 2
187 // Resize ... and that's it!
188 p->resize(new_sz);
189 return p;
190 }
191}
192
193/*! Release a block.
194 *
195 * This is invoked from the dtor of TRUSTArray and makes the memory block available again by registering it in the pool of
196 * free blocks.
197 * We don't register blocks of size 0.
198 */
199template<typename _TYPE_>
201{
202 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
203
204 assert(p != nullptr);
205 size_t sz = p->size();
206
207 if (sz)
208 {
209 lst_t& lst = GetOrCreateList<_TYPE_>(sz);
210 // Append the free block pointer to the list corresponding to its size:
211 lst.push_back(p);
212#ifndef NDEBUG
214 // If the pool becomes too big this probably means we have a pattern like this
215 //
216 // DoubleTrav b(1)
217 // for(i=0; i < a_lot; i++)
218 // b.append_array(x);
219 //
220 // where the Trav is resized over and over, and each of its intermediate size is stored in the Pool.
221 // Trav size should be fixed once and moved too much, or one should use a Tab if outside time steps.
222// if (PoolImpl_<_TYPE_>::num_items_ > 500)
223// {
224// Cerr << "Too many blocks in the TravPool!! This probably means that a Trav is badly used!! Fix this." << finl;
225// Process::exit();
226// }
227#endif
228 }
229}
230
231/*!
232 * Empty the TRUSTTrav pool explicitely.
233 */
234template<typename _TYPE_>
236{
237 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
238
239 auto& ze_pool = PoolImpl_<_TYPE_>::Free_blocks_;
240
241 // Delete GPU allocated memory:
242 for(const auto & kv: ze_pool)
243 {
244 size_t size = kv.first;
245 const lst_t& lst = kv.second;
246 for (auto& mem : lst)
247 {
248 _TYPE_* ptr = mem->data();
249 if(isAllocatedOnDevice(ptr))
250 deleteOnDevice(ptr, (int)size); // Delete the block memory on the device
251 }
252 }
253 // Clear the whole pool (shared_ptr will do the cleaning job):
254 ze_pool.clear();
255}
256
257/*!
258 * Debug method printing useful stats.
259 */
260template<typename _TYPE_>
262{
263#ifdef NDEBUG
264 Cerr << "TRUSTTravPool stats are only available in debug mode for performance reasons!!" << finl;
265 Process::exit(-1);
266#else
267 using pi = PoolImpl_<_TYPE_>;
268
269 Cerr << "Total requested (MB): " << (double)pi::req_sz_ / (1024.0 * 1024.0) << finl;
270 Cerr << "Total allocated (MB): " << (double)pi::actual_sz_ / (1024.0 * 1024.0) << finl;
271 Cerr << "Number of blocks in the pool: " << pi::num_items_ << finl;
272 // std::cout << "-- Top five blocks:" << std::endl;
273// std::cout << " Size" << std::setw(40) << "Nb instances" << std::finl;
274// int cnt = 0;
275// for (auto& )
276// {
277// if(++cnt >= 5) break;
278//
279// }
280#endif
281}
282
283
284//
285// Explicit instanciations of templates
286//
287template class TRUSTTravPool<double>;
288template class TRUSTTravPool<int>;
289template class TRUSTTravPool<float>;
290
291#if INT_is_64_ == 2
292template class TRUSTTravPool<trustIdType>;
293#endif
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
std::vector< _TYPE_, TVAlloc< _TYPE_ > > Vector_
Definition TRUSTArray.h:101
static void ClearPool()
static block_ptr_t GetFreeBlock(int sz)
static void ReleaseBlock(block_ptr_t)
static void PrintStats()
static block_ptr_t ResizeBlock(block_ptr_t p, int new_sz)
std::shared_ptr< std::vector< _TYPE_, TVAlloc< _TYPE_ > > > block_ptr_t
std::shared_ptr< typename TRUSTArray< _TYPE_, int >::Vector_ > ptr_t
std::unordered_map< size_t, list_t > pool_t
static size_t actual_sz_
Actual alloc performed:
static int num_items_
Total number of blocks in the pool:
static size_t req_sz_
Total allocation requests:
std::list< ptr_t > list_t
static pool_t Free_blocks_