Arcane  v3.15.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MemoryCopier.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 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/* MemoryCopier.cc (C) 2000-2024 */
9/* */
10/* Fonctions diverses de copie mémoire. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/accelerator/AcceleratorGlobal.h"
15
16#include "arcane/utils/Ref.h"
17#include "arcane/utils/FixedArray.h"
18#include "arcane/utils/NotSupportedException.h"
19#include "arcane/utils/internal/SpecificMemoryCopyList.h"
20
21#include "arcane/accelerator/core/RunQueue.h"
23
24/*---------------------------------------------------------------------------*/
25/*---------------------------------------------------------------------------*/
26
27namespace Arcane::Accelerator::impl
28{
29using IndexedMemoryCopyArgs = Arcane::impl::IndexedMemoryCopyArgs;
30using IndexedMultiMemoryCopyArgs = Arcane::impl::IndexedMultiMemoryCopyArgs;
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35template <typename DataType, typename Extent>
37: public Arcane::impl::SpecificMemoryCopyBase<DataType, Extent>
38{
40 using BaseClass::_toTrueType;
41
42 public:
43
44 using BaseClass::m_extent;
45
46 public:
47
48 void copyFrom(const IndexedMemoryCopyArgs& args) override
49 {
50 _copyFrom(args.m_queue, args.m_indexes, _toTrueType(args.m_source), _toTrueType(args.m_destination));
51 }
52
53 void copyTo(const IndexedMemoryCopyArgs& args) override
54 {
55 _copyTo(args.m_queue, args.m_indexes, _toTrueType(args.m_source), _toTrueType(args.m_destination));
56 }
57
58 void fill(const IndexedMemoryCopyArgs& args) override
59 {
60 _fill(args.m_queue, args.m_indexes, _toTrueType(args.m_source), _toTrueType(args.m_destination));
61 }
62
63 void copyFrom(const IndexedMultiMemoryCopyArgs& args) override
64 {
65 _copyFrom(args.m_queue, args.m_indexes, args.m_multi_memory, _toTrueType(args.m_source_buffer));
66 }
67
68 void copyTo(const IndexedMultiMemoryCopyArgs& args) override
69 {
70 _copyTo(args.m_queue, args.m_indexes, args.m_const_multi_memory, _toTrueType(args.m_destination_buffer));
71 }
72
73 void fill(const IndexedMultiMemoryCopyArgs& args) override
74 {
75 _fill(args.m_queue, args.m_indexes, args.m_multi_memory, _toTrueType(args.m_source_buffer));
76 }
77
78 public:
79
80 void _copyFrom(const RunQueue* queue, SmallSpan<const Int32> indexes,
81 Span<const DataType> source, Span<DataType> destination)
82 {
84
85 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, indexes.data());
86 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, source.data());
87 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, destination.data());
88
89 Int32 nb_index = indexes.size();
90 const Int64 sub_size = m_extent.v;
91
92 auto command = makeCommand(queue);
93 command << RUNCOMMAND_LOOP1(iter, nb_index)
94 {
95 auto [i] = iter();
96 Int64 zindex = i * sub_size;
97 Int64 zci = indexes[i] * sub_size;
98 for (Int32 z = 0; z < sub_size; ++z)
99 destination[zindex + z] = source[zci + z];
100 };
101 }
102
103 void _copyFrom(const RunQueue* queue, SmallSpan<const Int32> indexes, SmallSpan<Span<std::byte>> multi_views,
105 {
107
108 if (arcaneIsCheck()) {
109 ARCANE_CHECK_ACCESSIBLE_POINTER_ALWAYS(queue, indexes.data());
110 ARCANE_CHECK_ACCESSIBLE_POINTER_ALWAYS(queue, source.data());
112 // Idéalement il faudrait tester les valeurs des éléments de multi_views
113 // mais si on fait cela on peut potentiellement faire des transferts
114 // entre l'accélérateur et le CPU.
115 }
116 const Int32 nb_index = indexes.size() / 2;
117 // On devrait pouvoir utiliser 'm_extent.v' mais avec CUDA 12.1 cela génère
118 // une erreur lors de l'exécution: error 98 : invalid device function
119 const Int32 sub_size = m_extent.v;
120
121 auto command = makeCommand(queue);
122 command << RUNCOMMAND_LOOP1(iter, nb_index)
123 {
124 auto [i] = iter();
125 Int32 index0 = indexes[i * 2];
126 Int32 index1 = indexes[(i * 2) + 1];
128 auto* orig_view_data = reinterpret_cast<DataType*>(orig_view_bytes.data());
129 // Utilise un span pour tester les débordements de tableau mais on
130 // pourrait directement utiliser 'orig_view_data' pour plus de performances
131 Span<DataType> orig_view = { orig_view_data, orig_view_bytes.size() / (Int64)sizeof(DataType) };
132 Int64 zci = ((Int64)(index1)) * sub_size;
133 Int64 z_index = (Int64)i * sub_size;
134 for (Int32 z = 0, n = sub_size; z < n; ++z)
135 orig_view[zci + z] = source[z_index + z];
136 };
137 }
138
144 void _fill(const RunQueue* queue, SmallSpan<const Int32> indexes, Span<const DataType> source,
145 Span<DataType> destination)
146 {
148
149 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, indexes.data());
150 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, destination.data());
152
153 Int32 nb_index = indexes.size();
154 const Int32 sub_size = m_extent.v;
155 constexpr Int32 max_size = 24;
156
157 // Pour l'instant on limite la taille de DataType en dur.
158 // A terme, il faudrait allouer sur le device et désallouer en fin
159 // d'exécution (via cudaMallocAsync/cudaFreeAsync pour gérer l'asynchronisme)
160 if (sub_size > max_size)
161 ARCANE_THROW(NotSupportedException, "sizeof(type) is too big (v={0} max={1})",
162 sizeof(DataType) * sub_size, sizeof(DataType) * max_size);
164 for (Int32 z = 0; z < sub_size; ++z)
165 local_source[z] = source[z];
166 for (Int32 z = sub_size; z < max_size; ++z)
167 local_source[z] = {};
168
169 auto command = makeCommand(queue);
170 // Si \a nb_index vaut 0, on remplit tous les éléments
171 if (nb_index == 0) {
172 Int32 nb_value = CheckedConvert::toInt32(destination.size() / sub_size);
173 command << RUNCOMMAND_LOOP1(iter, nb_value)
174 {
175 auto [i] = iter();
176 Int64 zci = i * sub_size;
177 for (Int32 z = 0; z < sub_size; ++z)
178 destination[zci + z] = local_source[z];
179 };
180 }
181 else {
182 command << RUNCOMMAND_LOOP1(iter, nb_index)
183 {
184 auto [i] = iter();
185 Int64 zci = indexes[i] * sub_size;
186 for (Int32 z = 0; z < sub_size; ++z)
187 destination[zci + z] = local_source[z];
188 };
189 }
190 }
191
194 {
196
197 if (arcaneIsCheck()) {
198 ARCANE_CHECK_ACCESSIBLE_POINTER_ALWAYS(queue, indexes.data());
201 // Idéalement il faudrait tester les valeurs des éléments de multi_views
202 // mais si on fait cela on peut potentiellement faire des transferts
203 // entre l'accélérateur et le CPU.
204 }
205 const Int32 nb_index = indexes.size() / 2;
206 // On devrait pouvoir utiliser 'm_extent.v' mais avec CUDA 12.1 cela génère
207 // une erreur lors de l'exécution: error 98 : invalid device function
208 const Int32 sub_size = m_extent.v;
209 constexpr Int32 max_size = 24;
210
211 // Pour l'instant on limite la taille de DataType en dur.
212 // A terme, il faudrait allouer sur le device et désallouer en fin
213 // d'exécution (via cudaMallocAsync/cudaFreeAsync pour gérer l'asynchronisme)
214 if (sub_size > max_size)
215 ARCANE_THROW(NotSupportedException, "sizeof(type) is too big (v={0} max={1})",
216 sizeof(DataType) * sub_size, sizeof(DataType) * max_size);
218 for (Int32 z = 0; z < sub_size; ++z)
219 local_source[z] = source[z];
220 for (Int32 z = sub_size; z < max_size; ++z)
221 local_source[z] = {};
222
223 if (nb_index == 0) {
224 // Remplit toutes les valeurs du tableau avec la source.
225 // Comme le nombre d'éléments de la deuxième dimension dépend de la première,
226 // on utilise un noyau par dimension.
227 RunQueue q(*queue);
229 const Int32 nb_dim1 = multi_views.size();
230 for (Int32 zz = 0; zz < nb_dim1; ++zz) {
231 Span<DataType> orig_view = Arccore::asSpan<DataType>(multi_views[zz]);
232 Int32 nb_value = CheckedConvert::toInt32(orig_view.size() / sub_size);
233 auto command = makeCommand(queue);
234 command << RUNCOMMAND_LOOP1(iter, nb_value)
235 {
236 auto [i] = iter();
237 orig_view[i] = local_source[i % sub_size];
238 };
239 }
240 }
241 else {
242 auto command = makeCommand(queue);
243 command << RUNCOMMAND_LOOP1(iter, nb_index)
244 {
245 auto [i] = iter();
246 Int32 index0 = indexes[i * 2];
247 Int32 index1 = indexes[(i * 2) + 1];
248 Span<std::byte> orig_view_bytes = multi_views[index0];
249 auto* orig_view_data = reinterpret_cast<DataType*>(orig_view_bytes.data());
250 // Utilise un span pour tester les débordements de tableau mais on
251 // pourrait directement utiliser 'orig_view_data' pour plus de performances
252 Span<DataType> orig_view = { orig_view_data, orig_view_bytes.size() / (Int64)sizeof(DataType) };
253 Int64 zci = ((Int64)(index1)) * sub_size;
254 for (Int32 z = 0, n = sub_size; z < n; ++z)
255 orig_view[zci + z] = local_source[z];
256 };
257 }
258 }
259
260 void _copyTo(const RunQueue* queue, SmallSpan<const Int32> indexes, Span<const DataType> source,
261 Span<DataType> destination)
262 {
264
265 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, indexes.data());
266 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, source.data());
267 ARCANE_CHECK_ACCESSIBLE_POINTER(queue, destination.data());
268
269 Int32 nb_index = indexes.size();
270 const Int64 sub_size = m_extent.v;
271
272 auto command = makeCommand(queue);
273 command << RUNCOMMAND_LOOP1(iter, nb_index)
274 {
275 auto [i] = iter();
276 Int64 zindex = i * sub_size;
277 Int64 zci = indexes[i] * sub_size;
278 for (Int32 z = 0; z < sub_size; ++z)
279 destination[zci + z] = source[zindex + z];
280 };
281 }
282
283 void _copyTo(const RunQueue* queue, SmallSpan<const Int32> indexes, SmallSpan<const Span<const std::byte>> multi_views,
284 Span<DataType> destination)
285 {
287
288 if (arcaneIsCheck()) {
289 ARCANE_CHECK_ACCESSIBLE_POINTER_ALWAYS(queue, indexes.data());
290 ARCANE_CHECK_ACCESSIBLE_POINTER_ALWAYS(queue, destination.data());
291 ARCANE_CHECK_ACCESSIBLE_POINTER_ALWAYS(queue, multi_views.data());
292 // Idéalement il faudrait tester les valeurs des éléments de multi_views
293 // mais si on fait cela on peut potentiellement faire des transferts
294 // entre l'accélérateur et le CPU.
295 }
296
297 const Int32 nb_index = indexes.size() / 2;
298 // On devrait pouvoir utiliser 'm_extent.v' mais avec CUDA 12.1 cela génère
299 // une erreur lors de l'exécution: error 98 : invalid device function
300 const Int32 sub_size = m_extent.v;
301
302 auto command = makeCommand(queue);
303 command << RUNCOMMAND_LOOP1(iter, nb_index)
304 {
305 auto [i] = iter();
306 Int32 index0 = indexes[i * 2];
307 Int32 index1 = indexes[(i * 2) + 1];
308 Span<const std::byte> orig_view_bytes = multi_views[index0];
309 auto* orig_view_data = reinterpret_cast<const DataType*>(orig_view_bytes.data());
310 // Utilise un span pour tester les débordements de tableau mais on
311 // pourrait directement utiliser 'orig_view_data' pour plus de performances
312 Span<const DataType> orig_view = { orig_view_data, orig_view_bytes.size() / (Int64)sizeof(DataType) };
313 Int64 zci = ((Int64)(index1)) * sub_size;
314 Int64 z_index = (Int64)i * sub_size;
315 for (Int32 z = 0, n = sub_size; z < n; ++z)
316 destination[z_index + z] = orig_view[zci + z];
317 };
318 }
319};
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
332
333/*---------------------------------------------------------------------------*/
334/*---------------------------------------------------------------------------*/
335
346
347namespace
348{
350}
351
352/*---------------------------------------------------------------------------*/
353/*---------------------------------------------------------------------------*/
354
355} // namespace Arcane::Accelerator::impl
356
357/*---------------------------------------------------------------------------*/
358/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_ACCESSIBLE_POINTER(queue_or_runner_or_policy, ptr)
Macro qui vérifie en mode check si ptr est accessible pour une RunQueue ou un Runner.
#define ARCANE_CHECK_ACCESSIBLE_POINTER_ALWAYS(queue_or_runner_or_policy, ptr)
Macro qui vérifie si ptr est accessible pour une RunQueue ou un Runner.
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
Types et macros pour gérer les boucles sur les accélérateurs.
#define RUNCOMMAND_LOOP1(iter_name, x1,...)
Boucle sur accélérateur avec arguments supplémentaires pour les réductions.
Permet de modifier l'asynchronisme de la file pendant la durée de vie de l'instance.
File d'exécution pour un accélérateur.
void _fill(const RunQueue *queue, SmallSpan< const Int32 > indexes, Span< const DataType > source, Span< DataType > destination)
Remplit les valeurs d'indices spécifiés par indexes.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
static void setDefaultCopyListIfNotSet(ISpecificMemoryCopyList *ptr)
Positionne l'instance par défaut pour les copies.
Definition MemoryView.cc:78
Interface d'un copieur mémoire spécialisé pour une taille de donnée.
Arguments pour une copie de certains indices entre deux zones mémoire.
Arguments pour une copie de certains indices vers/depuis une zone mémoire multiple.
Liste d'instances de ISpecificMemoryCopy spécialisées.
Exception lorsqu'une opération n'est pas supportée.
Vue d'un tableau d'éléments de type T.
Definition Span.h:670
RunCommand makeCommand(const RunQueue &run_queue)
Créé une commande associée à la file run_queue.
@ Sequential
Politique d'exécution séquentielle.
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
bool arcaneIsCheck()
Vrai si on est en mode vérification.
Definition Misc.cc:68
std::int64_t Int64
Type entier signé sur 64 bits.
std::int32_t Int32
Type entier signé sur 32 bits.