Arcane  v3.15.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
GenericFilterer.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/* GenericFilterer.h (C) 2000-2024 */
9/* */
10/* Algorithme de filtrage. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_ACCELERATOR_GENERICFILTERER_H
13#define ARCANE_ACCELERATOR_GENERICFILTERER_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/utils/ArrayView.h"
18#include "arcane/utils/FatalErrorException.h"
19#include "arcane/utils/NumArray.h"
20#include "arcane/utils/TraceInfo.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#include "arcane/accelerator/MultiThreadAlgo.h"
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane::Accelerator::impl
35{
36//#define ARCANE_USE_SCAN_ONEDPL
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
46class ARCANE_ACCELERATOR_EXPORT GenericFilteringBase
47{
48 template <typename DataType, typename FlagType, typename OutputDataType>
49 friend class GenericFilteringFlag;
50 friend class GenericFilteringIf;
51 friend class SyclGenericFilteringImpl;
52
53 public:
54
55
56 protected:
57
59
60 protected:
61
62 Int32 _nbOutputElement() const;
63 void _allocate();
64 void _allocateTemporaryStorage(size_t size);
65 int* _getDeviceNbOutPointer();
66 void _copyDeviceNbOutToHostNbOut();
67
68 protected:
69
72 // Mémoire de travail pour l'algorithme de filtrage.
73 GenericDeviceStorage m_algo_storage;
85 bool m_use_direct_host_storage = true;
86};
87
88/*---------------------------------------------------------------------------*/
89/*---------------------------------------------------------------------------*/
90
91#if defined(ARCANE_COMPILING_SYCL)
93class SyclGenericFilteringImpl
94{
95 public:
96
97 template <typename SelectLambda, typename InputIterator, typename OutputIterator>
100 {
101 RunQueue queue = s.m_queue;
102 using DataType = std::iterator_traits<OutputIterator>::value_type;
103#if defined(ARCANE_USE_SCAN_ONEDPL) && defined(__INTEL_LLVM_COMPILER)
104 sycl::queue true_queue = AcceleratorUtils::toSyclNativeStream(queue);
105 auto policy = oneapi::dpl::execution::make_device_policy(true_queue);
106 auto out_iter = oneapi::dpl::copy_if(policy, input_iter, input_iter + nb_item, output_iter, select_lambda);
109#else
114 {
115 auto command = makeCommand(queue);
116 command << RUNCOMMAND_LOOP1(iter, nb_item)
117 {
118 auto [i] = iter();
119 in_scan_data[i] = select_lambda(input_iter[i]) ? 1 : 0;
120 };
121 }
122 queue.barrier();
123 SyclScanner<false /*is_exclusive*/, Int32, ScannerSumOperator<Int32>> scanner;
124 scanner.doScan(queue, in_scan_data, out_scan_data, 0);
125 // La valeur de 'out_data' pour le dernier élément (nb_item-1) contient la taille du filtre
128
129 const bool do_verbose = false;
130 if (do_verbose && nb_item < 1500)
131 for (int i = 0; i < nb_item; ++i) {
132 std::cout << "out_data i=" << i << " out_data=" << out_scan_data[i]
133 << " in_data=" << in_scan_data[i] << " value=" << input_iter[i] << "\n ";
134 }
135 // Copie depuis 'out_data' vers 'in_data' les indices correspondant au filtre
136 // Comme 'output_iter' et 'input_iter' peuvent se chevaucher, il
137 // faut faire une copie intermédiaire
138 // TODO: détecter cela et ne faire la copie que si nécessaire.
139 NumArray<DataType,MDDim1> out_copy(eMemoryRessource::Device);
140 out_copy.resize(nb_output);
141 auto out_copy_view = out_copy.to1DSpan();
142 {
143 auto command = makeCommand(queue);
144 command << RUNCOMMAND_LOOP1(iter, nb_item)
145 {
146 auto [i] = iter();
147 if (in_scan_data[i] == 1)
149 };
150 }
151 {
152 auto command = makeCommand(queue);
153 command << RUNCOMMAND_LOOP1(iter, nb_output)
154 {
155 auto [i] = iter();
157 };
158 }
159 // Obligatoire à cause de 'out_copy'. On pourra le supprimer avec une
160 // allocation temporaire.
161 queue.barrier();
162#endif
163 }
164};
165#endif
166
167/*---------------------------------------------------------------------------*/
168/*---------------------------------------------------------------------------*/
176template <typename DataType, typename FlagType, typename OutputDataType>
178{
179 public:
180
183 {
184 const Int32 nb_item = input.size();
185 if (output.size() != nb_item)
186 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_item, output.size());
187 [[maybe_unused]] const DataType* input_data = input.data();
188 [[maybe_unused]] DataType* output_data = output.data();
189 [[maybe_unused]] const FlagType* flag_data = flag.data();
191 RunQueue queue = s.m_queue;
193 switch (exec_policy) {
194#if defined(ARCANE_COMPILING_CUDA)
196 size_t temp_storage_size = 0;
197 cudaStream_t stream = AcceleratorUtils::toCudaNativeStream(queue);
198 // Premier appel pour connaitre la taille pour l'allocation
199 int* nb_out_ptr = nullptr;
200 ARCANE_CHECK_CUDA(::cub::DeviceSelect::Flagged(nullptr, temp_storage_size,
202
203 s._allocateTemporaryStorage(temp_storage_size);
204 nb_out_ptr = s._getDeviceNbOutPointer();
205 ARCANE_CHECK_CUDA(::cub::DeviceSelect::Flagged(s.m_algo_storage.address(), temp_storage_size,
207 s._copyDeviceNbOutToHostNbOut();
208 } break;
209#endif
210#if defined(ARCANE_COMPILING_HIP)
212 size_t temp_storage_size = 0;
213 // Premier appel pour connaitre la taille pour l'allocation
214 hipStream_t stream = AcceleratorUtils::toHipNativeStream(queue);
215 int* nb_out_ptr = nullptr;
216 ARCANE_CHECK_HIP(rocprim::select(nullptr, temp_storage_size, input_data, flag_data, output_data,
217 nb_out_ptr, nb_item, stream));
218
219 s._allocateTemporaryStorage(temp_storage_size);
220 nb_out_ptr = s._getDeviceNbOutPointer();
221
222 ARCANE_CHECK_HIP(rocprim::select(s.m_algo_storage.address(), temp_storage_size, input_data, flag_data, output_data,
223 nb_out_ptr, nb_item, stream));
224 s._copyDeviceNbOutToHostNbOut();
225 } break;
226#endif
227#if defined(ARCANE_COMPILING_SYCL)
230 auto filter_lambda = [=](Int32 input_index) -> bool { return flag[input_index] != 0; };
233 SyclGenericFilteringImpl::apply(s, nb_item, iter2, out, filter_lambda);
234 } break;
235#endif
237 // Pas encore implémenté en multi-thread
238 [[fallthrough]];
240 Int32 index = 0;
241 for (Int32 i = 0; i < nb_item; ++i) {
242 if (flag[i] != 0) {
243 output[index] = input[i];
244 ++index;
245 }
246 }
247 s.m_host_nb_out_storage[0] = index;
248 } break;
249 default:
250 ARCANE_FATAL(getBadPolicyMessage(exec_policy));
251 }
252 }
253};
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
265{
266 public:
267
274 template <bool InPlace, typename SelectLambda, typename InputIterator, typename OutputIterator>
277 {
279 RunQueue queue = s.m_queue;
281 RunCommand command = makeCommand(queue);
282 command << trace_info;
284 launch_info.beginExecute();
285 switch (exec_policy) {
286#if defined(ARCANE_COMPILING_CUDA)
288 size_t temp_storage_size = 0;
289 cudaStream_t stream = impl::CudaUtils::toNativeStream(queue);
290 // Premier appel pour connaitre la taille pour l'allocation
291 int* nb_out_ptr = nullptr;
292 if constexpr (InPlace)
293 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(nullptr, temp_storage_size,
295 select_lambda, stream));
296 else
297 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(nullptr, temp_storage_size,
299 select_lambda, stream));
300
301 s._allocateTemporaryStorage(temp_storage_size);
302 nb_out_ptr = s._getDeviceNbOutPointer();
303 if constexpr (InPlace)
304 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(s.m_algo_storage.address(), temp_storage_size,
306 select_lambda, stream));
307 else
308 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(s.m_algo_storage.address(), temp_storage_size,
310 select_lambda, stream));
311
312 s._copyDeviceNbOutToHostNbOut();
313 } break;
314#endif
315#if defined(ARCANE_COMPILING_HIP)
317 size_t temp_storage_size = 0;
318 // Premier appel pour connaitre la taille pour l'allocation
319 hipStream_t stream = impl::HipUtils::toNativeStream(queue);
320 int* nb_out_ptr = nullptr;
321 // NOTE: il n'y a pas de version spécifique de 'select' en-place.
322 // A priori il est possible que \a input_iter et \a output_iter
323 // aient la même valeur.
324 ARCANE_CHECK_HIP(rocprim::select(nullptr, temp_storage_size, input_iter, output_iter,
325 nb_out_ptr, nb_item, select_lambda, stream));
326 s._allocateTemporaryStorage(temp_storage_size);
327 nb_out_ptr = s._getDeviceNbOutPointer();
328 ARCANE_CHECK_HIP(rocprim::select(s.m_algo_storage.address(), temp_storage_size, input_iter, output_iter,
330 s._copyDeviceNbOutToHostNbOut();
331 } break;
332#endif
333#if defined(ARCANE_COMPILING_SYCL)
335 SyclGenericFilteringImpl::apply(s, nb_item, input_iter, output_iter, select_lambda);
336 } break;
337#endif
339 if (nb_item > 500) {
342 s.m_host_nb_out_storage[0] = v;
343 break;
344 }
345 [[fallthrough]];
347 Int32 index = 0;
348 for (Int32 i = 0; i < nb_item; ++i) {
351 ++index;
352 ++output_iter;
353 }
354 ++input_iter;
355 }
356 s.m_host_nb_out_storage[0] = index;
357 } break;
358 default:
359 ARCANE_FATAL(getBadPolicyMessage(exec_policy));
360 }
361 launch_info.endExecute();
362 }
363};
364
365/*---------------------------------------------------------------------------*/
366/*---------------------------------------------------------------------------*/
367
368} // namespace Arcane::Accelerator::impl
369
370namespace Arcane::Accelerator
371{
372
373/*---------------------------------------------------------------------------*/
374/*---------------------------------------------------------------------------*/
380{
381
382 public:
383
389 ARCANE_DEPRECATED_REASON("Y2024: Use GenericFilterer(const RunQueue&) instead")
391 {
393 m_queue = *queue;
394 _allocate();
395 }
396
402 explicit GenericFilterer(const RunQueue& queue)
403 {
404 m_queue = queue;
405 _allocate();
406 }
407
408 public:
409
433 template <typename InputDataType, typename OutputDataType, typename FlagType>
435 {
436 const Int32 nb_value = input.size();
437 if (output.size() != nb_value)
438 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_value, output.size());
439 if (flag.size() != nb_value)
440 ARCANE_FATAL("Sizes are not equals: input={0} flag={1}", nb_value, flag.size());
441
442 _setCalled();
443 if (_checkEmpty(nb_value))
444 return;
447 gf.apply(*base_ptr, input, output, flag);
448 }
449
485 template <typename DataType, typename SelectLambda>
488 {
489 const Int32 nb_value = input.size();
490 if (output.size() != nb_value)
491 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_value, output.size());
492 if (input.data() == output.data())
493 ARCANE_FATAL("Input and Output are the same. Use in place overload instead");
494 _setCalled();
495 if (_checkEmpty(nb_value))
496 return;
499 gf.apply<false>(*base_ptr, nb_value, input.data(), output.data(), select_lambda, trace_info);
500 }
501
509 template <typename DataType, typename SelectLambda>
511 const TraceInfo& trace_info = TraceInfo())
512 {
513 const Int32 nb_value = input_output.size();
514 if (nb_value <= 0)
515 return;
516 _setCalled();
517 if (_checkEmpty(nb_value))
518 return;
521 gf.apply<true>(*base_ptr, nb_value, input_output.data(), input_output.data(), select_lambda, trace_info);
522 }
523
534 template <typename InputIterator, typename OutputIterator, typename SelectLambda>
537 {
538 _setCalled();
539 if (_checkEmpty(nb_value))
540 return;
544 }
545
579 template <typename SelectLambda, typename SetterLambda>
592
595 {
596 m_is_already_called = false;
597 return _nbOutputElement();
598 }
599
600 private:
601
602 bool m_is_already_called = false;
603
604 private:
605
606 void _setCalled()
607 {
608 if (m_is_already_called)
609 ARCANE_FATAL("apply() has already been called for this instance");
610 m_is_already_called = true;
611 }
612 bool _checkEmpty(Int32 nb_value)
613 {
614 if (nb_value == 0) {
616 return true;
617 }
618 return false;
619 }
620};
621
622/*---------------------------------------------------------------------------*/
623/*---------------------------------------------------------------------------*/
624
625} // namespace Arcane::Accelerator
626
627/*---------------------------------------------------------------------------*/
628/*---------------------------------------------------------------------------*/
629
630#endif
631
632/*---------------------------------------------------------------------------*/
633/*---------------------------------------------------------------------------*/
#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.
Algorithme générique de filtrage sur accélérateur.
void applyIf(Int32 nb_value, InputIterator input_iter, OutputIterator output_iter, const SelectLambda &select_lambda, const TraceInfo &trace_info=TraceInfo())
Applique un filtre.
void applyWithIndex(Int32 nb_value, const SelectLambda &select_lambda, const SetterLambda &setter_lambda, const TraceInfo &trace_info=TraceInfo())
Applique un filtre avec une sélection suivant un index.
void applyIf(SmallSpan< DataType > input_output, const SelectLambda &select_lambda, const TraceInfo &trace_info=TraceInfo())
Applique un filtre en place.
void apply(SmallSpan< const InputDataType > input, SmallSpan< OutputDataType > output, SmallSpan< const FlagType > flag)
Applique un filtre.
void applyIf(SmallSpan< const DataType > input, SmallSpan< DataType > output, const SelectLambda &select_lambda, const TraceInfo &trace_info=TraceInfo())
Applique un filtre.
Int32 nbOutputElement()
Nombre d'éléments en sortie.
GenericFilterer(const RunQueue &queue)
Créé une instance.
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:159
eExecutionPolicy executionPolicy() const
Politique d'exécution de la file.
Definition RunQueue.cc:169
Gère l'allocation interne sur le device.
Definition CommonUtils.h:95
Classe de base pour effectuer un filtrage.
DeviceStorage< int > m_device_nb_out_storage
Mémoire sur le device du nombre de valeurs filtrées.
NumArray< Int32, MDDim1 > m_host_nb_out_storage
Mémoire hôte pour le nombre de valeurs filtrées.
RunQueue m_queue
File d'exécution. Ne doit pas être nulle.
Classe pour effectuer un filtrage.
void apply(GenericFilteringBase &s, Int32 nb_item, InputIterator input_iter, OutputIterator output_iter, const SelectLambda &select_lambda, const TraceInfo &trace_info)
Applique le filtre.
Algorithmes avancée en mode multi-thread.
Object temporaire pour conserver les informations d'exécution d'une commande et regrouper les tests.
Itérateur sur une lambda pour positionner une valeur via un index.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
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.