Arcane  v4.1.2.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 ARCCORE_COMMON_ACCELERATOR_INTERNAL_ACCELERATORMEMORYALLOCATORBASE_H
13#define ARCCORE_COMMON_ACCELERATOR_INTERNAL_ACCELERATORMEMORYALLOCATORBASE_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arccore/common/accelerator/CommonAcceleratorGlobal.h"
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#include "arccore/common/internal/MemoryPool.h"
25
26#include "arccore/common/accelerator/internal/MemoryTracer.h"
27
28#include <atomic>
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33namespace Arcane::Accelerator
34{
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
49class ARCCORE_COMMON_EXPORT BlockAllocatorWrapper
50{
51 public:
52
53 void initialize(Int64 block_size, bool do_block_alloc)
54 {
55 m_block_size = block_size;
56 if (m_block_size <= 0)
57 m_block_size = 128;
58 m_do_block_allocate = do_block_alloc;
59 }
60
61 void dumpStats(std::ostream& ostr, const String& name);
62
63 Int64 adjustedCapacity(Int64 wanted_capacity, Int64 element_size) const
64 {
65 const bool do_page = m_do_block_allocate;
66 if (!do_page)
67 return wanted_capacity;
68 // Alloue un multiple de la taille d'un bloc
69 // Pour la mémoire unifiée, la taille de bloc est une page mémoire.
70 // Comme les transfers de la mémoire unifiée se font par page,
71 // cela permet de détecter quelles allocations provoquent le transfert.
72 // On se débrouille aussi pour limiter les différentes taille
73 // de bloc alloué pour éviter d'avoir trop de blocs de taille
74 // différente pour que l'éventuel MemoryPool ne contienne trop
75 // de valeurs.
76 Int64 orig_capacity = wanted_capacity;
77 Int64 new_size = orig_capacity * element_size;
78 Int64 block_size = m_block_size;
79 Int64 nb_iter = 4 + (4096 / block_size);
80 for (Int64 i = 0; i < nb_iter; ++i) {
81 if (new_size >= (4 * block_size))
82 block_size *= 4;
83 else
84 break;
85 }
86 new_size = _computeNextMultiple(new_size, block_size);
87 wanted_capacity = new_size / element_size;
88 if (wanted_capacity < orig_capacity)
89 wanted_capacity = orig_capacity;
90 return wanted_capacity;
91 }
92
93 void notifyDoAllocate(void* ptr)
94 {
97 uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
98 if ((addr % m_block_size) != 0) {
100 }
101 }
102 }
103
104 private:
105
111 std::atomic<Int32> m_nb_allocate = 0;
113 std::atomic<Int32> m_nb_unaligned_allocate = 0;
114
115 private:
116
117 // Calcule la plus petite valeur de \a multiple de \a multiple
118 static Int64 _computeNextMultiple(Int64 n, Int64 multiple)
119 {
120 Int64 new_n = n / multiple;
121 if ((n % multiple) != 0)
122 ++new_n;
123 return (new_n * multiple);
124 }
125};
126
127/*---------------------------------------------------------------------------*/
128/*---------------------------------------------------------------------------*/
132class ARCCORE_COMMON_EXPORT AcceleratorMemoryAllocatorBase
133: public AlignedMemoryAllocator
134{
135 public:
136
137 using IMemoryPoolAllocator = Arcane::Impl::IMemoryPoolAllocator;
138 using BaseClass = AlignedMemoryAllocator;
139
140 public:
141
144 {
145 UVM = 1,
146 Device = 2,
147 HostPinned = 4
148 };
149
150 public:
151
153 : public IMemoryPoolAllocator
154 {
155 public:
156
157 virtual void doMemoryCopy(void* destination, const void* source, Int64 size) = 0;
158 virtual eMemoryResource memoryResource() const = 0;
159 };
160
161 public:
162
163 AcceleratorMemoryAllocatorBase(const String& allocator_name, IUnderlyingAllocator* underlying_allocator);
164
165 public:
166
167 void finalize(ITraceMng* tm);
168
169 public:
170
171 bool hasRealloc(MemoryAllocationArgs) const final { return true; }
173 {
174 void* out = m_sub_allocator->allocateMemory(new_size);
175 m_block_wrapper.notifyDoAllocate(out);
176 Int64 a = reinterpret_cast<Int64>(out);
177 if ((a % 128) != 0)
178 ARCCORE_FATAL("Bad alignment for Accelerator allocator: offset={0}", (a % 128));
179 m_tracer.traceAllocate(out, new_size, args);
180 _applyHint(out, new_size, args);
181 return { out, new_size };
182 }
183 AllocatedMemoryInfo reallocate(MemoryAllocationArgs args, AllocatedMemoryInfo current_info, Int64 new_size) final;
185 {
186 void* ptr = mem_info.baseAddress();
187 size_t mem_size = mem_info.capacity();
188 if (m_use_memory_pool)
189 _removeHint(ptr, mem_size, args);
190 // Ne lève pas d'exception en cas d'erreurs lors de la désallocation
191 // car elles ont souvent lieu dans les destructeurs et cela provoque
192 // un arrêt du code par std::terminate().
193 m_tracer.traceDeallocate(mem_info, args);
194 m_sub_allocator->freeMemory(ptr, mem_size);
195 }
196
197 Int64 adjustedCapacity(MemoryAllocationArgs args, Int64 wanted_capacity, Int64 element_size) const final
198 {
199 wanted_capacity = AlignedMemoryAllocator::adjustedCapacity(args, wanted_capacity, element_size);
200 return m_block_wrapper.adjustedCapacity(wanted_capacity, element_size);
201 }
202 eMemoryResource memoryResource() const final { return m_direct_sub_allocator->memoryResource(); }
203 IMemoryPool* memoryPool() { return &m_memory_pool; }
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(bool default_use_memory_pool = false);
230 void _doInitializeHostPinned(bool default_use_memory_pool = false);
232 void _doInitializeDevice(bool default_use_memory_pool = false);
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 ARCCORE_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 d'un pool mémoire.
Definition IMemoryPool.h:31
Interface du gestionnaire de traces.
Interface d'un allocateur pour un MemoryPool.
Definition MemoryPool.h:39
Classe contenant des informations pour spécialiser les allocations.
Chaîne de caractères unicode.
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.