Arcane  v3.15.3.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-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/* GenericFilterer.h (C) 2000-2025 */
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();
63 void _allocate();
64 void _allocateTemporaryStorage(size_t size);
65 int* _getDeviceNbOutPointer();
66 void _copyDeviceNbOutToHostNbOut();
67 void _setCalled();
68 bool _checkEmpty(Int32 nb_value);
69
70 protected:
71
74 // Mémoire de travail pour l'algorithme de filtrage.
75 GenericDeviceStorage m_algo_storage;
87 bool m_use_direct_host_storage = true;
88
90 bool m_is_already_called = false;
91};
92
93/*---------------------------------------------------------------------------*/
94/*---------------------------------------------------------------------------*/
95
96#if defined(ARCANE_COMPILING_SYCL)
98class SyclGenericFilteringImpl
99{
100 public:
101
102 template <typename SelectLambda, typename InputIterator, typename OutputIterator>
103 static void apply(GenericFilteringBase& s, Int32 nb_item, InputIterator input_iter,
105 {
106 RunQueue queue = s.m_queue;
107 using DataType = std::iterator_traits<OutputIterator>::value_type;
108#if defined(ARCANE_USE_SCAN_ONEDPL) && defined(__INTEL_LLVM_COMPILER)
109 sycl::queue true_queue = AcceleratorUtils::toSyclNativeStream(queue);
110 auto policy = oneapi::dpl::execution::make_device_policy(true_queue);
111 auto out_iter = oneapi::dpl::copy_if(policy, input_iter, input_iter + nb_item, output_iter, select_lambda);
114#else
119 {
120 auto command = makeCommand(queue);
121 command << RUNCOMMAND_LOOP1(iter, nb_item)
122 {
123 auto [i] = iter();
124 in_scan_data[i] = select_lambda(input_iter[i]) ? 1 : 0;
125 };
126 }
127 queue.barrier();
128 SyclScanner<false /*is_exclusive*/, Int32, ScannerSumOperator<Int32>> scanner;
129 scanner.doScan(queue, in_scan_data, out_scan_data, 0);
130 // La valeur de 'out_data' pour le dernier élément (nb_item-1) contient la taille du filtre
131 Int32 nb_output = out_scan_data[nb_item - 1];
133
134 const bool do_verbose = false;
135 if (do_verbose && nb_item < 1500)
136 for (int i = 0; i < nb_item; ++i) {
137 std::cout << "out_data i=" << i << " out_data=" << out_scan_data[i]
138 << " in_data=" << in_scan_data[i] << " value=" << input_iter[i] << "\n ";
139 }
140 // Copie depuis 'out_data' vers 'in_data' les indices correspondant au filtre
141 // Comme 'output_iter' et 'input_iter' peuvent se chevaucher, il
142 // faut faire une copie intermédiaire
143 // TODO: détecter cela et ne faire la copie que si nécessaire.
144 NumArray<DataType,MDDim1> out_copy(eMemoryRessource::Device);
145 out_copy.resize(nb_output);
146 auto out_copy_view = out_copy.to1DSpan();
147 {
148 auto command = makeCommand(queue);
149 command << RUNCOMMAND_LOOP1(iter, nb_item)
150 {
151 auto [i] = iter();
152 if (in_scan_data[i] == 1)
154 };
155 }
156 {
157 auto command = makeCommand(queue);
158 command << RUNCOMMAND_LOOP1(iter, nb_output)
159 {
160 auto [i] = iter();
162 };
163 }
164 // Obligatoire à cause de 'out_copy'. On pourra le supprimer avec une
165 // allocation temporaire.
166 queue.barrier();
167#endif
168 }
169};
170#endif
171
172/*---------------------------------------------------------------------------*/
173/*---------------------------------------------------------------------------*/
181template <typename DataType, typename FlagType, typename OutputDataType>
183{
184 public:
185
188 {
189 const Int32 nb_item = input.size();
190 if (output.size() != nb_item)
191 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_item, output.size());
192 [[maybe_unused]] const DataType* input_data = input.data();
193 [[maybe_unused]] DataType* output_data = output.data();
194 [[maybe_unused]] const FlagType* flag_data = flag.data();
196 RunQueue queue = s.m_queue;
198 switch (exec_policy) {
199#if defined(ARCANE_COMPILING_CUDA)
201 size_t temp_storage_size = 0;
202 cudaStream_t stream = AcceleratorUtils::toCudaNativeStream(queue);
203 // Premier appel pour connaitre la taille pour l'allocation
204 int* nb_out_ptr = nullptr;
205 ARCANE_CHECK_CUDA(::cub::DeviceSelect::Flagged(nullptr, temp_storage_size,
206 input_data, flag_data, output_data, nb_out_ptr, nb_item, stream));
207
208 s._allocateTemporaryStorage(temp_storage_size);
209 nb_out_ptr = s._getDeviceNbOutPointer();
210 ARCANE_CHECK_CUDA(::cub::DeviceSelect::Flagged(s.m_algo_storage.address(), temp_storage_size,
211 input_data, flag_data, output_data, nb_out_ptr, nb_item, stream));
212 s._copyDeviceNbOutToHostNbOut();
213 } break;
214#endif
215#if defined(ARCANE_COMPILING_HIP)
217 size_t temp_storage_size = 0;
218 // Premier appel pour connaitre la taille pour l'allocation
219 hipStream_t stream = AcceleratorUtils::toHipNativeStream(queue);
220 int* nb_out_ptr = nullptr;
221 ARCANE_CHECK_HIP(rocprim::select(nullptr, temp_storage_size, input_data, flag_data, output_data,
222 nb_out_ptr, nb_item, stream));
223
224 s._allocateTemporaryStorage(temp_storage_size);
225 nb_out_ptr = s._getDeviceNbOutPointer();
226
227 ARCANE_CHECK_HIP(rocprim::select(s.m_algo_storage.address(), temp_storage_size, input_data, flag_data, output_data,
228 nb_out_ptr, nb_item, stream));
229 s._copyDeviceNbOutToHostNbOut();
230 } break;
231#endif
232#if defined(ARCANE_COMPILING_SYCL)
235 auto filter_lambda = [=](Int32 input_index) -> bool { return flag[input_index] != 0; };
236 auto setter_lambda = [=](Int32 input_index, Int32 output_index) { output[output_index] = input[input_index]; };
238 SyclGenericFilteringImpl::apply(s, nb_item, iter2, out, filter_lambda);
239 } break;
240#endif
242 // Pas encore implémenté en multi-thread
243 [[fallthrough]];
245 Int32 index = 0;
246 for (Int32 i = 0; i < nb_item; ++i) {
247 if (flag[i] != 0) {
248 output[index] = input[i];
249 ++index;
250 }
251 }
252 s.m_host_nb_out_storage[0] = index;
253 } break;
254 default:
255 ARCANE_FATAL(getBadPolicyMessage(exec_policy));
256 }
257 }
258};
259
260/*---------------------------------------------------------------------------*/
261/*---------------------------------------------------------------------------*/
270{
271 public:
272
279 template <bool InPlace, typename SelectLambda, typename InputIterator, typename OutputIterator>
282 {
284 RunQueue queue = s.m_queue;
286 RunCommand command = makeCommand(queue);
287 command << trace_info;
288 impl::RunCommandLaunchInfo launch_info(command, nb_item);
289 launch_info.beginExecute();
290 switch (exec_policy) {
291#if defined(ARCANE_COMPILING_CUDA)
293 size_t temp_storage_size = 0;
294 cudaStream_t stream = impl::CudaUtils::toNativeStream(queue);
295 // Premier appel pour connaitre la taille pour l'allocation
296 int* nb_out_ptr = nullptr;
297 if constexpr (InPlace)
298 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(nullptr, temp_storage_size,
299 input_iter, nb_out_ptr, nb_item,
300 select_lambda, stream));
301 else
302 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(nullptr, temp_storage_size,
304 select_lambda, stream));
305
306 s._allocateTemporaryStorage(temp_storage_size);
307 nb_out_ptr = s._getDeviceNbOutPointer();
308 if constexpr (InPlace)
309 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(s.m_algo_storage.address(), temp_storage_size,
310 input_iter, nb_out_ptr, nb_item,
311 select_lambda, stream));
312 else
313 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(s.m_algo_storage.address(), temp_storage_size,
315 select_lambda, stream));
316
317 s._copyDeviceNbOutToHostNbOut();
318 } break;
319#endif
320#if defined(ARCANE_COMPILING_HIP)
322 size_t temp_storage_size = 0;
323 // Premier appel pour connaitre la taille pour l'allocation
324 hipStream_t stream = impl::HipUtils::toNativeStream(queue);
325 int* nb_out_ptr = nullptr;
326 // NOTE: il n'y a pas de version spécifique de 'select' en-place.
327 // A priori il est possible que \a input_iter et \a output_iter
328 // aient la même valeur.
329 ARCANE_CHECK_HIP(rocprim::select(nullptr, temp_storage_size, input_iter, output_iter,
330 nb_out_ptr, nb_item, select_lambda, stream));
331 s._allocateTemporaryStorage(temp_storage_size);
332 nb_out_ptr = s._getDeviceNbOutPointer();
333 ARCANE_CHECK_HIP(rocprim::select(s.m_algo_storage.address(), temp_storage_size, input_iter, output_iter,
334 nb_out_ptr, nb_item, select_lambda, 0));
335 s._copyDeviceNbOutToHostNbOut();
336 } break;
337#endif
338#if defined(ARCANE_COMPILING_SYCL)
340 SyclGenericFilteringImpl::apply(s, nb_item, input_iter, output_iter, select_lambda);
341 } break;
342#endif
344 if (nb_item > 500) {
346 Int32 v = scanner.doFilter<InPlace>(launch_info.loopRunInfo(), nb_item, input_iter, output_iter, select_lambda);
347 s.m_host_nb_out_storage[0] = v;
348 break;
349 }
350 [[fallthrough]];
352 Int32 index = 0;
353 for (Int32 i = 0; i < nb_item; ++i) {
356 ++index;
357 ++output_iter;
358 }
359 ++input_iter;
360 }
361 s.m_host_nb_out_storage[0] = index;
362 } break;
363 default:
364 ARCANE_FATAL(getBadPolicyMessage(exec_policy));
365 }
366 launch_info.endExecute();
367 }
368};
369
370/*---------------------------------------------------------------------------*/
371/*---------------------------------------------------------------------------*/
372
373} // namespace Arcane::Accelerator::impl
374
375namespace Arcane::Accelerator
376{
377
378/*---------------------------------------------------------------------------*/
379/*---------------------------------------------------------------------------*/
385{
386
387 public:
388
394 ARCANE_DEPRECATED_REASON("Y2024: Use GenericFilterer(const RunQueue&) instead")
396 {
398 m_queue = *queue;
399 _allocate();
400 }
401
407 explicit GenericFilterer(const RunQueue& queue)
408 {
409 m_queue = queue;
410 _allocate();
411 }
412
413 public:
414
438 template <typename InputDataType, typename OutputDataType, typename FlagType>
440 {
441 const Int32 nb_value = input.size();
442 if (output.size() != nb_value)
443 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_value, output.size());
444 if (flag.size() != nb_value)
445 ARCANE_FATAL("Sizes are not equals: input={0} flag={1}", nb_value, flag.size());
446
447 if (_checkEmpty(nb_value))
448 return;
449 _setCalled();
452 gf.apply(*base_ptr, input, output, flag);
453 }
454
490 template <typename DataType, typename SelectLambda>
493 {
494 const Int32 nb_value = input.size();
495 if (output.size() != nb_value)
496 ARCANE_FATAL("Sizes are not equals: input={0} output={1}", nb_value, output.size());
497 if (input.data() == output.data())
498 ARCANE_FATAL("Input and Output are the same. Use in place overload instead");
499 if (_checkEmpty(nb_value))
500 return;
501 _setCalled();
504 gf.apply<false>(*base_ptr, nb_value, input.data(), output.data(), select_lambda, trace_info);
505 }
506
514 template <typename DataType, typename SelectLambda>
516 const TraceInfo& trace_info = TraceInfo())
517 {
518 const Int32 nb_value = input_output.size();
519 if (_checkEmpty(nb_value))
520 return;
521 _setCalled();
524 gf.apply<true>(*base_ptr, nb_value, input_output.data(), input_output.data(), select_lambda, trace_info);
525 }
526
537 template <typename InputIterator, typename OutputIterator, typename SelectLambda>
540 {
541 if (_checkEmpty(nb_value))
542 return;
543 _setCalled();
547 }
548
582 template <typename SelectLambda, typename SetterLambda>
595
598 {
599 return _nbOutputElement();
600 }
601};
602
603/*---------------------------------------------------------------------------*/
604/*---------------------------------------------------------------------------*/
605
606} // namespace Arcane::Accelerator
607
608/*---------------------------------------------------------------------------*/
609/*---------------------------------------------------------------------------*/
610
611#endif
612
613/*---------------------------------------------------------------------------*/
614/*---------------------------------------------------------------------------*/
#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.