Arcane  v4.1.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
AcceleratorMemoryAllocatorBase.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* AcceleratorMemoryAllocatorBase.h (C) 2000-2025 */
9/* */
10/* Classe de base d'un allocateur spécifique pour accélérateur. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_ACCELERATOR_CORE_INTERNAL_ACCELERATORMEMORYALLOCATORBASE_H
13#define ARCANE_ACCELERATOR_CORE_INTERNAL_ACCELERATORMEMORYALLOCATORBASE_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
18
19#include "arccore/base/String.h"
20#include "arccore/base/FatalErrorException.h"
21
22#include "arccore/common/AllocatedMemoryInfo.h"
23#include "arccore/common/AlignedMemoryAllocator.h"
24
25#include "arcane/utils/internal/MemoryPool.h"
26
27#include "arcane/accelerator/core/internal/MemoryTracer.h"
28
29#include <atomic>
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane::Accelerator
35{
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
50class ARCANE_ACCELERATOR_CORE_EXPORT BlockAllocatorWrapper
51{
52 public:
53
54 void initialize(Int64 block_size, bool do_block_alloc)
55 {
56 m_block_size = block_size;
57 if (m_block_size <= 0)
58 m_block_size = 128;
59 m_do_block_allocate = do_block_alloc;
60 }
61
62 void dumpStats(std::ostream& ostr, const String& name);
63
64 Int64 adjustedCapacity(Int64 wanted_capacity, Int64 element_size) const
65 {
66 const bool do_page = m_do_block_allocate;
67 if (!do_page)
68 return wanted_capacity;
69 // Alloue un multiple de la taille d'un bloc
70 // Pour la mémoire unifiée, la taille de bloc est une page mémoire.
71 // Comme les transfers de la mémoire unifiée se font par page,
72 // cela permet de détecter quelles allocations provoquent le transfert.
73 // On se débrouille aussi pour limiter les différentes taille
74 // de bloc alloué pour éviter d'avoir trop de blocs de taille
75 // différente pour que l'éventuel MemoryPool ne contienne trop
76 // de valeurs.
77 Int64 orig_capacity = wanted_capacity;
78 Int64 new_size = orig_capacity * element_size;
79 Int64 block_size = m_block_size;
80 Int64 nb_iter = 4 + (4096 / block_size);
81 for (Int64 i = 0; i < nb_iter; ++i) {
82 if (new_size >= (4 * block_size))
83 block_size *= 4;
84 else
85 break;
86 }
87 new_size = _computeNextMultiple(new_size, block_size);
88 wanted_capacity = new_size / element_size;
89 if (wanted_capacity < orig_capacity)
90 wanted_capacity = orig_capacity;
91 return wanted_capacity;
92 }
93
94 void notifyDoAllocate(void* ptr)
95 {
98 uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
99 if ((addr % m_block_size) != 0) {
101 }
102 }
103 }
104
105 private:
106
112 std::atomic<Int32> m_nb_allocate = 0;
114 std::atomic<Int32> m_nb_unaligned_allocate = 0;
115
116 private:
117
118 // Calcule la plus petite valeur de \a multiple de \a multiple
119 static Int64 _computeNextMultiple(Int64 n, Int64 multiple)
120 {
121 Int64 new_n = n / multiple;
122 if ((n % multiple) != 0)
123 ++new_n;
124 return (new_n * multiple);
125 }
126};
127
128/*---------------------------------------------------------------------------*/
129/*---------------------------------------------------------------------------*/
133class ARCANE_ACCELERATOR_CORE_EXPORT AcceleratorMemoryAllocatorBase
134: public AlignedMemoryAllocator
135{
136 public:
137
138 using IMemoryPoolAllocator = Arcane::impl::IMemoryPoolAllocator;
139 using BaseClass = AlignedMemoryAllocator;
140
141 public:
142
145 {
146 UVM = 1,
147 Device = 2,
148 HostPinned = 4
149 };
150
151 public:
152
154 : public IMemoryPoolAllocator
155 {
156 public:
157
158 virtual void doMemoryCopy(void* destination, const void* source, Int64 size) = 0;
159 virtual eMemoryResource memoryResource() const = 0;
160 };
161
162 public:
163
164 AcceleratorMemoryAllocatorBase(const String& allocator_name, IUnderlyingAllocator* underlying_allocator);
165
166 public:
167
168 void finalize(ITraceMng* tm);
169
170 public:
171
172 bool hasRealloc(MemoryAllocationArgs) const final { return true; }
174 {
175 void* out = m_sub_allocator->allocateMemory(new_size);
176 m_block_wrapper.notifyDoAllocate(out);
177 Int64 a = reinterpret_cast<Int64>(out);
178 if ((a % 128) != 0)
179 ARCANE_FATAL("Bad alignment for Accelerator allocator: offset={0}", (a % 128));
180 m_tracer.traceAllocate(out, new_size, args);
181 _applyHint(out, new_size, args);
182 return { out, new_size };
183 }
184 AllocatedMemoryInfo reallocate(MemoryAllocationArgs args, AllocatedMemoryInfo current_info, Int64 new_size) final;
186 {
187 void* ptr = mem_info.baseAddress();
188 size_t mem_size = mem_info.capacity();
189 if (m_use_memory_pool)
190 _removeHint(ptr, mem_size, args);
191 // Ne lève pas d'exception en cas d'erreurs lors de la désallocation
192 // car elles ont souvent lieu dans les destructeurs et cela provoque
193 // un arrêt du code par std::terminate().
194 m_tracer.traceDeallocate(mem_info, args);
195 m_sub_allocator->freeMemory(ptr, mem_size);
196 }
197
198 Int64 adjustedCapacity(MemoryAllocationArgs args, Int64 wanted_capacity, Int64 element_size) const final
199 {
200 wanted_capacity = AlignedMemoryAllocator3::adjustedCapacity(args, wanted_capacity, element_size);
201 return m_block_wrapper.adjustedCapacity(wanted_capacity, element_size);
202 }
203 eMemoryResource memoryResource() const final { return m_direct_sub_allocator->memoryResource(); }
204
205 protected:
206
207 virtual void _applyHint([[maybe_unused]] void* ptr, [[maybe_unused]] size_t new_size,
208 [[maybe_unused]] MemoryAllocationArgs args) {}
209 virtual void _removeHint([[maybe_unused]] void* ptr, [[maybe_unused]] size_t new_size,
210 [[maybe_unused]] MemoryAllocationArgs args) {}
211
212 private:
213
214 impl::MemoryTracerWrapper m_tracer;
215 std::unique_ptr<IUnderlyingAllocator> m_direct_sub_allocator;
216 Arcane::impl::MemoryPool m_memory_pool;
217 IMemoryPoolAllocator* m_sub_allocator = nullptr;
218 bool m_use_memory_pool = false;
219 String m_allocator_name;
220 std::atomic<Int32> m_nb_reallocate = 0;
221 std::atomic<Int64> m_reallocate_size = 0;
222 Int32 m_print_level = 0;
223 BlockAllocatorWrapper m_block_wrapper;
224
225 protected:
226
228 void _doInitializeUVM();
230 void _doInitializeHostPinned();
232 void _doInitializeDevice();
233
234 protected:
235
236 void _setTraceLevel(Int32 v) { m_tracer.setTraceLevel(v); }
237
238 private:
239
240 // IMPORTANT: doit être appelé avant toute allocation et ne plus être modifié ensuite.
241 void _setUseMemoryPool(bool is_used);
242};
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
246
247} // namespace Arcane::Accelerator
248
249/*---------------------------------------------------------------------------*/
250/*---------------------------------------------------------------------------*/
251
252#endif
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
MemoryPoolFlags
Liste des flags pour le pool mémoire à activer.
eMemoryResource memoryResource() const final
Ressource mémoire fournie par l'allocateur.
bool hasRealloc(MemoryAllocationArgs) const final
Indique si l'allocateur supporte la sémantique de realloc.
AllocatedMemoryInfo allocate(MemoryAllocationArgs args, Int64 new_size) final
Alloue de la mémoire pour new_size octets et retourne le pointeur.
void deallocate(MemoryAllocationArgs args, AllocatedMemoryInfo mem_info) final
Libère la mémoire dont l'adresse de base est ptr.
Int64 adjustedCapacity(MemoryAllocationArgs args, Int64 wanted_capacity, Int64 element_size) const final
Ajuste la capacité suivant la taille d'élément.
Classe commune pour gérer l'allocation par bloc.
std::atomic< Int32 > m_nb_allocate
Nombre d'allocations.
Int64 m_block_size
Taille d'un bloc. L'allocation sera un multiple de cette taille.
bool m_do_block_allocate
Indique si l'allocation en utilisant m_block_size.
std::atomic< Int32 > m_nb_unaligned_allocate
Nombre d'allocations non alignées.
Int64 adjustedCapacity(MemoryAllocationArgs args, Int64 wanted_capacity, Int64 element_size) const override
Ajuste la capacité suivant la taille d'élément.
Informations sur une zone mémoire allouée.
Interface du gestionnaire de traces.
Classe contenant des informations pour spécialiser les allocations.
Chaîne de caractères unicode.
Interface d'un allocateur pour un MemoryPool.
Definition MemoryPool.h:39
Classe pour gérer une liste de zone allouées.
Definition MemoryPool.h:65
Espace de nom pour l'utilisation des accélérateurs.
std::int64_t Int64
Type entier signé sur 64 bits.
eMemoryResource
Liste des ressources mémoire disponibles.