Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
Scan.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/* Scan.h (C) 2000-2024 */
9/* */
10/* Gestion des opérations de scan pour les accélérateurs. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_ACCELERATOR_SCAN_H
13#define ARCANE_ACCELERATOR_SCAN_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/utils/ArrayView.h"
18#include "arcane/utils/FatalErrorException.h"
19
20#include "arcane/utils/NumArray.h"
21
22#include "arcane/accelerator/core/RunQueue.h"
23
24#include "arcane/accelerator/AcceleratorGlobal.h"
25#include "arcane/accelerator/CommonUtils.h"
26#include "arcane/accelerator/RunCommandLaunchInfo.h"
28#include "arcane/accelerator/ScanImpl.h"
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33namespace Arcane::Accelerator::impl
34{
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38/*!
39 * \internal
40 * \brief Classe pour effectuer un scan exlusif ou inclusif avec un opérateur spécifique.
41 */
43{
44 public:
45
46 explicit ScannerImpl(const RunQueue& queue)
47 : m_queue(queue)
48 {}
49
50 public:
51
52 template <bool IsExclusive, typename InputIterator, typename OutputIterator,
53 typename Operator, typename DataType>
54 void apply(Int32 nb_item, InputIterator input_data, OutputIterator output_data,
55 DataType init_value, Operator op, const TraceInfo& trace_info)
56 {
57 RunCommand command = makeCommand(m_queue);
58 command << trace_info;
59 impl::RunCommandLaunchInfo launch_info(command, nb_item);
60 launch_info.beginExecute();
61 eExecutionPolicy exec_policy = m_queue.executionPolicy();
62 switch (exec_policy) {
63#if defined(ARCANE_COMPILING_CUDA)
65 size_t temp_storage_size = 0;
66 cudaStream_t stream = impl::CudaUtils::toNativeStream(&m_queue);
67 // Premier appel pour connaitre la taille pour l'allocation
68 if constexpr (IsExclusive)
69 ARCANE_CHECK_CUDA(::cub::DeviceScan::ExclusiveScan(nullptr, temp_storage_size,
70 input_data, output_data, op, init_value, nb_item, stream));
71 else
72 ARCANE_CHECK_CUDA(::cub::DeviceScan::InclusiveScan(nullptr, temp_storage_size,
73 input_data, output_data, op, nb_item, stream));
74 void* temp_storage = m_storage.allocate(temp_storage_size);
75 if constexpr (IsExclusive)
76 ARCANE_CHECK_CUDA(::cub::DeviceScan::ExclusiveScan(temp_storage, temp_storage_size,
77 input_data, output_data, op, init_value, nb_item, stream));
78 else
79 ARCANE_CHECK_CUDA(::cub::DeviceScan::InclusiveScan(temp_storage, temp_storage_size,
80 input_data, output_data, op, nb_item, stream));
81 } break;
82#endif
83#if defined(ARCANE_COMPILING_HIP)
85 size_t temp_storage_size = 0;
86 // Premier appel pour connaitre la taille pour l'allocation
87 hipStream_t stream = impl::HipUtils::toNativeStream(&m_queue);
88 if constexpr (IsExclusive)
89 ARCANE_CHECK_HIP(rocprim::exclusive_scan(nullptr, temp_storage_size, input_data, output_data,
90 init_value, nb_item, op, stream));
91 else
92 ARCANE_CHECK_HIP(rocprim::inclusive_scan(nullptr, temp_storage_size, input_data, output_data,
93 nb_item, op, stream));
94 void* temp_storage = m_storage.allocate(temp_storage_size);
95 if constexpr (IsExclusive)
96 ARCANE_CHECK_HIP(rocprim::exclusive_scan(temp_storage, temp_storage_size, input_data, output_data,
97 init_value, nb_item, op, stream));
98 else
99 ARCANE_CHECK_HIP(rocprim::inclusive_scan(temp_storage, temp_storage_size, input_data, output_data,
100 nb_item, op, stream));
101 } break;
102#endif
103#if defined(ARCANE_COMPILING_SYCL)
105#if defined(ARCANE_USE_SCAN_ONEDPL) && defined(__INTEL_LLVM_COMPILER)
106 sycl::queue queue = impl::SyclUtils::toNativeStream(&m_queue);
107 auto policy = oneapi::dpl::execution::make_device_policy(queue);
108 if constexpr (IsExclusive) {
109 oneapi::dpl::exclusive_scan(policy, input_data, input_data + nb_item, output_data, init_value, op);
110 }
111 else {
112 oneapi::dpl::inclusive_scan(policy, input_data, input_data + nb_item, output_data, op);
113 }
114#else
116 copy_input_data(nb_item);
117 NumArray<DataType, MDDim1> copy_output_data(nb_item);
118 SmallSpan<DataType> in_data = copy_input_data.to1DSmallSpan();
119 SmallSpan<DataType> out_data = copy_output_data.to1DSmallSpan();
120 {
121 auto command = makeCommand(m_queue);
122 command << RUNCOMMAND_LOOP1(iter, nb_item)
123 {
124 auto [i] = iter();
125 in_data[i] = input_data[i];
126 };
127 }
128 m_queue.barrier();
129 SyclScanner<IsExclusive, DataType, Operator> scanner;
130 scanner.doScan(m_queue, in_data, out_data, init_value);
131 {
132 auto command = makeCommand(m_queue);
133 command << RUNCOMMAND_LOOP1(iter, nb_item)
134 {
135 auto [i] = iter();
136 output_data[i] = out_data[i];
137 };
138 }
139 m_queue.barrier();
140#endif
141 } break;
142#endif
144 // Pas encore implémenté en multi-thread
145 [[fallthrough]];
147 DataType sum = init_value;
148 for (Int32 i = 0; i < nb_item; ++i) {
149 DataType v = *input_data;
150 if constexpr (IsExclusive) {
151 *output_data = sum;
152 sum = op(v, sum);
153 }
154 else {
155 sum = op(v, sum);
156 *output_data = sum;
157 }
158 ++input_data;
159 ++output_data;
160 }
161 } break;
162 default:
163 ARCANE_FATAL(getBadPolicyMessage(exec_policy));
164 }
165 launch_info.endExecute();
166 }
167
168 private:
169
170 RunQueue m_queue;
171 GenericDeviceStorage m_storage;
172};
173
174/*---------------------------------------------------------------------------*/
175/*---------------------------------------------------------------------------*/
176
177} // namespace Arcane::Accelerator::impl
178
179namespace Arcane::Accelerator
180{
181
182/*---------------------------------------------------------------------------*/
183/*---------------------------------------------------------------------------*/
184/*!
185 * \brief Algorithmes de scan exclusif ou inclusif sur accélérateurs.
186 *
187 * Voir https://en.wikipedia.org/wiki/Prefix_sum.
188 *
189 * Dans les méthodes suivantes, l'argument \a queue ne doit pas être nul.
190 */
191template <typename DataType>
192class Scanner
193{
194 public:
195
196 //! Somme exclusive
197 static void exclusiveSum(RunQueue* queue, SmallSpan<const DataType> input, SmallSpan<DataType> output)
198 {
199 _applyArray<true>(queue, input, output, ScannerSumOperator<DataType>{});
200 }
201 //! Minimum exclusif
202 static void exclusiveMin(RunQueue* queue, SmallSpan<const DataType> input, SmallSpan<DataType> output)
203 {
204 _applyArray<true>(queue, input, output, ScannerMinOperator<DataType>{});
205 }
206 //! Maximum exclusif
207 static void exclusiveMax(RunQueue* queue, SmallSpan<const DataType> input, SmallSpan<DataType> output)
208 {
209 _applyArray<true>(queue, input, output, ScannerMaxOperator<DataType>{});
210 }
211 //! Somme inclusive
212 static void inclusiveSum(RunQueue* queue, SmallSpan<const DataType> input, SmallSpan<DataType> output)
213 {
214 _applyArray<false>(queue, input, output, ScannerSumOperator<DataType>{});
215 }
216 //! Minimum inclusif
217 static void inclusiveMin(RunQueue* queue, SmallSpan<const DataType> input, SmallSpan<DataType> output)
218 {
219 _applyArray<false>(queue, input, output, ScannerMinOperator<DataType>{});
220 }
221 //! Maximum inclusif
222 static void inclusiveMax(RunQueue* queue, SmallSpan<const DataType> input, SmallSpan<DataType> output)
223 {
224 _applyArray<false>(queue, input, output, ScannerMaxOperator<DataType>{});
225 }
226
227 private:
228
229 template <bool IsExclusive, typename Operator>
230 static void _applyArray(RunQueue* queue, SmallSpan<const DataType> input, SmallSpan<DataType> output, const Operator& op)
231 {
233 impl::ScannerImpl scanner(*queue);
234 const Int32 nb_item = input.size();
235 if (output.size() != nb_item)
236 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_item, output.size());
237 const DataType* input_data = input.data();
238 DataType* output_data = output.data();
239 DataType init_value = op.defaultValue();
240 scanner.apply<IsExclusive>(nb_item, input_data, output_data, init_value, op, TraceInfo{});
241 }
242};
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
246/*!
247 * \brief Algorithmes de scan exclusif ou inclusif sur accélérateurs.
248 *
249 * Voir https://en.wikipedia.org/wiki/Prefix_sum.
250 *
251 * Dans les méthodes de scan, les valeurs entre les entrées et les sorties
252 * ne doivent pas se chevaucher.
253 */
254class GenericScanner
255{
256 public:
257
258 /*!
259 * \brief Itérateur sur une lambda pour positionner une valeur via un index.
260 */
261 template <typename DataType, typename SetterLambda>
263 {
264 public:
265
266 //! Permet de positionner un élément de l'itérateur de sortie
267 class Setter
268 {
269 public:
270
271 ARCCORE_HOST_DEVICE explicit Setter(const SetterLambda& s, Int32 index)
272 : m_index(index)
273 , m_lambda(s)
274 {}
275 ARCCORE_HOST_DEVICE void operator=(const DataType& value)
276 {
277 m_lambda(m_index, value);
278 }
279
280 public:
281
282 Int32 m_index = 0;
283 SetterLambda m_lambda;
284 };
285
286 using value_type = DataType;
287 using iterator_category = std::random_access_iterator_tag;
288 using reference = Setter;
289 using difference_type = ptrdiff_t;
290 using pointer = void;
292
293 public:
294
295 ARCCORE_HOST_DEVICE SetterLambdaIterator(const SetterLambda& s)
296 : m_lambda(s)
297 {}
298 ARCCORE_HOST_DEVICE explicit SetterLambdaIterator(const SetterLambda& s, Int32 v)
299 : m_index(v)
300 , m_lambda(s)
301 {}
302
303 public:
304
305 ARCCORE_HOST_DEVICE ThatClass& operator++()
306 {
307 ++m_index;
308 return (*this);
309 }
310 ARCCORE_HOST_DEVICE friend ThatClass operator+(const ThatClass& iter, Int32 x)
311 {
312 return ThatClass(iter.m_lambda, iter.m_index + x);
313 }
314 ARCCORE_HOST_DEVICE friend ThatClass operator+(Int32 x, const ThatClass& iter)
315 {
316 return ThatClass(iter.m_lambda, iter.m_index + x);
317 }
318 ARCCORE_HOST_DEVICE friend bool operator<(const ThatClass& iter1, const ThatClass& iter2)
319 {
320 return iter1.m_index < iter2.m_index;
321 }
322 ARCCORE_HOST_DEVICE ThatClass operator-(Int32 x)
323 {
324 return ThatClass(m_lambda, m_index - x);
325 }
326 ARCCORE_HOST_DEVICE Int32 operator-(const ThatClass& x) const
327 {
328 return m_index - x.m_index;
329 }
330 ARCCORE_HOST_DEVICE reference operator*() const
331 {
332 return Setter(m_lambda, m_index);
333 }
334 ARCCORE_HOST_DEVICE reference operator[](Int32 x) const { return Setter(m_lambda, m_index + x); }
335 ARCCORE_HOST_DEVICE friend bool operator!=(const ThatClass& a, const ThatClass& b)
336 {
337 return a.m_index != b.m_index;
338 }
339
340 private:
341
342 Int32 m_index = 0;
343 SetterLambda m_lambda;
344 };
345
346 public:
347
348 explicit GenericScanner(const RunQueue& queue)
349 : m_queue(queue)
350 {}
351
352 public:
353
354 template <typename DataType, typename GetterLambda, typename SetterLambda, typename Operator>
355 void applyWithIndexExclusive(Int32 nb_value, const DataType& initial_value,
356 const GetterLambda& getter_lambda,
357 const SetterLambda& setter_lambda,
358 const Operator& op_lambda,
359 const TraceInfo& trace_info = TraceInfo())
360 {
361 _applyWithIndex<true>(nb_value, initial_value, getter_lambda, setter_lambda, op_lambda, trace_info);
362 }
363
364 template <typename DataType, typename GetterLambda, typename SetterLambda, typename Operator>
365 void applyWithIndexInclusive(Int32 nb_value, const DataType& initial_value,
366 const GetterLambda& getter_lambda,
367 const SetterLambda& setter_lambda,
368 const Operator& op_lambda,
369 const TraceInfo& trace_info = TraceInfo())
370 {
371 _applyWithIndex<false>(nb_value, initial_value, getter_lambda, setter_lambda, op_lambda, trace_info);
372 }
373
374 template <typename InputDataType, typename OutputDataType, typename Operator>
375 void applyExclusive(const OutputDataType& initial_value,
376 SmallSpan<const InputDataType> input,
377 SmallSpan<OutputDataType> output,
378 const Operator& op_lambda,
379 const TraceInfo& trace_info = TraceInfo())
380 {
381 _apply<true>(initial_value, input, output, op_lambda, trace_info);
382 }
383
384 template <typename InputDataType, typename OutputDataType, typename Operator>
385 void applyInclusive(const OutputDataType& initial_value,
386 SmallSpan<const InputDataType> input,
387 SmallSpan<OutputDataType> output,
388 const Operator& op_lambda,
389 const TraceInfo& trace_info = TraceInfo())
390 {
391 _apply<false>(initial_value, input, output, op_lambda, trace_info);
392 }
393
394 private:
395
396 template <bool IsExclusive, typename DataType, typename GetterLambda, typename SetterLambda, typename Operator>
397 void _applyWithIndex(Int32 nb_value, const DataType& initial_value,
398 const GetterLambda& getter_lambda,
399 const SetterLambda& setter_lambda,
400 const Operator& op_lambda,
401 const TraceInfo& trace_info)
402 {
403 impl::GetterLambdaIterator<DataType, GetterLambda> input_iter(getter_lambda);
404 SetterLambdaIterator<DataType, SetterLambda> output_iter(setter_lambda);
405 impl::ScannerImpl scanner(m_queue);
406 scanner.apply<IsExclusive>(nb_value, input_iter, output_iter, initial_value, op_lambda, trace_info);
407 }
408
409 template <bool IsExclusive, typename InputDataType, typename OutputDataType, typename Operator>
410 void _apply(const OutputDataType& initial_value,
411 SmallSpan<const InputDataType> input,
412 SmallSpan<OutputDataType> output,
413 const Operator& op,
414 const TraceInfo& trace_info = TraceInfo())
415 {
416 const Int32 nb_item = input.size();
417 if (output.size() != nb_item)
418 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_item, output.size());
419 auto* input_data = input.data();
420 auto* output_data = output.data();
421 impl::ScannerImpl scanner(m_queue);
422 scanner.apply<IsExclusive>(nb_item, input_data, output_data, initial_value, op, trace_info);
423 }
424
425 private:
426
427 RunQueue m_queue;
428};
429
430/*---------------------------------------------------------------------------*/
431/*---------------------------------------------------------------------------*/
432
433} // namespace Arcane::Accelerator
434
435/*---------------------------------------------------------------------------*/
436/*---------------------------------------------------------------------------*/
437
438#endif
439
440/*---------------------------------------------------------------------------*/
441/*---------------------------------------------------------------------------*/
#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_FATAL(...)
Macro envoyant une exception FatalErrorException.
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 positionner un élément de l'itérateur de sortie.
Definition Scan.h:268
Itérateur sur une lambda pour positionner une valeur via un index.
Definition Scan.h:263
Gestion d'une commande sur accélérateur.
File d'exécution pour un accélérateur.
void barrier() const
Bloque tant que toutes les commandes associées à la file ne sont pas terminées.
Definition RunQueue.cc:158
eExecutionPolicy executionPolicy() const
Politique d'exécution de la file.
Definition RunQueue.cc:168
void beginExecute()
Indique qu'on commence l'exécution de la commande.
void endExecute()
Signale la fin de l'exécution.
Tableaux multi-dimensionnels pour les types numériques accessibles sur accélérateurs.
constexpr SmallSpan< DataType > to1DSmallSpan()
Vue 1D sur l'instance (uniquement si rank == 1)
Vue d'un tableau d'éléments de type T.
Definition Span.h:670
Espace de nom pour l'utilisation des accélérateurs.
RunCommand makeCommand(const RunQueue &run_queue)
Créé une commande associée à la file run_queue.
eExecutionPolicy
Politique d'exécution pour un Runner.
@ SYCL
Politique d'exécution utilisant l'environnement SYCL.
@ HIP
Politique d'exécution utilisant l'environnement HIP.
@ CUDA
Politique d'exécution utilisant l'environnement CUDA.
@ Sequential
Politique d'exécution séquentielle.
@ Thread
Politique d'exécution multi-thread.
std::int32_t Int32
Type entier signé sur 32 bits.