12#ifndef ARCANE_ACCELERATOR_GENERICFILTERER_H
13#define ARCANE_ACCELERATOR_GENERICFILTERER_H
17#include "arcane/utils/ArrayView.h"
18#include "arcane/utils/FatalErrorException.h"
19#include "arcane/utils/NumArray.h"
20#include "arcane/utils/TraceInfo.h"
22#include "arcane/accelerator/core/RunQueue.h"
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"
34namespace Arcane::Accelerator::impl
46class ARCANE_ACCELERATOR_EXPORT GenericFilteringBase
48 template <
typename DataType,
typename FlagType,
typename OutputDataType>
49 friend class GenericFilteringFlag;
50 friend class GenericFilteringIf;
51 friend class SyclGenericFilteringImpl;
58 GenericFilteringBase();
62 Int32 _nbOutputElement();
64 void _allocateTemporaryStorage(
size_t size);
65 int* _getDeviceNbOutPointer();
66 void _copyDeviceNbOutToHostNbOut();
68 bool _checkEmpty(
Int32 nb_value);
96#if defined(ARCANE_COMPILING_SYCL)
98class SyclGenericFilteringImpl
102 template <
typename SelectLambda,
typename InputIterator,
typename OutputIterator>
104 OutputIterator output_iter, SelectLambda select_lambda)
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);
112 Int32 nb_output = out_iter - output_iter;
124 in_scan_data[i] = select_lambda(input_iter[i]) ? 1 : 0;
128 SyclScanner<
false ,
Int32, ScannerSumOperator<Int32>> scanner;
129 scanner.doScan(queue, in_scan_data, out_scan_data, 0);
131 Int32 nb_output = out_scan_data[nb_item - 1];
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 ";
145 out_copy.
resize(nb_output);
146 auto out_copy_view = out_copy.
to1DSpan();
152 if (in_scan_data[i] == 1)
153 out_copy_view[out_scan_data[i] - 1] = input_iter[i];
161 output_iter[i] = out_copy_view[i];
181template <
typename DataType,
typename FlagType,
typename OutputDataType>
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();
198 switch (exec_policy) {
199#if defined(ARCANE_COMPILING_CUDA)
201 size_t temp_storage_size = 0;
202 cudaStream_t stream = AcceleratorUtils::toCudaNativeStream(queue);
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));
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();
215#if defined(ARCANE_COMPILING_HIP)
217 size_t temp_storage_size = 0;
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));
224 s._allocateTemporaryStorage(temp_storage_size);
225 nb_out_ptr = s._getDeviceNbOutPointer();
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();
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);
246 for (
Int32 i = 0; i < nb_item; ++i) {
248 output[index] = input[i];
279 template <
bool InPlace,
typename SelectLambda,
typename InputIterator,
typename OutputIterator>
281 const SelectLambda& select_lambda,
const TraceInfo& trace_info)
287 command << trace_info;
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);
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));
302 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(
nullptr, temp_storage_size,
303 input_iter, output_iter, nb_out_ptr, nb_item,
304 select_lambda, stream));
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));
313 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(s.m_algo_storage.address(), temp_storage_size,
314 input_iter, output_iter, nb_out_ptr, nb_item,
315 select_lambda, stream));
317 s._copyDeviceNbOutToHostNbOut();
320#if defined(ARCANE_COMPILING_HIP)
322 size_t temp_storage_size = 0;
324 hipStream_t stream = impl::HipUtils::toNativeStream(queue);
325 int* nb_out_ptr =
nullptr;
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();
338#if defined(ARCANE_COMPILING_SYCL)
340 SyclGenericFilteringImpl::apply(s, nb_item, input_iter, output_iter, select_lambda);
346 Int32 v = scanner.doFilter<InPlace>(launch_info.
loopRunInfo(), nb_item, input_iter, output_iter, select_lambda);
353 for (
Int32 i = 0; i < nb_item; ++i) {
354 if (select_lambda(*input_iter)) {
355 *output_iter = *input_iter;
394 ARCANE_DEPRECATED_REASON(
"Y2024: Use GenericFilterer(const RunQueue&) instead")
438 template <
typename InputDataType,
typename OutputDataType,
typename FlagType>
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());
447 if (_checkEmpty(nb_value))
452 gf.apply(*base_ptr, input, output, flag);
490 template <
typename DataType,
typename SelectLambda>
495 if (output.
size() != nb_value)
496 ARCANE_FATAL(
"Sizes are not equals: input={0} output={1}", nb_value, output.
size());
498 ARCANE_FATAL(
"Input and Output are the same. Use in place overload instead");
499 if (_checkEmpty(nb_value))
504 gf.
apply<
false>(*base_ptr, nb_value, input.
data(), output.
data(), select_lambda, trace_info);
514 template <
typename DataType,
typename SelectLambda>
518 const Int32 nb_value = input_output.
size();
519 if (_checkEmpty(nb_value))
524 gf.
apply<
true>(*base_ptr, nb_value, input_output.
data(), input_output.
data(), select_lambda, trace_info);
537 template <
typename InputIterator,
typename OutputIterator,
typename SelectLambda>
538 void applyIf(
Int32 nb_value, InputIterator input_iter, OutputIterator output_iter,
541 if (_checkEmpty(nb_value))
546 gf.
apply<
false>(*base_ptr, nb_value, input_iter, output_iter, select_lambda, trace_info);
582 template <
typename SelectLambda,
typename SetterLambda>
586 if (_checkEmpty(nb_value))
593 gf.
apply<
false>(*base_ptr, nb_value, input_iter, out, select_lambda, trace_info);
599 return _nbOutputElement();
#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.
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.
GenericFilterer(RunQueue *queue)
Créé une instance.
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.
eExecutionPolicy executionPolicy() const
Politique d'exécution de la file.
Gère l'allocation interne sur le device pour un type donné.
Gère l'allocation interne sur le device.
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.
bool m_is_already_called
Indique si un appel est en cours.
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.
bool m_use_direct_host_storage
Indique quelle mémoire est utilisée pour le nombre de valeurs filtrées.
Classe pour effectuer un filtrage.
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.
void beginExecute()
Indique qu'on commence l'exécution de la commande.
void endExecute()
Signale la fin de l'exécution.
const ForLoopRunInfo & loopRunInfo() const
Informations d'exécution de la boucle.
Itérateur sur une lambda pour positionner une valeur via un index.
Tableaux multi-dimensionnels pour les types numériques accessibles sur accélérateurs.
Span< const DataType > to1DSpan() const
Vue 1D constante sur l'instance.
constexpr SmallSpan< DataType > to1DSmallSpan()
Vue 1D sur l'instance (uniquement si rank == 1)
void resize(Int32 dim1_size)
Modifie la taille du tableau en gardant pas les valeurs actuelles.
Vue d'un tableau d'éléments de type T.
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
constexpr __host__ __device__ pointer data() const noexcept
Pointeur sur le début de la vue.
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.