Arcane  v3.15.0.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
CommonUtils.h
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/* CommonUtils.h (C) 2000-2024 */
9/* */
10/* Fonctions/Classes utilitaires communes à tout les runtimes. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_ACCELERATOR_COMMONUTILS_H
13#define ARCANE_ACCELERATOR_COMMONUTILS_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/utils/Array.h"
18
19#include "arcane/accelerator/AcceleratorGlobal.h"
20#include "arcane/accelerator/core/RunQueue.h"
21#include "arcane/accelerator/AcceleratorUtils.h"
22
23#if defined(ARCANE_COMPILING_HIP)
24#include "arcane/accelerator/hip/HipAccelerator.h"
25#include <rocprim/rocprim.hpp>
26#endif
27#if defined(ARCANE_COMPILING_CUDA)
28#include "arcane/accelerator/cuda/CudaAccelerator.h"
29#include <cub/cub.cuh>
30#endif
31#if defined(ARCANE_COMPILING_SYCL)
32#include "arcane/accelerator/sycl/SyclAccelerator.h"
33#if defined(__INTEL_LLVM_COMPILER)
34#include <oneapi/dpl/execution>
35#include <oneapi/dpl/algorithm>
36#endif
37#endif
38
39// A définir si on souhaite utiliser LambdaStorage
40// #ifdef ARCANE_USE_LAMBDA_STORAGE
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45namespace Arcane::Accelerator::impl
46{
47/*!
48 * \brief Classe pour gérer la conservation d'une lambda dans un itérateur.
49 *
50 * Actuellement (C++20), on ne peut pas conserver une lambda dans un
51 * itérateur car il manque deux choses: un constructeur par défaut et
52 * un opérateur de recopie. Cette classe permet de supporter cela à condition
53 * que les deux poins suivants soient respectés:
54 * - instances capturées par la lambda sont trivialement copiables et donc
55 * la lambda l'est.
56 * - les instances utilisant le constructeur par défaut ne sont pas utilisées
57 * (ce qui est le cas des itérateurs car ils ne sont pas valides s'ils sont
58 * construits avec le constructeur par défaut.
59 *
60 * A noter que l'alignement de cette classe doit être au moins celui de la
61 * lambda associée.
62 *
63 * Cette classe n'est indispensable que pour SYCL avec oneAPI car il est
64 * nécessite que les itérateurs aient le concept std::random_access_iterator.
65 * Cependant elle devrait aussi fonctionner avec CUDA et ROCM. A tester
66 * l'effet sur les performances.
67 */
68template <typename LambdaType>
69class alignas(LambdaType) LambdaStorage
70{
71 static constexpr size_t SizeofLambda = sizeof(LambdaType);
72
73 public:
74
75 LambdaStorage() = default;
76 ARCCORE_HOST_DEVICE LambdaStorage(const LambdaType& v)
77 {
78 std::memcpy(bytes, &v, SizeofLambda);
79 }
80 //! Convertie la classe en la lambda.
81 ARCCORE_HOST_DEVICE operator const LambdaType&() const { return *reinterpret_cast<const LambdaType*>(&bytes); }
82
83 private:
84
85 char bytes[SizeofLambda];
86};
87
88/*---------------------------------------------------------------------------*/
89/*---------------------------------------------------------------------------*/
90/*!
91 * \internal
92 * \brief Gère l'allocation interne sur le device.
93 */
94class ARCANE_ACCELERATOR_EXPORT GenericDeviceStorage
95{
96 public:
97
100 {
101 deallocate();
102 }
103
104 public:
105
106 void* address() { return m_storage.data(); }
107 size_t size() const { return m_storage.largeSize(); }
108 void* allocate(size_t new_size)
109 {
110 m_storage.resize(new_size);
111 return m_storage.data();
112 }
113
114 void deallocate()
115 {
116 m_storage.clear();
117 }
118
119 Span<const std::byte> bytes() const
120 {
121 return m_storage.span();
122 }
123
124 private:
125
126 UniqueArray<std::byte> m_storage;
127};
128
129/*---------------------------------------------------------------------------*/
130/*---------------------------------------------------------------------------*/
131/*!
132 * \internal
133 * \brief Gère l'allocation interne sur le device.
134 */
135class ARCANE_ACCELERATOR_EXPORT DeviceStorageBase
136{
137 protected:
138
139 GenericDeviceStorage m_storage;
140
141 protected:
142
143 //! Copie l'instance dans \a dest_ptr
144 void _copyToAsync(Span<std::byte> destination, Span<const std::byte> source, const RunQueue& queue);
145};
146
147/*---------------------------------------------------------------------------*/
148/*---------------------------------------------------------------------------*/
149/*!
150 * \internal
151 * \brief Gère l'allocation interne sur le device pour un type donné.
152 */
153template <typename DataType, Int32 N = 1>
155: public DeviceStorageBase
156{
157 public:
158
159 DataType* address() { return reinterpret_cast<DataType*>(m_storage.address()); }
160 size_t size() const { return m_storage.size(); }
161 DataType* allocate()
162 {
163 m_storage.allocate(sizeof(DataType) * N);
164 return address();
165 }
166 void deallocate() { m_storage.deallocate(); }
167
168 //! Copie l'instance dans \a dest_ptr
169 void copyToAsync(SmallSpan<DataType> dest_ptr, const RunQueue& queue)
170 {
171 _copyToAsync(asWritableBytes(dest_ptr), m_storage.bytes(), queue);
172 }
173};
174
175/*---------------------------------------------------------------------------*/
176/*---------------------------------------------------------------------------*/
177/*!
178 * \brief Itérateur sur un index.
179 *
180 * Permet d'itérer entre deux entiers.
181 */
183{
184 public:
185
186 using value_type = Int32;
187 using iterator_category = std::random_access_iterator_tag;
188 using reference = value_type&;
189 using difference_type = ptrdiff_t;
190 using pointer = void;
191
192 using ThatClass = IndexIterator;
193
194 public:
195
196 IndexIterator() = default;
197 ARCCORE_HOST_DEVICE explicit IndexIterator(Int32 v)
198 : m_value(v)
199 {}
200
201 public:
202
203 ARCCORE_HOST_DEVICE IndexIterator& operator++()
204 {
205 ++m_value;
206 return (*this);
207 }
208 ARCCORE_HOST_DEVICE IndexIterator operator+(Int32 x) const
209 {
210 return IndexIterator(m_value + x);
211 }
212 ARCCORE_HOST_DEVICE friend ThatClass operator+(Int32 x, const ThatClass& iter)
213 {
214 return ThatClass(iter.m_value + x);
215 }
216 ARCCORE_HOST_DEVICE IndexIterator operator-(Int32 x) const
217 {
218 return IndexIterator(m_value - x);
219 }
220 ARCCORE_HOST_DEVICE Int32 operator-(const ThatClass& x) const
221 {
222 return m_value - x.m_value;
223 }
224 ARCCORE_HOST_DEVICE Int32 operator*() const { return m_value; }
225 ARCCORE_HOST_DEVICE Int32 operator[](Int32 x) const { return m_value + x; }
226 ARCCORE_HOST_DEVICE friend bool operator==(const ThatClass& a, const ThatClass& b)
227 {
228 return a.m_value == b.m_value;
229 }
230 ARCCORE_HOST_DEVICE friend bool operator<(const ThatClass& iter1, const ThatClass& iter2)
231 {
232 return iter1.m_value < iter2.m_value;
233 }
234
235 private:
236
237 Int32 m_value = 0;
238};
239
240/*---------------------------------------------------------------------------*/
241/*---------------------------------------------------------------------------*/
242
243//! Opérateur de Scan/Reduce pour les sommes
244template <typename DataType>
246{
247 public:
248
249 constexpr ARCCORE_HOST_DEVICE DataType operator()(const DataType& a, const DataType& b) const
250 {
251 return a + b;
252 }
253 static DataType defaultValue() { return {}; }
254#if defined(ARCANE_COMPILING_SYCL)
255 static sycl::plus<DataType> syclFunctor() { return {}; }
256#endif
257};
258
259/*---------------------------------------------------------------------------*/
260/*---------------------------------------------------------------------------*/
261
262//! Opérateur de Scan/Reduce pour le minimum
263template <typename DataType>
265{
266 public:
267
268 constexpr ARCCORE_HOST_DEVICE DataType operator()(const DataType& a, const DataType& b) const
269 {
270 return (a < b) ? a : b;
271 }
272 static DataType defaultValue() { return std::numeric_limits<DataType>::max(); }
273#if defined(ARCANE_COMPILING_SYCL)
274 static sycl::minimum<DataType> syclFunctor() { return {}; }
275#endif
276};
277
278/*---------------------------------------------------------------------------*/
279/*---------------------------------------------------------------------------*/
280
281//! Opérateur de Scan/Reduce pour le maximum
282template <typename DataType>
284{
285 public:
286
287 constexpr ARCCORE_HOST_DEVICE DataType operator()(const DataType& a, const DataType& b) const
288 {
289 return (a < b) ? b : a;
290 }
291 static DataType defaultValue() { return std::numeric_limits<DataType>::lowest(); }
292#if defined(ARCANE_COMPILING_SYCL)
293 static sycl::maximum<DataType> syclFunctor() { return {}; }
294#endif
295};
296
297/*---------------------------------------------------------------------------*/
298/*---------------------------------------------------------------------------*/
299/*!
300 * \brief Itérateur sur une lambda pour récupérer une valeur via un index.
301 */
302template <typename DataType, typename GetterLambda>
304{
305 public:
306
307 using value_type = DataType;
308 using iterator_category = std::random_access_iterator_tag;
309 using reference = DataType&;
310 using difference_type = ptrdiff_t;
311 using pointer = void;
313
314 public:
315
316 ARCCORE_HOST_DEVICE GetterLambdaIterator(const GetterLambda& s)
317 : m_lambda(s)
318 {}
319 ARCCORE_HOST_DEVICE explicit GetterLambdaIterator(const GetterLambda& s, Int32 v)
320 : m_index(v)
321 , m_lambda(s)
322 {}
323
324 public:
325
326 ARCCORE_HOST_DEVICE ThatClass& operator++()
327 {
328 ++m_index;
329 return (*this);
330 }
331 ARCCORE_HOST_DEVICE ThatClass& operator+=(Int32 x)
332 {
333 m_index += x;
334 return (*this);
335 }
336 ARCCORE_HOST_DEVICE friend ThatClass operator+(const ThatClass& iter, Int32 x)
337 {
338 return ThatClass(iter.m_lambda, iter.m_index + x);
339 }
340 ARCCORE_HOST_DEVICE friend ThatClass operator+(Int32 x, const ThatClass& iter)
341 {
342 return ThatClass(iter.m_lambda, iter.m_index + x);
343 }
344 ARCCORE_HOST_DEVICE friend bool operator<(const ThatClass& iter1, const ThatClass& iter2)
345 {
346 return iter1.m_index < iter2.m_index;
347 }
348
349 ARCCORE_HOST_DEVICE ThatClass operator-(Int32 x) const
350 {
351 return ThatClass(m_lambda, m_index - x);
352 }
353 ARCCORE_HOST_DEVICE Int32 operator-(const ThatClass& x) const
354 {
355 return m_index - x.m_index;
356 }
357 ARCCORE_HOST_DEVICE value_type operator*() const
358 {
359 return m_lambda(m_index);
360 }
361 ARCCORE_HOST_DEVICE value_type operator[](Int32 x) const { return m_lambda(m_index + x); }
362 ARCCORE_HOST_DEVICE friend bool operator!=(const ThatClass& a, const ThatClass& b)
363 {
364 return a.m_index != b.m_index;
365 }
366 ARCCORE_HOST_DEVICE friend bool operator==(const ThatClass& a, const ThatClass& b)
367 {
368 return a.m_index == b.m_index;
369 }
370
371 private:
372
373 Int32 m_index = 0;
374 GetterLambda m_lambda;
375};
376
377/*---------------------------------------------------------------------------*/
378/*---------------------------------------------------------------------------*/
379/*!
380 * \brief Itérateur sur une lambda pour positionner une valeur via un index.
381 *
382 * Le positionnement se fait via Setter::operator=().
383 */
384template <typename SetterLambda>
386{
387 public:
388
389 //! Permet de positionner un élément de l'itérateur de sortie
390 class Setter
391 {
392 public:
393
394 ARCCORE_HOST_DEVICE explicit Setter(const SetterLambda& s, Int32 output_index)
395 : m_output_index(output_index)
396 , m_lambda(s)
397 {}
398 ARCCORE_HOST_DEVICE void operator=(Int32 input_index)
399 {
400 m_lambda(input_index, m_output_index);
401 }
402 Int32 m_output_index = 0;
403 SetterLambda m_lambda;
404 };
405
406 using value_type = Int32;
407 using iterator_category = std::random_access_iterator_tag;
408 using reference = Setter;
409 using difference_type = ptrdiff_t;
410 using pointer = void;
411
412 using ThatClass = SetterLambdaIterator<SetterLambda>;
413
414 private:
415
416#ifdef ARCANE_USE_LAMBDA_STORAGE
417 using StorageType = LambdaStorage<SetterLambda>;
418#else
419 using StorageType = SetterLambda;
420#endif
421
422 public:
423
424 SetterLambdaIterator() = default;
425 ARCCORE_HOST_DEVICE SetterLambdaIterator(const SetterLambda& s)
426 : m_lambda(s)
427 {}
428 ARCCORE_HOST_DEVICE SetterLambdaIterator(const SetterLambda& s, Int32 v)
429 : m_index(v)
430 , m_lambda(s)
431 {}
432
433 private:
434
435#ifdef ARCANE_USE_LAMBDA_STORAGE
436 ARCCORE_HOST_DEVICE SetterLambdaIterator(const LambdaStorage<SetterLambda>& s, Int32 v)
437 : m_index(v)
438 , m_lambda(s)
439 {}
440#endif
441
442 public:
443
444 ARCCORE_HOST_DEVICE SetterLambdaIterator<SetterLambda>& operator++()
445 {
446 ++m_index;
447 return (*this);
448 }
449 ARCCORE_HOST_DEVICE SetterLambdaIterator<SetterLambda>& operator--()
450 {
451 --m_index;
452 return (*this);
453 }
454 ARCCORE_HOST_DEVICE reference operator*() const
455 {
456 return Setter(m_lambda, m_index);
457 }
458 ARCCORE_HOST_DEVICE reference operator[](Int32 x) const { return Setter(m_lambda, m_index + x); }
459 ARCCORE_HOST_DEVICE friend ThatClass operator+(Int32 x, const ThatClass& iter)
460 {
461 return ThatClass(iter.m_lambda, iter.m_index + x);
462 }
463 ARCCORE_HOST_DEVICE friend ThatClass operator+(const ThatClass& iter, Int32 x)
464 {
465 return ThatClass(iter.m_lambda, iter.m_index + x);
466 }
467 ARCCORE_HOST_DEVICE friend ThatClass operator-(const ThatClass& iter, Int32 x)
468 {
469 return ThatClass(iter.m_lambda, iter.m_index - x);
470 }
471 ARCCORE_HOST_DEVICE friend Int32 operator-(const ThatClass& iter1, const ThatClass& iter2)
472 {
473 return iter1.m_index - iter2.m_index;
474 }
475 ARCCORE_HOST_DEVICE friend bool operator<(const ThatClass& iter1, const ThatClass& iter2)
476 {
477 return iter1.m_index < iter2.m_index;
478 }
479
480 private:
481
482 Int32 m_index = 0;
483 StorageType m_lambda;
484};
485
486/*---------------------------------------------------------------------------*/
487/*---------------------------------------------------------------------------*/
488
489} // namespace Arcane::Accelerator::impl
490
491/*---------------------------------------------------------------------------*/
492/*---------------------------------------------------------------------------*/
493
494namespace Arcane::Accelerator
495{
496
497/*---------------------------------------------------------------------------*/
498/*---------------------------------------------------------------------------*/
499
500template <typename DataType> using ScannerSumOperator = impl::SumOperator<DataType>;
501template <typename DataType> using ScannerMaxOperator = impl::MaxOperator<DataType>;
502template <typename DataType> using ScannerMinOperator = impl::MinOperator<DataType>;
503
504/*---------------------------------------------------------------------------*/
505/*---------------------------------------------------------------------------*/
506
507} // namespace Arcane::Accelerator
508
509/*---------------------------------------------------------------------------*/
510/*---------------------------------------------------------------------------*/
511
512#ifdef ARCANE_USE_LAMBDA_STORAGE
513#undef ARCANE_USE_LAMBDA_STORAGE
514#endif
515
516#endif
517
518/*---------------------------------------------------------------------------*/
519/*---------------------------------------------------------------------------*/
File d'exécution pour un accélérateur.
void copyToAsync(SmallSpan< DataType > dest_ptr, const RunQueue &queue)
Copie l'instance dans dest_ptr.
Itérateur sur une lambda pour récupérer une valeur via un index.
Classe pour gérer la conservation d'une lambda dans un itérateur.
Definition CommonUtils.h:70
Opérateur de Scan/Reduce pour le maximum.
Opérateur de Scan/Reduce pour le minimum.
Permet de positionner un élément de l'itérateur de sortie.
Itérateur sur une lambda pour positionner une valeur via un index.
Opérateur de Scan/Reduce pour les sommes.
Vue d'un tableau d'éléments de type T.
Definition Span.h:670
Vue d'un tableau d'éléments de type T.
Definition Span.h:510
Vecteur 1D de données avec sémantique par valeur (style STL).
Espace de nom pour l'utilisation des accélérateurs.
Real2 operator*(Real sca, const Real2Proxy &vec)
Multiplication par un scalaire.
Definition Real2Proxy.h:241
bool operator<(const Item &item1, const Item &item2)
Compare deux entités.
Definition Item.h:533
detail::SpanTypeFromSize< std::byte, SizeType >::SpanType asWritableBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Converti la vue en un tableau d'octets modifiables.
Definition Span.h:916
std::int32_t Int32
Type entier signé sur 32 bits.