Arcane  v4.1.5.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, IndexType block_size);
50
51 public:
52
54 constexpr IndexType nbElement() const { return m_total_size; }
56 constexpr IndexType blockSize() const { return m_block_size; }
58 constexpr Int32 nbBlock() const { return m_nb_block; }
60 constexpr IndexType lastBlockSize() const { return m_last_block_size; }
62 constexpr IndexType nbActiveItem(Int32 i) const
63 {
64 return ((i + 1) != m_nb_block) ? m_block_size : m_last_block_size;
65 }
66
71 void setThreadGridSynchronizer(ThreadGridSynchronizer* v)
72 {
74 }
75
76 private:
77
80 IndexType m_total_size = 0;
81 IndexType m_block_size = 0;
82 IndexType m_last_block_size = 0;
83 Int32 m_nb_block = 0;
84};
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
89template <typename WorkGroupLoopRangeType_>
90class HostLaunchLoopRange
91: public HostLaunchLoopRangeBase<typename WorkGroupLoopRangeType_::IndexType>
92{
93 public:
94
95 using WorkGroupLoopRangeType = WorkGroupLoopRangeType_;
96 using IndexType = typename WorkGroupLoopRangeType_::IndexType;
97 using BaseClass = HostLaunchLoopRangeBase<typename WorkGroupLoopRangeType_::IndexType>;
98
99 public:
100
101 explicit HostLaunchLoopRange(const WorkGroupLoopRangeType& bounds)
102 : BaseClass(bounds.nbElement(), bounds.nbBlock(), bounds.blockSize())
103 {
104 }
105};
106
107/*---------------------------------------------------------------------------*/
108/*---------------------------------------------------------------------------*/
109
111{
112 public:
113
114#if defined(ARCCORE_COMPILING_CUDA_OR_HIP)
115
116 template <typename IndexType_> static constexpr ARCCORE_HOST_DEVICE WorkGroupLoopContext<IndexType_>
117 build(const WorkGroupLoopRange<IndexType_>& loop_range)
118 {
119 return WorkGroupLoopContext<IndexType_>(loop_range.nbElement());
120 }
121
122 template <typename IndexType_> static constexpr ARCCORE_HOST_DEVICE CooperativeWorkGroupLoopContext<IndexType_>
123 build(const CooperativeWorkGroupLoopRange<IndexType_>& loop_range)
124 {
126 }
127
128#endif
129
130#if defined(ARCCORE_COMPILING_SYCL)
131
132 template <typename IndexType_> static SyclWorkGroupLoopContext<IndexType_>
133 build(const WorkGroupLoopRange<IndexType_>& loop_range, sycl::nd_item<1> id)
134 {
135 return SyclWorkGroupLoopContext<IndexType_>(id, loop_range.nbElement());
136 }
137
138 template <typename IndexType_> static SyclCooperativeWorkGroupLoopContext<IndexType_>
139 build(const CooperativeWorkGroupLoopRange<IndexType_>& loop_range, sycl::nd_item<1> id)
140 {
142 }
143#endif
144};
145
146#if defined(ARCCORE_COMPILING_SYCL)
147
148// Pour indiquer qu'il faut toujours utiliser sycl::nd_item (et jamais sycl::id)
149// comme argument avec 'WorkGroupLoopRange.
150template <typename IndexType_>
152: public std::true_type
153{
154};
155// Pour indiquer qu'il faut toujours utiliser sycl::nd_item (et jamais sycl::id)
156// comme argument avec 'CooperativeWorkGroupLoopRange.
157template <typename IndexType_>
158class IsAlwaysUseSyclNdItem<StridedLoopRanges<CooperativeWorkGroupLoopRange<IndexType_>>>
159: public std::true_type
160{
161};
162
163#endif
164
165/*---------------------------------------------------------------------------*/
166/*---------------------------------------------------------------------------*/
167
173{
174 public:
175
177 template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> static void
179 const Lambda& func, RemainingArgs... remaining_args)
180 {
181 using LoopIndexType = LoopBoundType::LoopIndexType;
183 const Int32 group_size = bounds.blockSize();
184 Int32 loop_index = begin_index * group_size;
185 for (Int32 i = begin_index; i < (begin_index + nb_loop); ++i) {
186 // Pour la dernière itération de la boucle, le nombre d'éléments actifs peut-être
187 // inférieur à la taille d'un groupe si \a total_nb_element n'est pas
188 // un multiple de \a group_size.
189 Int32 nb_active = bounds.nbActiveItem(i);
190 LoopIndexType li(loop_index, i, group_size, nb_active, bounds.nbElement(), bounds.nbBlock(), bounds.threadGridSynchronizer());
191 func(li, remaining_args...);
192 loop_index += group_size;
193 }
194
196 }
197};
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
202#if defined(ARCCORE_COMPILING_CUDA_OR_HIP)
203
204// On utilise 'Argument dependent lookup' pour trouver 'arcaneGetLoopIndexCudaHip'
205template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> __global__ static void
206doHierarchicalLaunchCudaHip(LoopBoundType bounds, Lambda func, RemainingArgs... remaining_args)
207{
208 Int32 i = blockDim.x * blockIdx.x + threadIdx.x;
209
211 // TODO: regarder s'il faut faire ce test
212 if (i < bounds.nbOriginalElement()) {
213 func(WorkGroupLoopContextBuilder::build(bounds.originalLoop()), remaining_args...);
214 }
216};
217
218#endif
219
220#if defined(ARCCORE_COMPILING_SYCL)
221
222template <typename LoopBoundType, typename Lambda, typename... RemainingArgs>
223class doHierarchicalLaunchSycl
224{
225 public:
226
227 void operator()(sycl::nd_item<1> x, SmallSpan<std::byte> shared_memory,
228 LoopBoundType bounds, Lambda func,
229 RemainingArgs... remaining_args) const
230 {
231 Int32 i = static_cast<Int32>(x.get_global_id(0));
232 SyclKernelRemainingArgsHelper::applyAtBegin(x, shared_memory, remaining_args...);
233 // TODO: regarder s'il faut faire ce test
234 if (i < bounds.nbOriginalElement()) {
235 func(WorkGroupLoopContextBuilder::build(bounds.originalLoop(), x), remaining_args...);
236 }
237 SyclKernelRemainingArgsHelper::applyAtEnd(x, shared_memory, remaining_args...);
238 }
239};
240
241#endif
242
243/*---------------------------------------------------------------------------*/
244/*---------------------------------------------------------------------------*/
258template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
259_doHierarchicalLaunch(RunCommand& command, LoopBoundType bounds,
260 const Lambda& func, const RemainingArgs&... other_args)
261{
262 Int64 nb_orig_element = bounds.nbElement();
263 if (nb_orig_element == 0)
264 return;
265 const eExecutionPolicy exec_policy = command.executionPolicy();
266 // En mode coopératif, il faut toujours appeler setBlockSize()
267 // pour être certain que la taille de bloc est cohérente sur l'hôte
268 // (en séquentiel, il ne faut qu'un seul bloc dans ce cas).
269 if ((bounds.blockSize() == 0) || bounds.isCooperativeLaunch())
270 bounds.setBlockSize(command);
271 using TrueLoopBoundType = StridedLoopRanges<LoopBoundType>;
272 TrueLoopBoundType bounds2(bounds);
273 if (isAcceleratorPolicy(exec_policy)) {
274 command.addNbThreadPerBlock(bounds.blockSize());
275 bounds2.setNbStride(command.nbStride());
276 }
277
278 using HostLoopBoundType = HostLaunchLoopRange<LoopBoundType>;
279
280 Impl::RunCommandLaunchInfo launch_info(command, bounds2.strideValue(), bounds.isCooperativeLaunch());
281 launch_info.beginExecute();
282 switch (exec_policy) {
284 ARCCORE_KERNEL_CUDA_FUNC((Impl::doHierarchicalLaunchCudaHip<TrueLoopBoundType, Lambda, RemainingArgs...>),
285 launch_info, func, bounds2, other_args...);
286 break;
288 ARCCORE_KERNEL_HIP_FUNC((Impl::doHierarchicalLaunchCudaHip<TrueLoopBoundType, Lambda, RemainingArgs...>),
289 launch_info, func, bounds2, other_args...);
290 break;
292 ARCCORE_KERNEL_SYCL_FUNC((Impl::doHierarchicalLaunchSycl<TrueLoopBoundType, Lambda, RemainingArgs...>{}),
293 launch_info, func, bounds2, other_args...);
294 break;
296 HostLoopBoundType host_bounds(bounds);
297 arccoreSequentialFor(host_bounds, func, other_args...);
298 } break;
300 HostLoopBoundType host_bounds(bounds);
301 arccoreParallelFor(host_bounds, launch_info.loopRunInfo(), func, other_args...);
302 } break;
303 default:
304 ARCCORE_FATAL("Invalid execution policy '{0}'", exec_policy);
305 }
306 launch_info.endExecute();
307}
308
309/*---------------------------------------------------------------------------*/
310/*---------------------------------------------------------------------------*/
314template <typename LoopBoundType, typename... RemainingArgs>
315class ExtendedLaunchRunCommand
316{
317 public:
318
319 ExtendedLaunchRunCommand(RunCommand& command, const LoopBoundType& bounds)
320 : m_command(command)
321 , m_bounds(bounds)
322 {
323 }
324 ExtendedLaunchRunCommand(RunCommand& command, const LoopBoundType& bounds, const std::tuple<RemainingArgs...>& args)
325 : m_command(command)
326 , m_bounds(bounds)
327 , m_remaining_args(args)
328 {
329 }
330 RunCommand& m_command;
331 LoopBoundType m_bounds;
332 std::tuple<RemainingArgs...> m_remaining_args;
333};
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
340template <typename LoopBoundType, typename... RemainingArgs>
341class ExtendedLaunchLoop
342{
343 public:
344
345 ExtendedLaunchLoop(const LoopBoundType& bounds, RemainingArgs... args)
346 : m_bounds(bounds)
347 , m_remaining_args(args...)
348 {
349 }
350 LoopBoundType m_bounds;
351 std::tuple<RemainingArgs...> m_remaining_args;
352};
353
354/*---------------------------------------------------------------------------*/
355/*---------------------------------------------------------------------------*/
356
357template <typename LoopBoundType, typename... RemainingArgs> auto
358makeLaunch(const LoopBoundType& bounds, RemainingArgs... args)
359-> ExtendedLaunchLoop<LoopBoundType, RemainingArgs...>
360{
361 return ExtendedLaunchLoop<LoopBoundType, RemainingArgs...>(bounds, args...);
362}
363
364/*---------------------------------------------------------------------------*/
365/*---------------------------------------------------------------------------*/
366
367template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
368operator<<(ExtendedLaunchRunCommand<LoopBoundType, RemainingArgs...>&& nr, const Lambda& f)
369{
370 if constexpr (sizeof...(RemainingArgs) > 0) {
371 std::apply([&](auto... vs) { _doHierarchicalLaunch(nr.m_command, nr.m_bounds, f, vs...); }, nr.m_remaining_args);
372 }
373 else {
374 _doHierarchicalLaunch(nr.m_command, nr.m_bounds, f);
375 }
376}
377
378/*---------------------------------------------------------------------------*/
379/*---------------------------------------------------------------------------*/
384template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
385arccoreSequentialFor(HostLaunchLoopRange<LoopBoundType> bounds, const Lambda& func, const RemainingArgs&... remaining_args)
386{
387 WorkGroupSequentialForHelper::apply(0, bounds.nbBlock(), bounds, func, remaining_args...);
388}
389
390/*---------------------------------------------------------------------------*/
391/*---------------------------------------------------------------------------*/
396template <typename LoopBoundType, typename Lambda, typename... RemainingArgs> void
397arccoreParallelFor(HostLaunchLoopRange<LoopBoundType> bounds, ForLoopRunInfo run_info,
398 const Lambda& func, const RemainingArgs&... remaining_args)
399{
400 Int32 nb_thread = run_info.options().value().maxThread();
401 ThreadGridSynchronizer grid_sync(nb_thread);
402 bounds.setThreadGridSynchronizer(&grid_sync);
403 auto sub_func = [=](Int32 begin_index, Int32 nb_loop) {
404 Impl::WorkGroupSequentialForHelper::apply(begin_index, nb_loop, bounds, func, remaining_args...);
405 };
406 ::Arcane::arccoreParallelFor(0, bounds.nbBlock(), run_info, sub_func);
407}
408
409/*---------------------------------------------------------------------------*/
410/*---------------------------------------------------------------------------*/
411
412} // namespace Arcane::Accelerator::Impl
413
414/*---------------------------------------------------------------------------*/
415/*---------------------------------------------------------------------------*/
416
417#endif
418
419/*---------------------------------------------------------------------------*/
420/*---------------------------------------------------------------------------*/
#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.
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.