Arcane  4.2.3.0
Documentation utilisateur
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 "arccore/common/SequentialFor.h"
18#include "arccore/common/StridedLoopRanges.h"
19#include "arccore/common/accelerator/RunCommand.h"
20#include "arccore/concurrency/ParallelFor.h"
21
22#include "arccore/accelerator/WorkGroupLoopRange.h"
23#include "arccore/accelerator/CooperativeWorkGroupLoopRange.h"
24#include "arccore/accelerator/KernelLauncher.h"
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29namespace Arcane::Accelerator::Impl
30{
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34/*!
35 * \brief Informations d'une boucle utilisant le parallélisme hiérarchique
36 * sur l'hôte.
37 */
38template <typename IndexType_>
39class HostLaunchLoopRangeBase
40{
41 public:
42
43 using IndexType = IndexType_;
44
45 public:
46
47 ARCCORE_ACCELERATOR_EXPORT
48 HostLaunchLoopRangeBase(IndexType total_size, Int32 nb_group, IndexType block_size);
49
50 public:
51
52 //! Nombre d'éléments à traiter
53 constexpr IndexType nbElement() const { return m_total_size; }
54 //! Taille d'un bloc
55 constexpr IndexType blockSize() const { return m_block_size; }
56 //! Nombre de blocs
57 constexpr Int32 nbBlock() const { return m_nb_block; }
58 //! Nombre d'éléments du dernier bloc
59 constexpr IndexType lastBlockSize() const { return m_last_block_size; }
60 //! Nombre d'éléments actifs pour le i-ème bloc
61 constexpr IndexType nbActiveItem(Int32 i) const
62 {
63 return ((i + 1) != m_nb_block) ? m_block_size : m_last_block_size;
64 }
65 //! Synchronizer de la grille (non nul uniquement en multi-thread coopératif)
67 {
68 return m_thread_grid_synchronizer;
69 }
70 void setThreadGridSynchronizer(ThreadGridSynchronizer* v)
71 {
72 m_thread_grid_synchronizer = v;
73 }
74
75 private:
76
77 //! Cette instance est gérée par arcaneParallelFor(HostLaunchLoopRange<>...)
78 ThreadGridSynchronizer* m_thread_grid_synchronizer = nullptr;
79 IndexType m_total_size = 0;
80 IndexType m_block_size = 0;
81 IndexType m_last_block_size = 0;
82 Int32 m_nb_block = 0;
83};
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88template <typename WorkGroupLoopRangeType_>
89class HostLaunchLoopRange
90: public HostLaunchLoopRangeBase<typename WorkGroupLoopRangeType_::IndexType>
91{
92 public:
93
94 using WorkGroupLoopRangeType = WorkGroupLoopRangeType_;
95 using IndexType = typename WorkGroupLoopRangeType_::IndexType;
96 using BaseClass = HostLaunchLoopRangeBase<typename WorkGroupLoopRangeType_::IndexType>;
97
98 public:
99
100 explicit HostLaunchLoopRange(const WorkGroupLoopRangeType& bounds)
101 : BaseClass(bounds.nbElement(), bounds.nbBlock(), bounds.blockSize())
102 {
103 }
104};
105
106/*---------------------------------------------------------------------------*/
107/*---------------------------------------------------------------------------*/
108
110{
111 public:
112
113#if defined(ARCCORE_COMPILING_CUDA_OR_HIP)
114
115 template <typename IndexType_> static constexpr ARCCORE_HOST_DEVICE WorkGroupLoopContext<IndexType_>
116 build(const WorkGroupLoopRange<IndexType_>& loop_range)
117 {
118 return WorkGroupLoopContext<IndexType_>(loop_range.nbElement());
119 }
120
121 template <typename IndexType_> static constexpr ARCCORE_HOST_DEVICE CooperativeWorkGroupLoopContext<IndexType_>
122 build(const CooperativeWorkGroupLoopRange<IndexType_>& loop_range)
123 {
125 }
126
127#endif
128
129#if defined(ARCCORE_COMPILING_SYCL)
130
131 template <typename IndexType_> static SyclWorkGroupLoopContext<IndexType_>
132 build(const WorkGroupLoopRange<IndexType_>& loop_range, sycl::nd_item<1> id)
133 {
134 return SyclWorkGroupLoopContext<IndexType_>(id, loop_range.nbElement());
135 }
136
137 template <typename IndexType_> static SyclCooperativeWorkGroupLoopContext<IndexType_>
138 build(const CooperativeWorkGroupLoopRange<IndexType_>& loop_range, sycl::nd_item<1> id)
139 {
141 }
142#endif
143};
144
145#if defined(ARCCORE_COMPILING_SYCL)
146
147// Pour indiquer qu'il faut toujours utiliser sycl::nd_item (et jamais sycl::id)
148// comme argument avec 'WorkGroupLoopRange.
149template <typename IndexType_>
151: public std::true_type
152{
153};
154// Pour indiquer qu'il faut toujours utiliser sycl::nd_item (et jamais sycl::id)
155// comme argument avec 'CooperativeWorkGroupLoopRange.
156template <typename IndexType_>
157class IsAlwaysUseSyclNdItem<StridedLoopRanges<CooperativeWorkGroupLoopRange<IndexType_>>>
158: public std::true_type
159{
160};
161
162#endif
163
164/*---------------------------------------------------------------------------*/
165/*---------------------------------------------------------------------------*/
166
167/*!
168 * \internal
169 * \brief Classe pour exécuter en séquentiel sur l'hôte une partie de la boucle.
170 */
172{
173 public:
174
175 //! Applique le fonctor \a func sur une boucle séqentielle.
176 template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> static void
178 const Lambda& func, RemainingArgs... remaining_args)
179 {
180 using LoopIndexType = LoopBoundType::LoopIndexType;
182 const Int32 group_size = bounds.blockSize();
183 Int32 loop_index = begin_index * group_size;
184 for (Int32 i = begin_index; i < (begin_index + nb_loop); ++i) {
185 // Pour la dernière itération de la boucle, le nombre d'éléments actifs peut-être
186 // inférieur à la taille d'un groupe si \a total_nb_element n'est pas
187 // un multiple de \a group_size.
188 Int32 nb_active = bounds.nbActiveItem(i);
189 LoopIndexType li(loop_index, i, group_size, nb_active, bounds.nbElement(), bounds.nbBlock(), bounds.threadGridSynchronizer());
190 func(li, remaining_args...);
191 loop_index += group_size;
192 }
193
195 }
196};
197
198/*---------------------------------------------------------------------------*/
199/*---------------------------------------------------------------------------*/
200
201#if defined(ARCCORE_COMPILING_CUDA_OR_HIP)
202
203// On utilise 'Argument dependent lookup' pour trouver 'arcaneGetLoopIndexCudaHip'
204template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> __global__ static void
205doHierarchicalLaunchCudaHip(LoopBoundType bounds, Lambda func, RemainingArgs... remaining_args)
206{
207 Int32 i = blockDim.x * blockIdx.x + threadIdx.x;
208
210 // TODO: regarder s'il faut faire ce test
211 if (i < bounds.nbOriginalElement()) {
212 func(WorkGroupLoopContextBuilder::build(bounds.originalLoop()), remaining_args...);
213 }
215};
216
217#endif
218
219#if defined(ARCCORE_COMPILING_SYCL)
220
221template <typename LoopBoundType, typename Lambda, typename... RemainingArgs>
222class doHierarchicalLaunchSycl
223{
224 public:
225
226 void operator()(sycl::nd_item<1> x, SmallSpan<std::byte> shared_memory,
227 LoopBoundType bounds, Lambda func,
228 RemainingArgs... remaining_args) const
229 {
230 Int32 i = static_cast<Int32>(x.get_global_id(0));
231 SyclKernelRemainingArgsHelper::applyAtBegin(x, shared_memory, remaining_args...);
232 // TODO: regarder s'il faut faire ce test
233 if (i < bounds.nbOriginalElement()) {
234 func(WorkGroupLoopContextBuilder::build(bounds.originalLoop(), x), remaining_args...);
235 }
236 SyclKernelRemainingArgsHelper::applyAtEnd(x, shared_memory, remaining_args...);
237 }
238};
239
240#endif
241
242/*---------------------------------------------------------------------------*/
243/*---------------------------------------------------------------------------*/
244/*!
245 * \brief Applique la lambda \a func sur une boucle \a bounds.
246 *
247 * La lambda \a func est appliqué à la commande \a command.
248 * \a bound est le type de la boucle. Les types supportés sont:
249 *
250 * - WorkGroupLoopRange
251 * - CooperativeWorkGroupLoopRange
252 *
253 * Les arguments supplémentaires \a other_args sont utilisés pour supporter
254 * des fonctionnalités telles que les réductions (ReducerSum2, ReducerMax2, ...)
255 * ou la gestion de la mémoire locale (via LocalMemory).
256 */
257template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
258_doHierarchicalLaunch(RunCommand& command, LoopBoundType bounds,
259 const Lambda& func, const RemainingArgs&... other_args)
260{
261 Int64 nb_orig_element = bounds.nbElement();
262 if (nb_orig_element == 0)
263 return;
264 const eExecutionPolicy exec_policy = command.executionPolicy();
265 // En mode coopératif, il faut toujours appeler setBlockSize()
266 // pour être certain que la taille de bloc est cohérente sur l'hôte
267 // (en séquentiel, il ne faut qu'un seul bloc dans ce cas).
268 if ((bounds.blockSize() == 0) || bounds.isCooperativeLaunch())
269 bounds.setBlockSize(command);
270 using TrueLoopBoundType = StridedLoopRanges<LoopBoundType>;
271 TrueLoopBoundType bounds2(bounds);
272 if (isAcceleratorPolicy(exec_policy)) {
273 command.addNbThreadPerBlock(bounds.blockSize());
274 bounds2.setNbStride(command.nbStride());
275 }
276
277 using HostLoopBoundType = HostLaunchLoopRange<LoopBoundType>;
278
279 Impl::RunCommandLaunchInfo launch_info(command, bounds2.strideValue(), bounds.isCooperativeLaunch());
280 launch_info.beginExecute();
281 switch (exec_policy) {
283 ARCCORE_KERNEL_CUDA_FUNC((Impl::doHierarchicalLaunchCudaHip<TrueLoopBoundType, Lambda, RemainingArgs...>),
284 launch_info, func, bounds2, other_args...);
285 break;
287 ARCCORE_KERNEL_HIP_FUNC((Impl::doHierarchicalLaunchCudaHip<TrueLoopBoundType, Lambda, RemainingArgs...>),
288 launch_info, func, bounds2, other_args...);
289 break;
291 ARCCORE_KERNEL_SYCL_FUNC((Impl::doHierarchicalLaunchSycl<TrueLoopBoundType, Lambda, RemainingArgs...>{}),
292 launch_info, func, bounds2, other_args...);
293 break;
295 HostLoopBoundType host_bounds(bounds);
296 arccoreSequentialFor(host_bounds, func, other_args...);
297 } break;
299 HostLoopBoundType host_bounds(bounds);
300 arccoreParallelFor(host_bounds, launch_info.loopRunInfo(), func, other_args...);
301 } break;
302 default:
303 ARCCORE_FATAL("Invalid execution policy '{0}'", exec_policy);
304 }
305 launch_info.endExecute();
306}
307
308/*---------------------------------------------------------------------------*/
309/*---------------------------------------------------------------------------*/
310/*!
311 * \brief Classe pour conserver les arguments d'une RunCommand.
312 */
313template <typename LoopBoundType, typename... RemainingArgs>
314class ExtendedLaunchRunCommand
315{
316 public:
317
318 ExtendedLaunchRunCommand(RunCommand& command, const LoopBoundType& bounds)
319 : m_command(command)
320 , m_bounds(bounds)
321 {
322 }
323 ExtendedLaunchRunCommand(RunCommand& command, const LoopBoundType& bounds, const std::tuple<RemainingArgs...>& args)
324 : m_command(command)
325 , m_bounds(bounds)
326 , m_remaining_args(args)
327 {
328 }
329 RunCommand& m_command;
330 LoopBoundType m_bounds;
331 std::tuple<RemainingArgs...> m_remaining_args;
332};
333
334/*---------------------------------------------------------------------------*/
335/*---------------------------------------------------------------------------*/
336/*!
337 * \brief Classe pour gérer le lancement d'un noyau de calcul hiérarchique.
338 */
339template <typename LoopBoundType, typename... RemainingArgs>
340class ExtendedLaunchLoop
341{
342 public:
343
344 ExtendedLaunchLoop(const LoopBoundType& bounds, RemainingArgs... args)
345 : m_bounds(bounds)
346 , m_remaining_args(args...)
347 {
348 }
349 LoopBoundType m_bounds;
350 std::tuple<RemainingArgs...> m_remaining_args;
351};
352
353/*---------------------------------------------------------------------------*/
354/*---------------------------------------------------------------------------*/
355
356template <typename LoopBoundType, typename... RemainingArgs> auto
357makeLaunch(const LoopBoundType& bounds, RemainingArgs... args)
358-> ExtendedLaunchLoop<LoopBoundType, RemainingArgs...>
359{
360 return ExtendedLaunchLoop<LoopBoundType, RemainingArgs...>(bounds, args...);
361}
362
363/*---------------------------------------------------------------------------*/
364/*---------------------------------------------------------------------------*/
365
366template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
367operator<<(ExtendedLaunchRunCommand<LoopBoundType, RemainingArgs...>&& nr, const Lambda& f)
368{
369 if constexpr (sizeof...(RemainingArgs) > 0) {
370 std::apply([&](auto... vs) { _doHierarchicalLaunch(nr.m_command, nr.m_bounds, f, vs...); }, nr.m_remaining_args);
371 }
372 else {
373 _doHierarchicalLaunch(nr.m_command, nr.m_bounds, f);
374 }
375}
376
377/*---------------------------------------------------------------------------*/
378/*---------------------------------------------------------------------------*/
379/*!
380 * \internal
381 * \brief Applique le fonctor \a func sur une boucle séqentielle.
382 */
383template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
384arccoreSequentialFor(HostLaunchLoopRange<LoopBoundType> bounds, const Lambda& func, const RemainingArgs&... remaining_args)
385{
386 WorkGroupSequentialForHelper::apply(0, bounds.nbBlock(), bounds, func, remaining_args...);
387}
388
389/*---------------------------------------------------------------------------*/
390/*---------------------------------------------------------------------------*/
391/*!
392 * \internal
393 * \brief Applique le fonctor \a func sur une boucle parallèle.
394 */
395template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
396arccoreParallelFor(HostLaunchLoopRange<LoopBoundType> bounds, ForLoopRunInfo run_info,
397 const Lambda& func, const RemainingArgs&... remaining_args)
398{
399 Int32 nb_thread = run_info.options().value().maxThread();
400 ThreadGridSynchronizer grid_sync(nb_thread);
401 bounds.setThreadGridSynchronizer(&grid_sync);
402 auto sub_func = [=](Int32 begin_index, Int32 nb_loop) {
403 Impl::WorkGroupSequentialForHelper::apply(begin_index, nb_loop, bounds, func, remaining_args...);
404 };
405 ::Arcane::arccoreParallelFor(0, bounds.nbBlock(), run_info, sub_func);
406}
407
408/*---------------------------------------------------------------------------*/
409/*---------------------------------------------------------------------------*/
410
411} // namespace Arcane::Accelerator::Impl
412
413/*---------------------------------------------------------------------------*/
414/*---------------------------------------------------------------------------*/
415
416#endif
417
418/*---------------------------------------------------------------------------*/
419/*---------------------------------------------------------------------------*/
#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 IndexType nbActiveItem(Int32 i) const
Nombre d'éléments actifs pour le i-ème bloc.
ThreadGridSynchronizer * threadGridSynchronizer() const
Synchronizer de la grille (non nul uniquement en multi-thread coopératif).
constexpr IndexType nbElement() const
Nombre d'éléments à traiter.
constexpr IndexType lastBlockSize() const
Nombre d'éléments du dernier bloc.
constexpr IndexType blockSize() const
Taille d'un bloc.
constexpr Int32 nbBlock() const
Nombre de blocs.
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.
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.
void arccoreParallelFor(const ComplexForLoopRanges< RankValue, IndexType_ > &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:86
std::int64_t Int64
Type entier signé sur 64 bits.
std::int32_t Int32
Type entier signé sur 32 bits.