Arcane  v4.1.4.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
RunCommandLaunchImpl.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 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/* RunCommandLaunchImpl.h (C) 2000-2026 */
9/* */
10/* Implémentation d'une RunCommand pour le parallélisme hiérarchique. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ACCELERATOR_RUNCOMMANDLAUNCHIMPL_H
13#define ARCCORE_ACCELERATOR_RUNCOMMANDLAUNCHIMPL_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "AcceleratorGlobal.h"
18#include "arccore/common/SequentialFor.h"
19#include "arccore/common/StridedLoopRanges.h"
20#include "arccore/common/accelerator/RunCommand.h"
21#include "arccore/concurrency/ParallelFor.h"
22
23#include "arccore/accelerator/WorkGroupLoopRange.h"
24#include "arccore/accelerator/CooperativeWorkGroupLoopRange.h"
25#include "arccore/accelerator/KernelLauncher.h"
26
27/*---------------------------------------------------------------------------*/
28/*---------------------------------------------------------------------------*/
29
30namespace Arcane::Accelerator::Impl
31{
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
39template <typename IndexType_>
40class HostLaunchLoopRangeBase
41{
42 public:
43
44 using IndexType = IndexType_;
45
46 public:
47
48 ARCCORE_ACCELERATOR_EXPORT
49 HostLaunchLoopRangeBase(IndexType total_size, Int32 nb_group, Int32 block_size);
50
51 public:
52
54 constexpr IndexType nbElement() const { return m_total_size; }
56 constexpr Int32 blockSize() const { return m_block_size; }
58 constexpr Int32 nbBlock() const { return m_nb_block; }
60 constexpr Int32 lastBlockSize() const { return m_last_block_size; }
62 constexpr Int32 nbActiveItem(Int32 i) const
63 {
64 return ((i + 1) != m_nb_block) ? m_block_size : m_last_block_size;
65 }
66
67 private:
68
69 IndexType m_total_size = 0;
70 Int32 m_nb_block = 0;
71 Int32 m_block_size = 0;
72 Int32 m_last_block_size = 0;
73};
74
75/*---------------------------------------------------------------------------*/
76/*---------------------------------------------------------------------------*/
77
78template <typename WorkGroupLoopRangeType_>
79class HostLaunchLoopRange
80: public HostLaunchLoopRangeBase<typename WorkGroupLoopRangeType_::IndexType>
81{
82 public:
83
84 using WorkGroupLoopRangeType = WorkGroupLoopRangeType_;
85 using IndexType = typename WorkGroupLoopRangeType_::IndexType;
86 using BaseClass = HostLaunchLoopRangeBase<typename WorkGroupLoopRangeType_::IndexType>;
87
88 public:
89
90 explicit HostLaunchLoopRange(const WorkGroupLoopRangeType& bounds)
91 : BaseClass(bounds.nbElement(), bounds.nbBlock(), bounds.blockSize())
92 {
93 }
94};
95
96/*---------------------------------------------------------------------------*/
97/*---------------------------------------------------------------------------*/
98
100{
101 public:
102
103#if defined(ARCCORE_COMPILING_CUDA_OR_HIP)
104
105 template <typename IndexType_> static constexpr ARCCORE_HOST_DEVICE WorkGroupLoopContext<IndexType_>
106 build(const WorkGroupLoopRange<IndexType_>& loop_range)
107 {
108 return WorkGroupLoopContext<IndexType_>(loop_range.nbElement());
109 }
110
111 template <typename IndexType_> static constexpr ARCCORE_HOST_DEVICE CooperativeWorkGroupLoopContext<IndexType_>
112 build(const CooperativeWorkGroupLoopRange<IndexType_>& loop_range)
113 {
115 }
116
117#endif
118
119#if defined(ARCCORE_COMPILING_SYCL)
120
121 template <typename IndexType_> static SyclWorkGroupLoopContext<IndexType_>
122 build(const WorkGroupLoopRange<IndexType_>& loop_range, sycl::nd_item<1> id)
123 {
124 return SyclWorkGroupLoopContext<IndexType_>(id, loop_range.nbElement());
125 }
126
127 template <typename IndexType_> static SyclCooperativeWorkGroupLoopContext<IndexType_>
128 build(const CooperativeWorkGroupLoopRange<IndexType_>& loop_range, sycl::nd_item<1> id)
129 {
131 }
132#endif
133};
134
135#if defined(ARCCORE_COMPILING_SYCL)
136
137// Pour indiquer qu'il faut toujours utiliser sycl::nd_item (et jamais sycl::id)
138// comme argument avec 'WorkGroupLoopRange.
139template <typename IndexType_>
141: public std::true_type
142{
143};
144// Pour indiquer qu'il faut toujours utiliser sycl::nd_item (et jamais sycl::id)
145// comme argument avec 'CooperativeWorkGroupLoopRange.
146template <typename IndexType_>
147class IsAlwaysUseSyclNdItem<StridedLoopRanges<CooperativeWorkGroupLoopRange<IndexType_>>>
148: public std::true_type
149{
150};
151
152#endif
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
162{
163 public:
164
166 template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> static void
168 const Lambda& func, RemainingArgs... remaining_args)
169 {
170 using LoopIndexType = LoopBoundType::LoopIndexType;
172 const Int32 group_size = bounds.blockSize();
173 Int32 loop_index = begin_index * group_size;
174 for (Int32 i = begin_index; i < (begin_index + nb_loop); ++i) {
175 // Pour la dernière itération de la boucle, le nombre d'éléments actifs peut-être
176 // inférieur à la taille d'un groupe si \a total_nb_element n'est pas
177 // un multiple de \a group_size.
178 Int32 nb_active = bounds.nbActiveItem(i);
179 func(LoopIndexType(loop_index, i, group_size, nb_active, bounds.nbElement()), remaining_args...);
180 loop_index += group_size;
181 }
182
184 }
185};
186
187/*---------------------------------------------------------------------------*/
188/*---------------------------------------------------------------------------*/
189
190#if defined(ARCCORE_COMPILING_CUDA_OR_HIP)
191
192// On utilise 'Argument dependent lookup' pour trouver 'arcaneGetLoopIndexCudaHip'
193template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> __global__ static void
194doHierarchicalLaunchCudaHip(LoopBoundType bounds, Lambda func, RemainingArgs... remaining_args)
195{
196 // TODO: a supprimer quand il n'y aura plus les anciennes réductions
197 //auto privatizer = privatize(func);
198 //auto& body = privatizer.privateCopy();
199
200 //using LoopIndexType = LoopBoundType::LoopBoundType::LoopIndexType;
201
202 Int32 i = blockDim.x * blockIdx.x + threadIdx.x;
203
205 // TODO: regarder s'il faut faire ce test
206 if (i < bounds.nbOriginalElement()) {
207 func(WorkGroupLoopContextBuilder::build(bounds.originalLoop()), remaining_args...);
208 }
210};
211
212#endif
213
214#if defined(ARCCORE_COMPILING_SYCL)
215
216template <typename LoopBoundType, typename Lambda, typename... RemainingArgs>
217class doHierarchicalLaunchSycl
218{
219 public:
220
221 void operator()(sycl::nd_item<1> x, SmallSpan<std::byte> shared_memory,
222 LoopBoundType bounds, Lambda func,
223 RemainingArgs... remaining_args) const
224 {
225 Int32 i = static_cast<Int32>(x.get_global_id(0));
226 SyclKernelRemainingArgsHelper::applyAtBegin(x, shared_memory, remaining_args...);
227 // TODO: regarder s'il faut faire ce test
228 if (i < bounds.nbOriginalElement()) {
229 func(WorkGroupLoopContextBuilder::build(bounds.originalLoop(), x), remaining_args...);
230 }
231 SyclKernelRemainingArgsHelper::applyAtEnd(x, shared_memory, remaining_args...);
232 }
233};
234
235#endif
236
237/*---------------------------------------------------------------------------*/
238/*---------------------------------------------------------------------------*/
252template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
253_doHierarchicalLaunch(RunCommand& command, LoopBoundType bounds,
254 const Lambda& func, const RemainingArgs&... other_args)
255{
256 Int64 nb_orig_element = bounds.nbElement();
257 if (nb_orig_element == 0)
258 return;
259 const eExecutionPolicy exec_policy = command.executionPolicy();
260 // En mode coopératif, il faut toujours appeler setBlockSize()
261 // pour être certain que la taille de bloc est cohérente.
262 if ((bounds.blockSize() == 0) || bounds.isCooperativeLaunch())
263 bounds.setBlockSize(command);
264 using TrueLoopBoundType = StridedLoopRanges<LoopBoundType>;
265 TrueLoopBoundType bounds2(bounds);
266 if (isAcceleratorPolicy(exec_policy)) {
267 command.addNbThreadPerBlock(bounds.blockSize());
268 bounds2.setNbStride(command.nbStride());
269 }
270
271 using HostLoopBoundType = HostLaunchLoopRange<LoopBoundType>;
272
273 Impl::RunCommandLaunchInfo launch_info(command, bounds2.strideValue(), bounds.isCooperativeLaunch());
274 launch_info.beginExecute();
275 switch (exec_policy) {
277 ARCCORE_KERNEL_CUDA_FUNC((Impl::doHierarchicalLaunchCudaHip<TrueLoopBoundType, Lambda, RemainingArgs...>),
278 launch_info, func, bounds2, other_args...);
279 break;
281 ARCCORE_KERNEL_HIP_FUNC((Impl::doHierarchicalLaunchCudaHip<TrueLoopBoundType, Lambda, RemainingArgs...>),
282 launch_info, func, bounds2, other_args...);
283 break;
285 ARCCORE_KERNEL_SYCL_FUNC((Impl::doHierarchicalLaunchSycl<TrueLoopBoundType, Lambda, RemainingArgs...>{}),
286 launch_info, func, bounds2, other_args...);
287 break;
289 HostLoopBoundType host_bounds(bounds);
290 arccoreSequentialFor(host_bounds, func, other_args...);
291 } break;
293 HostLoopBoundType host_bounds(bounds);
294 arccoreParallelFor(host_bounds, launch_info.loopRunInfo(), func, other_args...);
295 } break;
296 default:
297 ARCCORE_FATAL("Invalid execution policy '{0}'", exec_policy);
298 }
299 launch_info.endExecute();
300}
301
302/*---------------------------------------------------------------------------*/
303/*---------------------------------------------------------------------------*/
307template <typename LoopBoundType, typename... RemainingArgs>
308class ExtendedLaunchRunCommand
309{
310 public:
311
312 ExtendedLaunchRunCommand(RunCommand& command, const LoopBoundType& bounds)
313 : m_command(command)
314 , m_bounds(bounds)
315 {
316 }
317 ExtendedLaunchRunCommand(RunCommand& command, const LoopBoundType& bounds, const std::tuple<RemainingArgs...>& args)
318 : m_command(command)
319 , m_bounds(bounds)
320 , m_remaining_args(args)
321 {
322 }
323 RunCommand& m_command;
324 LoopBoundType m_bounds;
325 std::tuple<RemainingArgs...> m_remaining_args;
326};
327
328/*---------------------------------------------------------------------------*/
329/*---------------------------------------------------------------------------*/
333template <typename LoopBoundType, typename... RemainingArgs>
334class ExtendedLaunchLoop
335{
336 public:
337
338 ExtendedLaunchLoop(const LoopBoundType& bounds, RemainingArgs... args)
339 : m_bounds(bounds)
340 , m_remaining_args(args...)
341 {
342 }
343 LoopBoundType m_bounds;
344 std::tuple<RemainingArgs...> m_remaining_args;
345};
346
347/*---------------------------------------------------------------------------*/
348/*---------------------------------------------------------------------------*/
349
350template <typename LoopBoundType, typename... RemainingArgs> auto
351makeLaunch(const LoopBoundType& bounds, RemainingArgs... args)
352-> ExtendedLaunchLoop<LoopBoundType, RemainingArgs...>
353{
354 return ExtendedLaunchLoop<LoopBoundType, RemainingArgs...>(bounds, args...);
355}
356
357/*---------------------------------------------------------------------------*/
358/*---------------------------------------------------------------------------*/
359
360template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
361operator<<(ExtendedLaunchRunCommand<LoopBoundType, RemainingArgs...>&& nr, const Lambda& f)
362{
363 if constexpr (sizeof...(RemainingArgs) > 0) {
364 std::apply([&](auto... vs) { _doHierarchicalLaunch(nr.m_command, nr.m_bounds, f, vs...); }, nr.m_remaining_args);
365 }
366 else {
367 _doHierarchicalLaunch(nr.m_command, nr.m_bounds, f);
368 }
369}
370
371/*---------------------------------------------------------------------------*/
372/*---------------------------------------------------------------------------*/
377template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
378arccoreSequentialFor(HostLaunchLoopRange<LoopBoundType> bounds, const Lambda& func, const RemainingArgs&... remaining_args)
379{
380 WorkGroupSequentialForHelper::apply(0, bounds.nbBlock(), bounds, func, remaining_args...);
381}
382
383/*---------------------------------------------------------------------------*/
384/*---------------------------------------------------------------------------*/
389template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
390arccoreParallelFor(Impl::HostLaunchLoopRange<LoopBoundType> bounds, ForLoopRunInfo run_info,
391 const Lambda& func, const RemainingArgs&... remaining_args)
392{
393 auto sub_func = [=](Int32 begin_index, Int32 nb_loop) {
394 Impl::WorkGroupSequentialForHelper::apply(begin_index, nb_loop, bounds, func, remaining_args...);
395 };
396 ::Arcane::arccoreParallelFor(0, bounds.nbBlock(), run_info, sub_func);
397}
398
399/*---------------------------------------------------------------------------*/
400/*---------------------------------------------------------------------------*/
401
402} // namespace Arcane::Accelerator::Impl
403
404/*---------------------------------------------------------------------------*/
405/*---------------------------------------------------------------------------*/
406
407#endif
408
409/*---------------------------------------------------------------------------*/
410/*---------------------------------------------------------------------------*/
#define ARCCORE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Contexte d'exécution d'une commande sur un ensemble de blocs.
Intervalle d'itération d'une boucle utilisant le parallélisme hiérarchique collaboratif.
static ARCCORE_DEVICE void applyAtEnd(Int32 index, RemainingArgs &... remaining_args)
Applique les fonctors des arguments additionnels en fin de kernel.
static ARCCORE_DEVICE void applyAtBegin(Int32 index, RemainingArgs &... remaining_args)
Applique les fonctors des arguments additionnels en début de kernel.
Classe pour gérer le lancement d'un noyau de calcul hiérarchique.
constexpr Int32 blockSize() const
Taille d'un bloc.
constexpr Int32 lastBlockSize() const
Nombre d'éléments du dernier groupe.
constexpr Int32 nbActiveItem(Int32 i) const
Nombre d'éléments actifs pour le i-ème groupe.
constexpr IndexType nbElement() const
Nombre d'éléments à traiter.
constexpr Int32 nbBlock() const
Nombre de groupes.
Template pour savoir si un type utilisé comme boucle dans les kernels nécessite toujours sycl::nb_ite...
Classe pour gérer la décomposition d'une boucle en plusieurs parties.
Classe pour exécuter en séquentiel sur l'hôte une partie de la boucle.
static void apply(Int32 begin_index, Int32 nb_loop, HostLaunchLoopRange< LoopBoundType > bounds, const Lambda &func, RemainingArgs... remaining_args)
Applique le fonctor func sur une boucle séqentielle.
Contexte d'exécution d'une commande sur un ensemble de blocs.
Intervalle d'itération d'une boucle utilisant le parallélisme hiérarchique.
static void applyAtEnd(RemainingArgs &... remaining_args)
Applique les functors des arguments additionnels à la fin de l'itération.
static void applyAtBegin(RemainingArgs &... remaining_args)
Applique les functors des arguments additionnels au début de l'itération.
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.
bool isAcceleratorPolicy(eExecutionPolicy exec_policy)
Indique si exec_policy correspond à un accélérateur.
std::int64_t Int64
Type entier signé sur 64 bits.
void arccoreParallelFor(const ComplexForLoopRanges< RankValue > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applique en concurrence la fonction lambda lambda_function sur l'intervalle d'itération donné par loo...
Definition ParallelFor.h:85
std::int32_t Int32
Type entier signé sur 32 bits.