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
48 template <
typename DataType,
typename FlagType,
typename OutputDataType>
51 friend class SyclGenericFilteringImpl;
62 Int32 _nbOutputElement()
const;
64 void _allocateTemporaryStorage(
size_t size);
65 int* _getDeviceNbOutPointer();
66 void _copyDeviceNbOutToHostNbOut();
85 bool m_use_direct_host_storage =
true;
91#if defined(ARCANE_COMPILING_SYCL)
93class SyclGenericFilteringImpl
97 template <
typename SelectLambda,
typename InputIterator,
typename OutputIterator>
99 OutputIterator output_iter, SelectLambda select_lambda)
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);
107 Int32 nb_output = out_iter - output_iter;
119 in_scan_data[i] = select_lambda(input_iter[i]) ? 1 : 0;
123 SyclScanner<
false ,
Int32, ScannerSumOperator<Int32>> scanner;
124 scanner.doScan(queue, in_scan_data, out_scan_data, 0);
126 Int32 nb_output = out_scan_data[nb_item - 1];
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 ";
140 out_copy.
resize(nb_output);
141 auto out_copy_view = out_copy.
to1DSpan();
147 if (in_scan_data[i] == 1)
148 out_copy_view[out_scan_data[i] - 1] = input_iter[i];
156 output_iter[i] = out_copy_view[i];
176template <
typename DataType,
typename FlagType,
typename OutputDataType>
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();
193 switch (exec_policy) {
194#if defined(ARCANE_COMPILING_CUDA)
196 size_t temp_storage_size = 0;
197 cudaStream_t stream = AcceleratorUtils::toCudaNativeStream(queue);
199 int* nb_out_ptr =
nullptr;
200 ARCANE_CHECK_CUDA(::cub::DeviceSelect::Flagged(
nullptr, temp_storage_size,
201 input_data, flag_data, output_data, nb_out_ptr, nb_item, stream));
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,
206 input_data, flag_data, output_data, nb_out_ptr, nb_item, stream));
207 s._copyDeviceNbOutToHostNbOut();
210#if defined(ARCANE_COMPILING_HIP)
212 size_t temp_storage_size = 0;
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));
219 s._allocateTemporaryStorage(temp_storage_size);
220 nb_out_ptr = s._getDeviceNbOutPointer();
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();
227#if defined(ARCANE_COMPILING_SYCL)
230 auto filter_lambda = [=](
Int32 input_index) ->
bool {
return flag[input_index] != 0; };
231 auto setter_lambda = [=](
Int32 input_index,
Int32 output_index) { output[output_index] = input[input_index]; };
233 SyclGenericFilteringImpl::apply(s, nb_item, iter2, out, filter_lambda);
241 for (
Int32 i = 0; i < nb_item; ++i) {
243 output[index] = input[i];
274 template <
bool InPlace,
typename SelectLambda,
typename InputIterator,
typename OutputIterator>
276 const SelectLambda& select_lambda,
const TraceInfo& trace_info)
282 command << trace_info;
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);
291 int* nb_out_ptr =
nullptr;
292 if constexpr (InPlace)
293 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(
nullptr, temp_storage_size,
294 input_iter, nb_out_ptr, nb_item,
295 select_lambda, stream));
297 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(
nullptr, temp_storage_size,
298 input_iter, output_iter, nb_out_ptr, nb_item,
299 select_lambda, stream));
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,
305 input_iter, nb_out_ptr, nb_item,
306 select_lambda, stream));
308 ARCANE_CHECK_CUDA(::cub::DeviceSelect::If(s.m_algo_storage.address(), temp_storage_size,
309 input_iter, output_iter, nb_out_ptr, nb_item,
310 select_lambda, stream));
312 s._copyDeviceNbOutToHostNbOut();
315#if defined(ARCANE_COMPILING_HIP)
317 size_t temp_storage_size = 0;
319 hipStream_t stream = impl::HipUtils::toNativeStream(queue);
320 int* nb_out_ptr =
nullptr;
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,
329 nb_out_ptr, nb_item, select_lambda, 0));
330 s._copyDeviceNbOutToHostNbOut();
333#if defined(ARCANE_COMPILING_SYCL)
335 SyclGenericFilteringImpl::apply(s, nb_item, input_iter, output_iter, select_lambda);
341 Int32 v = scanner.doFilter<InPlace>(launch_info.
loopRunInfo(), nb_item, input_iter, output_iter, select_lambda);
348 for (
Int32 i = 0; i < nb_item; ++i) {
349 if (select_lambda(*input_iter)) {
350 *output_iter = *input_iter;
389 ARCANE_DEPRECATED_REASON(
"Y2024: Use GenericFilterer(const RunQueue&) instead")
433 template <
typename InputDataType,
typename OutputDataType,
typename FlagType>
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());
443 if (_checkEmpty(nb_value))
447 gf.apply(*base_ptr, input, output, flag);
485 template <
typename DataType,
typename SelectLambda>
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());
493 ARCANE_FATAL(
"Input and Output are the same. Use in place overload instead");
495 if (_checkEmpty(nb_value))
499 gf.
apply<
false>(*base_ptr, nb_value, input.
data(), output.
data(), select_lambda, trace_info);
509 template <
typename DataType,
typename SelectLambda>
513 const Int32 nb_value = input_output.
size();
517 if (_checkEmpty(nb_value))
521 gf.
apply<
true>(*base_ptr, nb_value, input_output.
data(), input_output.
data(), select_lambda, trace_info);
534 template <
typename InputIterator,
typename OutputIterator,
typename SelectLambda>
535 void applyIf(Int32 nb_value, InputIterator input_iter, OutputIterator output_iter,
539 if (_checkEmpty(nb_value))
543 gf.
apply<
false>(*base_ptr, nb_value, input_iter, output_iter, select_lambda, trace_info);
579 template <
typename SelectLambda,
typename SetterLambda>
584 if (_checkEmpty(nb_value))
590 gf.
apply<
false>(*base_ptr, nb_value, input_iter, out, select_lambda, trace_info);
596 m_is_already_called =
false;
597 return _nbOutputElement();
602 bool m_is_already_called =
false;
608 if (m_is_already_called)
609 ARCANE_FATAL(
"apply() has already been called for this instance");
610 m_is_already_called =
true;
612 bool _checkEmpty(Int32 nb_value)
#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.
eExecutionPolicy executionPolicy() const
Politique d'exécution de la file.
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.
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.
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.