Arcane  v4.1.1.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
204 protected:
205
206 virtual void _applyHint([[maybe_unused]] void* ptr, [[maybe_unused]] size_t new_size,
207 [[maybe_unused]] MemoryAllocationArgs args) {}
208 virtual void _removeHint([[maybe_unused]] void* ptr, [[maybe_unused]] size_t new_size,
209 [[maybe_unused]] MemoryAllocationArgs args) {}
210
211 private:
212
213 impl::MemoryTracerWrapper m_tracer;
214 std::unique_ptr<IUnderlyingAllocator> m_direct_sub_allocator;
215 Arcane::impl::MemoryPool m_memory_pool;
216 IMemoryPoolAllocator* m_sub_allocator = nullptr;
217 bool m_use_memory_pool = false;
218 String m_allocator_name;
219 std::atomic<Int32> m_nb_reallocate = 0;
220 std::atomic<Int64> m_reallocate_size = 0;
221 Int32 m_print_level = 0;
222 BlockAllocatorWrapper m_block_wrapper;
223
224 protected:
225
227 void _doInitializeUVM(bool default_use_memory_pool = false);
229 void _doInitializeHostPinned(bool default_use_memory_pool = false);
231 void _doInitializeDevice(bool default_use_memory_pool = false);
232
233 protected:
234
235 void _setTraceLevel(Int32 v) { m_tracer.setTraceLevel(v); }
236
237 private:
238
239 // IMPORTANT: doit être appelé avant toute allocation et ne plus être modifié ensuite.
240 void _setUseMemoryPool(bool is_used);
241};
242
243/*---------------------------------------------------------------------------*/
244/*---------------------------------------------------------------------------*/
245
246} // namespace Arcane::Accelerator
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
250
251#endif
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.