12#ifndef ARCANE_ACCELERATOR_GENERICPARTITIONER_H
13#define ARCANE_ACCELERATOR_GENERICPARTITIONER_H
17#include "arcane/utils/ArrayView.h"
18#include "arcane/utils/FatalErrorException.h"
19#include "arcane/utils/NotImplementedException.h"
20#include "arcane/utils/NumArray.h"
22#include "arcane/accelerator/AcceleratorGlobal.h"
23#include "arcane/accelerator/core/RunQueue.h"
24#include "arcane/accelerator/CommonUtils.h"
25#include "arcane/accelerator/RunCommandLaunchInfo.h"
26#if defined(ARCANE_COMPILING_SYCL)
33namespace Arcane::Accelerator::impl
44class ARCANE_ACCELERATOR_EXPORT GenericPartitionerBase
46 friend class GenericPartitionerIf;
50 explicit GenericPartitionerBase(
const RunQueue& queue);
54 Int32 _nbFirstPart()
const;
80 template <
typename SelectLambda,
typename InputIterator,
typename OutputIterator>
87 command << trace_info;
90 switch (exec_policy) {
91#if defined(ARCANE_COMPILING_CUDA)
93 size_t temp_storage_size = 0;
94 cudaStream_t stream = Impl::CudaUtils::toNativeStream(&queue);
96 int* nb_list1_ptr =
nullptr;
97 ARCANE_CHECK_CUDA(::cub::DevicePartition::If(
nullptr, temp_storage_size,
98 input_iter, output_iter, nb_list1_ptr, nb_item,
99 select_lambda, stream));
101 s.m_algo_storage.allocate(temp_storage_size);
102 nb_list1_ptr = s.m_device_nb_list1_storage.allocate();
103 ARCANE_CHECK_CUDA(::cub::DevicePartition::If(s.m_algo_storage.address(), temp_storage_size,
104 input_iter, output_iter, nb_list1_ptr, nb_item,
105 select_lambda, stream));
106 s.m_device_nb_list1_storage.
copyToAsync(s.m_host_nb_list1_storage, queue);
109#if defined(ARCANE_COMPILING_HIP)
111 size_t temp_storage_size = 0;
113 hipStream_t stream = Impl::HipUtils::toNativeStream(&queue);
114 int* nb_list1_ptr =
nullptr;
115 ARCANE_CHECK_HIP(rocprim::partition(
nullptr, temp_storage_size, input_iter, output_iter,
116 nb_list1_ptr, nb_item, select_lambda, stream));
118 s.m_algo_storage.allocate(temp_storage_size);
119 nb_list1_ptr = s.m_device_nb_list1_storage.allocate();
121 ARCANE_CHECK_HIP(rocprim::partition(s.m_algo_storage.address(), temp_storage_size, input_iter, output_iter,
122 nb_list1_ptr, nb_item, select_lambda, stream));
123 s.m_device_nb_list1_storage.
copyToAsync(s.m_host_nb_list1_storage, queue);
126#if defined(ARCANE_COMPILING_SYCL)
128#if defined(ARCANE_HAS_ONEDPL)
139 using InputDataType =
typename InputIterator::value_type;
140 using DataType =
typename OutputIterator::value_type;
150 tmp_output[i] = input_iter[i];
153 auto tmp_select_lambda = [=](
Int32 i) {
return tmp_select[i]; };
154 sycl::queue sycl_queue = Impl::SyclUtils::toNativeStream(queue);
155 auto policy = oneapi::dpl::execution::make_device_policy(sycl_queue);
156 auto output_after = oneapi::dpl::stable_partition(policy, tmp_output.begin(), tmp_output.end(), select_lambda);
158 Int32 nb_list1 = (output_after - tmp_output.begin());
159 Int32 nb_list2 = nb_item - nb_list1;
160 s.m_host_nb_list1_storage[0] = nb_list1;
169 Int32 nb_iter2 = (nb_list2 / 2) + (nb_list2 % 2);
176 Int32 j = i - nb_list1;
177 Int32 reverse_i = (nb_item - (j + 1));
178 auto x1 = tmp_output[i];
179 auto x2 = tmp_output[reverse_i];
180 output_iter[i] = tmp_output[reverse_i];
181 output_iter[reverse_i] = tmp_output[i];
184 output_iter[i] = tmp_output[i];
197 auto saved_output_iter = output_iter;
198 auto output2_iter = output_iter + nb_item;
199 for (
Int32 i = 0; i < nb_item; ++i) {
200 auto v = *input_iter;
201 if (select_lambda(v)) {
211 Int32 nb_list1 =
static_cast<Int32>(output_iter - saved_output_iter);
212 s.m_host_nb_list1_storage[0] = nb_list1;
223 template <
typename Select1Lambda,
typename Select2Lambda,
224 typename InputIterator,
typename FirstOutputIterator,
225 typename SecondOutputIterator,
typename UnselectedIterator>
227 InputIterator input_iter,
228 FirstOutputIterator first_output_iter,
229 SecondOutputIterator second_output_iter,
230 UnselectedIterator unselected_iter,
231 const Select1Lambda& select1_lambda,
232 const Select2Lambda& select2_lambda,
238 command << trace_info;
241 switch (exec_policy) {
242#if defined(ARCANE_COMPILING_CUDA)
244 size_t temp_storage_size = 0;
245 cudaStream_t stream = Impl::CudaUtils::toNativeStream(&queue);
247 int* nb_list1_ptr =
nullptr;
248 ARCANE_CHECK_CUDA(::cub::DevicePartition::If(
nullptr, temp_storage_size,
249 input_iter, first_output_iter, second_output_iter,
250 unselected_iter, nb_list1_ptr, nb_item,
251 select1_lambda, select2_lambda, stream));
253 s.m_algo_storage.allocate(temp_storage_size);
254 nb_list1_ptr = s.m_device_nb_list1_storage.allocate();
255 ARCANE_CHECK_CUDA(::cub::DevicePartition::If(s.m_algo_storage.address(), temp_storage_size,
256 input_iter, first_output_iter, second_output_iter,
257 unselected_iter, nb_list1_ptr, nb_item,
258 select1_lambda, select2_lambda, stream));
259 s.m_device_nb_list1_storage.
copyToAsync(s.m_host_nb_list1_storage, queue);
262#if defined(ARCANE_COMPILING_HIP)
264 size_t temp_storage_size = 0;
266 hipStream_t stream = Impl::HipUtils::toNativeStream(&queue);
267 int* nb_list1_ptr =
nullptr;
268 using namespace rocprim;
269 ARCANE_CHECK_HIP(::rocprim::partition_three_way(
nullptr, temp_storage_size, input_iter, first_output_iter,
270 second_output_iter, unselected_iter,
271 nb_list1_ptr, nb_item, select1_lambda, select2_lambda, stream));
273 s.m_algo_storage.allocate(temp_storage_size);
274 nb_list1_ptr = s.m_device_nb_list1_storage.allocate();
276 ARCANE_CHECK_HIP(partition_three_way(s.m_algo_storage.address(), temp_storage_size, input_iter, first_output_iter,
277 second_output_iter, unselected_iter, nb_list1_ptr, nb_item,
278 select1_lambda, select2_lambda, stream));
279 s.m_device_nb_list1_storage.
copyToAsync(s.m_host_nb_list1_storage, queue);
282#if defined(ARCANE_COMPILING_SYCL)
294 for (
Int32 i = 0; i < nb_item; ++i) {
295 auto v = *input_iter;
296 bool is_1 = select1_lambda(v);
297 bool is_2 = select2_lambda(v);
299 *first_output_iter = v;
305 *second_output_iter = v;
306 ++second_output_iter;
310 *unselected_iter = v;
317 s.m_host_nb_list1_storage[0] = nb_first;
318 s.m_host_nb_list1_storage[1] = nb_second;
343class GenericPartitioner
348 explicit GenericPartitioner(
const RunQueue& queue)
368 template <
typename SelectLambda,
typename SetterLambda>
372 if (_checkEmpty(nb_value))
380 gf.
apply(*base_ptr, nb_value, input_iter, out, select_lambda, trace_info);
399 template <
typename InputIterator,
typename OutputIterator,
typename SelectLambda>
400 void applyIf(
Int32 nb_value, InputIterator input_iter, OutputIterator output_iter,
403 if (_checkEmpty(nb_value))
408 gf.
apply(*base_ptr, nb_value, input_iter, output_iter, select_lambda, trace_info);
428 template <
typename Setter1Lambda,
typename Setter2Lambda,
typename UnselectedSetterLambda,
429 typename Select1Lambda,
typename Select2Lambda>
431 const Setter1Lambda setter1_lambda,
432 const Setter2Lambda setter2_lambda,
433 const UnselectedSetterLambda& unselected_setter_lambda,
434 const Select1Lambda& select1_lambda,
435 const Select2Lambda& select2_lambda,
438 if (_checkEmpty(nb_value))
447 gf.
apply3(*base_ptr, nb_value, input_iter, setter1_wrapper, setter2_wrapper,
448 unselected_setter_wrapper, select1_lambda, select2_lambda, trace_info);
468 template <
typename InputIterator,
typename FirstOutputIterator,
469 typename SecondOutputIterator,
typename UnselectedIterator,
470 typename Select1Lambda,
typename Select2Lambda>
472 FirstOutputIterator first_output_iter,
473 SecondOutputIterator second_output_iter,
474 UnselectedIterator unselected_iter,
475 const Select1Lambda& select1_lambda,
476 const Select2Lambda& select2_lambda,
479 if (_checkEmpty(nb_value))
484 gf.
apply3(*base_ptr, nb_value, input_iter, first_output_iter, second_output_iter,
485 unselected_iter, select1_lambda, select2_lambda, trace_info);
493 m_is_already_called =
false;
494 return _nbFirstPart();
509 m_is_already_called =
false;
515 bool m_is_already_called =
false;
521 if (m_is_already_called)
522 ARCANE_FATAL(
"apply() has already been called for this instance");
523 m_is_already_called =
true;
525 bool _checkEmpty(
Int32 nb_value)
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#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 1D sur accélérateur avec arguments supplémentaires.
SmallSpan< const Int32 > nbParts()
Nombre d'éléments de la première et deuxième partie de la liste.
Int32 nbFirstPart()
Nombre d'éléments de la première partie de la liste.
void applyWithIndex(Int32 nb_value, const Setter1Lambda setter1_lambda, const Setter2Lambda setter2_lambda, const UnselectedSetterLambda &unselected_setter_lambda, const Select1Lambda &select1_lambda, const Select2Lambda &select2_lambda, const TraceInfo &trace_info=TraceInfo())
Effectue un partitionnement d'une liste en trois parties.
void applyIf(Int32 nb_value, InputIterator input_iter, OutputIterator output_iter, const SelectLambda &select_lambda, const TraceInfo &trace_info=TraceInfo())
Effectue un partitionnement d'une liste en deux parties.
void applyWithIndex(Int32 nb_value, const SetterLambda &setter_lambda, const SelectLambda &select_lambda, const TraceInfo &trace_info=TraceInfo())
Effectue un partitionnement d'une liste en deux parties.
void applyIf(Int32 nb_value, InputIterator input_iter, FirstOutputIterator first_output_iter, SecondOutputIterator second_output_iter, UnselectedIterator unselected_iter, const Select1Lambda &select1_lambda, const Select2Lambda &select2_lambda, const TraceInfo &trace_info=TraceInfo())
Effectue un partitionnement d'une liste en trois parties.
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.
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é.
void copyToAsync(SmallSpan< DataType > dest_ptr, const RunQueue &queue)
Copie l'instance dans dest_ptr.
Gère l'allocation interne sur le device.
Classe de base pour effectuer un filtrage.
Classe pour effectuer un partitionnement d'une liste.
void apply3(GenericPartitionerBase &s, Int32 nb_item, InputIterator input_iter, FirstOutputIterator first_output_iter, SecondOutputIterator second_output_iter, UnselectedIterator unselected_iter, const Select1Lambda &select1_lambda, const Select2Lambda &select2_lambda, const TraceInfo &trace_info=TraceInfo())
Effectue le partitionnement d'une liste en trois parties.
void apply(GenericPartitionerBase &s, Int32 nb_item, InputIterator input_iter, OutputIterator output_iter, const SelectLambda &select_lambda, const TraceInfo &trace_info=TraceInfo())
Effectue le partitionnement d'une liste en deux parties.
Itérateur sur une lambda pour positionner une valeur via un index.
Exception lorsqu'une fonction n'est pas implémentée.
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.
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.