TrioCFD 1.9.9_beta
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/*! @brief 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 /*! @brief 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/*! @brief 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 * @param sz the requested block size
91 * @return reference to the list of free blocks for that size
92 */
93template<typename _TYPE_>
94typename PoolImpl_<_TYPE_>::list_t& GetOrCreateList(size_t sz)
95{
96 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
97 auto& ze_pool = PoolImpl_<_TYPE_>::Free_blocks_;
98
99 auto it = ze_pool.find(sz);
100 if (it == ze_pool.end())
101 {
102 auto pr = ze_pool.emplace(sz, lst_t());
103 // emplace returns a pair { iterator, bool } - the iterator itself is a pair (since this is a map) whose 'second' is the value.
104 return pr.first->second;
105 }
106 else
107 return it->second;
108}
109
110
111/*! @brief Retrieve a free block of size sz.
112 *
113 * 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
114 * block.
115 * @param sz the number of elements in the requested block
116 * @return a shared pointer to a free memory block of the requested size
117 */
118template<typename _TYPE_>
120{
121 using vec_t = typename TRUSTArray<_TYPE_,int>::Vector_;
122 using ptr_t = typename PoolImpl_<_TYPE_>::ptr_t;
123 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
124
125#ifndef NDEBUG
127#endif
128
129 lst_t& lst = GetOrCreateList<_TYPE_>(sz);
130 // Is there an available block?
131 if (lst.size())
132 {
133 // Yes - pop it from the list and returns it:
134 ptr_t ret = lst.back();
135 lst.pop_back();
136#ifndef NDEBUG
138#endif
139 return ret;
140 }
141 else // No, must create a new one - it will be registered in the pool when released in ~TRUSTArray()
142 {
143#ifndef NDEBUG
145#endif
146 return std::make_shared<vec_t>(vec_t(sz));
147 }
148}
149
150/*! @brief "Resize" a temporary Trav block - two possible strategies:
151 * Strategy 1
152 * - get a new free block of the new size
153 * - copy the former data into it
154 * - release the former small block (and so make it available for future potential use by another Trav)
155 * - danger: can lead to clottering of the pool if many incremental resize() are done (typically append_line() in a for loop...)
156 * -> mitigation: when the number of elements in the pool becomes too large, raise a warning
157 * Strategy 2
158 * - simply resize the underlying vector, hence completely forgetting the previous block which is never registered in the pool.
159 * - danger: can also lead to clottering of the pool if doing
160 * { DoubleTrav a(1);
161 * a.resize(10);
162 * }
163 * many times -> the array of size 10 is registered at each destruction (because it was always arrays of size 1 that were
164 * requested ...) -> same mitigation as above.
165 * @param p shared pointer to the current block to resize
166 * @param new_sz the new number of elements
167 * @return a shared pointer to a block of the new size containing a copy of the original data
168 */
169template<typename _TYPE_>
171{
172 assert(p != nullptr);
173 assert(p->size() > 0);
174 assert(new_sz > 0); // new_sz == 0 should never happen, see TRUSTArray::resize_array_()
175
176 bool first_strategy = true;
177 // Second strategy may increase memory with a growing pool if DoubleTrav resized several times
178 // in a loop as in Op_Grad_PolyMAC_MPFA_Face::ajouter_blocs
179 if (first_strategy)
180 {
181 // Strategy 1
182 // Get new bigger block
184 // Copy data
185 std::copy(p->begin(), p->end(), new_blk->begin());
186 // Release small block
188 return new_blk;
189 }
190 else
191 {
192 // Strategy 2
193 // Resize ... and that's it!
194 p->resize(new_sz);
195 return p;
196 }
197}
198
199/*! @brief Release a block.
200 *
201 * This is invoked from the dtor of TRUSTArray and makes the memory block available again by registering it in the pool of
202 * free blocks.
203 * We don't register blocks of size 0.
204 * @param p the shared pointer to the block to release back to the pool
205 */
206template<typename _TYPE_>
208{
209 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
210
211 assert(p != nullptr);
212 size_t sz = p->size();
213
214 if (sz)
215 {
216 lst_t& lst = GetOrCreateList<_TYPE_>(sz);
217 // Append the free block pointer to the list corresponding to its size:
218 lst.push_back(p);
219#ifndef NDEBUG
221 // If the pool becomes too big this probably means we have a pattern like this
222 //
223 // DoubleTrav b(1)
224 // for(i=0; i < a_lot; i++)
225 // b.append_array(x);
226 //
227 // where the Trav is resized over and over, and each of its intermediate size is stored in the Pool.
228 // Trav size should be fixed once and moved too much, or one should use a Tab if outside time steps.
229// if (PoolImpl_<_TYPE_>::num_items_ > 500)
230// {
231// Cerr << "Too many blocks in the TravPool!! This probably means that a Trav is badly used!! Fix this." << finl;
232// Process::exit();
233// }
234#endif
235 }
236}
237
238/*!
239 * @brief Empty the TRUSTTrav pool explicitely.
240 */
241template<typename _TYPE_>
243{
244 using lst_t = typename PoolImpl_<_TYPE_>::list_t;
245
246 auto& ze_pool = PoolImpl_<_TYPE_>::Free_blocks_;
247
248 // Delete GPU allocated memory:
249 for(const auto & kv: ze_pool)
250 {
251 size_t size = kv.first;
252 const lst_t& lst = kv.second;
253 for (auto& mem : lst)
254 {
255 _TYPE_* ptr = mem->data();
256 if(isAllocatedOnDevice(ptr))
257 deleteOnDevice(ptr, (int)size); // Delete the block memory on the device
258 }
259 }
260 // Clear the whole pool (shared_ptr will do the cleaning job):
261 ze_pool.clear();
262}
263
264/*!
265 * @brief Debug method printing useful stats.
266 */
267template<typename _TYPE_>
269{
270#ifdef NDEBUG
271 Cerr << "TRUSTTravPool stats are only available in debug mode for performance reasons!!" << finl;
272 Process::exit(-1);
273#else
274 using pi = PoolImpl_<_TYPE_>;
275
276 Cerr << "Total requested (MB): " << (double)pi::req_sz_ / (1024.0 * 1024.0) << finl;
277 Cerr << "Total allocated (MB): " << (double)pi::actual_sz_ / (1024.0 * 1024.0) << finl;
278 Cerr << "Number of blocks in the pool: " << pi::num_items_ << finl;
279 // std::cout << "-- Top five blocks:" << std::endl;
280// std::cout << " Size" << std::setw(40) << "Nb instances" << std::finl;
281// int cnt = 0;
282// for (auto& )
283// {
284// if(++cnt >= 5) break;
285//
286// }
287#endif
288}
289
290
291//
292// Explicit instanciations of templates
293//
294template class TRUSTTravPool<double>;
295template class TRUSTTravPool<int>;
296template class TRUSTTravPool<float>;
297
298#if INT_is_64_ == 2
299template class TRUSTTravPool<trustIdType>;
300#endif
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
std::vector< _TYPE_, TVAlloc< _TYPE_ > > Vector_
Definition TRUSTArray.h:101
Pool of memory blocks used when requesting temporary storage (Trav arrays).
static void ClearPool()
Empty the TRUSTTrav pool explicitely.
static block_ptr_t GetFreeBlock(int sz)
Retrieve a free block of size sz.
static void ReleaseBlock(block_ptr_t)
Release a block.
static void PrintStats()
Debug method printing useful stats.
static block_ptr_t ResizeBlock(block_ptr_t p, int new_sz)
"Resize" a temporary Trav block - two possible strategies: Strategy 1
std::shared_ptr< std::vector< _TYPE_, TVAlloc< _TYPE_ > > > block_ptr_t
The shared pools of memory - visibility: here only.
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_
A pool is a map of lists: