Arcane  v4.1.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
WorkGroupLoopRange.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 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/* WorkGroupLoopRange.h (C) 2000-2025 */
9/* */
10/* Boucle pour le parallélisme hiérarchique. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_ACCELERATOR_WORKGROUPLOOPRANGE_H
13#define ARCANE_ACCELERATOR_WORKGROUPLOOPRANGE_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/accelerator/AcceleratorUtils.h"
18
19#if defined(ARCANE_COMPILING_CUDA)
20#include <cooperative_groups.h>
21#endif
22#if defined(ARCANE_COMPILING_HIP)
23#include <hip/hip_cooperative_groups.h>
24#endif
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29namespace Arcane::Accelerator
30{
31namespace Impl
32{
34} // namespace Impl
35
39class SyclDeviceWorkItemBlock;
40class DeviceWorkItemBlock;
41class SyclWorkGroupLoopContext;
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
49{
50 friend WorkGroupLoopContext;
51 friend SyclDeviceWorkItemBlock;
52 friend DeviceWorkItemBlock;
53 friend HostWorkItemGroup;
54
55 private:
56
58 explicit constexpr ARCCORE_HOST_DEVICE WorkItem(Int32 loop_index)
59 : m_loop_index(loop_index)
60 {}
61
62 public:
63
65 constexpr Int32 linearIndex() const { return m_loop_index; }
66
67 private:
68
69 Int32 m_loop_index = 0;
70};
71
72/*---------------------------------------------------------------------------*/
73/*---------------------------------------------------------------------------*/
87{
88 friend WorkGroupLoopContext;
89 friend SyclDeviceWorkItemBlock;
90 friend DeviceWorkItemBlock;
91
92 private:
93
95 explicit constexpr ARCCORE_HOST_DEVICE HostWorkItemGroup(Int32 loop_index, Int32 group_index, Int32 group_size, Int32 nb_active_item)
96 : m_loop_index(loop_index)
97 , m_group_size(group_size)
98 , m_group_index(group_index)
99 , m_nb_active_item(nb_active_item)
100 {}
101
102 public:
103
105 constexpr Int32 groupRank() const { return m_group_index; }
106
108 constexpr Int32 groupSize() const { return m_group_size; }
109
111 constexpr Int32 activeWorkItemRankInGroup() const { return 0; }
112
114 static constexpr bool isDevice() { return false; }
115
117 void barrier() {}
118
120 constexpr Int32 nbActiveItem() const { return m_nb_active_item; }
121
124 {
125 ARCANE_CHECK_AT(index, m_nb_active_item);
126 return WorkItem(m_loop_index);
127 }
128
129 private:
130
131 Int32 m_loop_index = 0;
132 Int32 m_group_size = 0;
133 Int32 m_group_index = 0;
134 Int32 m_nb_active_item = 0;
135};
136
137/*---------------------------------------------------------------------------*/
138/*---------------------------------------------------------------------------*/
139
140#if defined(ARCANE_COMPILING_CUDA) || defined(ARCANE_COMPILING_HIP)
141
142/*---------------------------------------------------------------------------*/
143/*---------------------------------------------------------------------------*/
147class DeviceWorkItemBlock
148{
150
151 private:
152
159 explicit __device__ DeviceWorkItemBlock()
160 : m_thread_block(cooperative_groups::this_thread_block())
161 {}
162
163 public:
164
166 __device__ Int32 groupRank() const { return m_thread_block.group_index().x; }
167
169 __device__ Int32 groupSize() { return m_thread_block.group_dim().x; }
170
172 __device__ Int32 activeWorkItemRankInGroup() const { return m_thread_block.thread_index().x; }
173
175 __device__ void barrier() { m_thread_block.sync(); }
176
178 static constexpr __device__ bool isDevice() { return true; }
179
181 constexpr __device__ Int32 nbActiveItem() const { return 1; }
182
184 __device__ WorkItem activeItem(Int32 index)
185 {
186 // Seulement valide pour index==0
187 ARCANE_CHECK_AT(index, 1);
188 return WorkItem(blockDim.x * blockIdx.x + threadIdx.x);
189 }
190
191 private:
192
193 cooperative_groups::thread_block m_thread_block;
194};
195#endif
196
197/*---------------------------------------------------------------------------*/
198/*---------------------------------------------------------------------------*/
208{
209 // Pour accéder aux constructeurs
210 friend WorkGroupLoopRange;
212
213 private:
214
216 explicit constexpr WorkGroupLoopContext(Int32 loop_index, Int32 group_index, Int32 group_size, Int32 nb_active_item)
217 : m_loop_index(loop_index)
218 , m_group_index(group_index)
219 , m_group_size(group_size)
220 , m_nb_active_item(nb_active_item)
221 {
222 }
223
224 // Ce constructeur n'est utilisé que sur le device
225 // Il ne fait rien car les valeurs utiles sont récupérées via cooperative_groups::this_thread_block()
226 explicit constexpr ARCCORE_DEVICE WorkGroupLoopContext() {}
227
228 public:
229
230#if defined(ARCCORE_DEVICE_CODE) && !defined(ARCANE_COMPILING_SYCL)
232 __device__ DeviceWorkItemBlock group() const { return DeviceWorkItemBlock(); }
233#else
235 HostWorkItemGroup group() const { return HostWorkItemGroup(m_loop_index, m_group_index, m_group_size, m_nb_active_item); }
236#endif
237
238 private:
239
240 Int32 m_loop_index = 0;
241 Int32 m_group_index = 0;
242 Int32 m_group_size = 0;
243 Int32 m_nb_active_item = 0;
244};
245
246/*---------------------------------------------------------------------------*/
247/*---------------------------------------------------------------------------*/
248/*
249 * Implémentation pour SYCL.
250 *
251 * L'équivalent de \a cooperative_groups::thread_group() avec SYCL
252 * est le \a sycl::nd_item<1>. Il est plus compliqué à utiliser pour deux
253 * raisons:
254 *
255 * - il n'y a pas dans SYCL un équivalent de
256 * \a cooperative_groups::this_thread_block(). Il faut utiliser la valeur
257 * de \a sycl::nb_item<1> passé en argument du noyau de calcul.
258 * - il n'y a pas de constructeurs par défaut pour \a sycl::nb_item<1>.
259 *
260 * Pour contourner ces deux problèmes, on utilise un type spécifique pour
261 * gérer les noyaux en SYCL. Heureusement, il est possible d'utiliser les
262 * lambda template avec SYCL. On utilise donc deux types pour gérer
263 * les noyaux selon qu'on s'exécute sur le device SYCL ou sur l'hôte.
264 *
265 * TODO: regarder si avec la macro SYCL_DEVICE_ONLY il n'est pas possible
266 * d'avoir le même type comportant des champs différents
267 */
268#if defined(ARCANE_COMPILING_SYCL)
269
273class SyclDeviceWorkItemBlock
274{
275 friend SyclWorkGroupLoopContext;
276
277 private:
278
279 explicit SyclDeviceWorkItemBlock(sycl::nd_item<1> n)
280 : m_nd_item(n)
281 {
282 }
283
284 public:
285
287 Int32 groupRank() const { return static_cast<Int32>(m_nd_item.get_group(0)); }
288
290 Int32 groupSize() { return static_cast<Int32>(m_nd_item.get_local_range(0)); }
291
293 Int32 activeWorkItemRankInGroup() const { return static_cast<Int32>(m_nd_item.get_local_id(0)); }
294
296 void barrier() { m_nd_item.barrier(); }
297
299 static constexpr bool isDevice() { return true; }
300
302 constexpr Int32 nbActiveItem() const { return 1; }
303
305 WorkItem activeItem(Int32 index)
306 {
307 // Seulement valide pour index==0
308 ARCANE_CHECK_AT(index, 1);
309 return WorkItem(static_cast<Int32>(m_nd_item.get_group(0) * m_nd_item.get_local_range(0) + m_nd_item.get_local_id(0)));
310 }
311
312 private:
313
314 sycl::nd_item<1> m_nd_item;
315};
316
317/*---------------------------------------------------------------------------*/
318/*---------------------------------------------------------------------------*/
324class SyclWorkGroupLoopContext
325{
326 friend WorkGroupLoopRange;
327
328 private:
329
330 // Ce constructeur n'est utilisé que sur le device
331 explicit SyclWorkGroupLoopContext(sycl::nd_item<1> n)
332 : m_nd_item(n)
333 {
334 }
335
336 public:
337
339 SyclDeviceWorkItemBlock group() const { return SyclDeviceWorkItemBlock(m_nd_item); }
340
341 private:
342
343 sycl::nd_item<1> m_nd_item;
344};
345
346#endif // ARCANE_COMPILING_SYCL
347
348/*---------------------------------------------------------------------------*/
349/*---------------------------------------------------------------------------*/
364class ARCANE_ACCELERATOR_EXPORT WorkGroupLoopRange
365{
366 private:
367
368 friend ARCANE_ACCELERATOR_EXPORT WorkGroupLoopRange
369 makeWorkGroupLoopRange(RunCommand& command, Int32 nb_group, Int32 group_size);
370 friend ARCANE_ACCELERATOR_EXPORT WorkGroupLoopRange
371 makeWorkGroupLoopRange(RunCommand& command, Int32 nb_element, Int32 nb_group, Int32 group_size);
372
373 public:
374
375 using LoopIndexType = WorkGroupLoopContext;
376
377 public:
378
379 WorkGroupLoopRange() = default;
380
381 private:
382
389 WorkGroupLoopRange(Int32 total_nb_element, Int32 nb_group, Int32 group_size);
390
391 public:
392
394 constexpr Int32 nbElement() const { return m_total_size; }
396 constexpr Int32 groupSize() const { return m_group_size; }
398 constexpr Int32 nbGroup() const { return m_nb_group; }
400 constexpr Int32 lastGroupSize() const { return m_last_group_size; }
402 constexpr Int32 nbActiveItem(Int32 i) const
403 {
404 return ((i + 1) != m_nb_group) ? m_group_size : m_last_group_size;
405 }
406
407 public:
408
409 //TODO rendre privé ou mettre en externe
410#if defined(ARCANE_COMPILING_CUDA) || defined(ARCANE_COMPILING_HIP)
411 constexpr ARCCORE_HOST_DEVICE WorkGroupLoopContext getIndices(Int32) const { return WorkGroupLoopContext(); }
412#endif
413
414#if defined(ARCANE_COMPILING_SYCL)
415 //TODO rendre privé ou mettre en externe
416 SyclWorkGroupLoopContext getIndices(sycl::nd_item<1> id) const
417 {
418 return SyclWorkGroupLoopContext(id);
419 }
420#endif
421
422 private:
423
424 Int32 m_total_size = 0;
425 Int32 m_nb_group = 0;
426 Int32 m_group_size = 0;
427 Int32 m_last_group_size = 0;
428};
429
430/*---------------------------------------------------------------------------*/
431/*---------------------------------------------------------------------------*/
432
433} // namespace Arcane::Accelerator
434
435/*---------------------------------------------------------------------------*/
436/*---------------------------------------------------------------------------*/
437
438#endif
439
440/*---------------------------------------------------------------------------*/
441/*---------------------------------------------------------------------------*/
Gère un groupe de WorkItem dans un WorkGroupLoopRange pour l'hôte.
constexpr __host__ __device__ HostWorkItemGroup(Int32 loop_index, Int32 group_index, Int32 group_size, Int32 nb_active_item)
Constructeur pour l'hôte.
WorkItem activeItem(Int32 index) const
Récupère le index-ème WorkItem à gérer.
static constexpr bool isDevice()
Indique si on s'exécute sur un accélérateur.
void barrier()
Bloque tant que tous les WorkItem du groupe ne sont pas arrivés ici.
constexpr Int32 activeWorkItemRankInGroup() const
Rang du WorkItem actif dans son WorkGroup.
constexpr Int32 groupRank() const
Rang du groupe du WorkItem dans la liste des WorkGroup.
constexpr Int32 nbActiveItem() const
Nombre de WorkItem à gérer dans l'itération.
constexpr Int32 groupSize() const
Nombre de WorkItem dans un WorkGroup.
Classe pour exécuter en séquentiel sur l'hôte une partie de la boucle.
Gestion d'une commande sur accélérateur.
Contexte d'exécution d'une commande sur un ensemble de blocs.
HostWorkItemGroup group() const
Groupe courant.
constexpr WorkGroupLoopContext(Int32 loop_index, Int32 group_index, Int32 group_size, Int32 nb_active_item)
Ce constructeur est utilisé dans l'implémentation hôte.
Intervalle d'itération d'une boucle utilisant le parallélisme hiérarchique.
constexpr Int32 nbActiveItem(Int32 i) const
Nombre d'éléments actifs pour le i-ème groupe.
constexpr Int32 nbGroup() const
Nombre de groupes.
constexpr Int32 lastGroupSize() const
Nombre d'éléments du dernier groupe.
constexpr Int32 nbElement() const
Nombre d'éléments à traiter.
friend WorkGroupLoopRange makeWorkGroupLoopRange(RunCommand &command, Int32 nb_group, Int32 group_size)
Créé un intervalle d'itération pour la commande command.
friend WorkGroupLoopRange makeWorkGroupLoopRange(RunCommand &command, Int32 nb_element, Int32 nb_group, Int32 group_size)
Créé un intervalle d'itération pour la commande command.
constexpr Int32 groupSize() const
Taille d'un groupe.
Représente un WorkItem dans le parallélisme hiérarchique.
constexpr __host__ __device__ WorkItem(Int32 loop_index)
Constructeur pour l'hôte.
constexpr Int32 linearIndex() const
Index linéaire entre 0 et WorkGroupLoopRange::nbElement()
Espace de nom pour l'utilisation des accélérateurs.
std::int32_t Int32
Type entier signé sur 32 bits.