Arcane  v4.1.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
RunCommandImpl.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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/* RunCommandImpl.cc (C) 2000-2025 */
9/* */
10/* Implémentation de la gestion d'une commande sur accélérateur. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/accelerator/core/internal/RunCommandImpl.h"
15#include "arcane/accelerator/core/internal/AcceleratorCoreGlobalInternal.h"
16
17#include "arccore/base/FatalErrorException.h"
18#include "arccore/base/ForLoopTraceInfo.h"
19#include "arccore/base/PlatformUtils.h"
20#include "arccore/base/Convert.h"
21#include "arccore/base/ConcurrencyBase.h"
22
23#include "arcane/accelerator/core/Runner.h"
24#include "arcane/accelerator/core/internal/IRunQueueEventImpl.h"
25#include "arcane/accelerator/core/internal/IRunQueueStream.h"
26#include "arcane/accelerator/core/internal/IRunnerRuntime.h"
27#include "arcane/accelerator/core/internal/RunQueueImpl.h"
28#include "arcane/accelerator/core/internal/ReduceMemoryImpl.h"
29#include "arcane/accelerator/core/internal/RunnerImpl.h"
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane::Accelerator::impl
35{
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
39
40RunCommandImpl::
41RunCommandImpl(RunQueueImpl* queue)
42: m_queue(queue)
43, m_use_accelerator(impl::isAcceleratorPolicy(queue->runner()->executionPolicy()))
44{
45 _init();
46}
47
48/*---------------------------------------------------------------------------*/
49/*---------------------------------------------------------------------------*/
50
51RunCommandImpl::
52~RunCommandImpl()
53{
54 _freePools();
55 delete m_start_event;
56 delete m_stop_event;
57}
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
61
62void RunCommandImpl::
63_freePools()
64{
65 while (!m_reduce_memory_pool.empty()) {
66 delete m_reduce_memory_pool.top();
67 m_reduce_memory_pool.pop();
68 }
69}
70
71/*---------------------------------------------------------------------------*/
72/*---------------------------------------------------------------------------*/
73
74IRunQueueEventImpl* RunCommandImpl::
75_createEvent()
76{
77 if (m_use_sequential_timer_event)
78 return getSequentialRunQueueRuntime()->createEventImplWithTimer();
79 return runner()->_createEventWithTimer();
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
84
85void RunCommandImpl::
86_init()
87{
88 // N'utilise les timers accélérateur que si le profiling est activé.
89 // On fait cela pour éviter d'appeler les évènements accélérateurs car on
90 // ne connait pas encore leur influence sur les performances. Si elle est
91 // négligeable alors on pourra l'activer par défaut.
92
93 // TODO: il faudrait éventuellement avoir une instance séquentielle et
94 // une associée à runner() pour gérer le cas ou ProfilingRegistry::hasProfiling()
95 // change en cours d'exécution.
96 if (m_use_accelerator && !ProfilingRegistry::hasProfiling())
97 m_use_sequential_timer_event = true;
98
99 m_start_event = _createEvent();
100 m_stop_event = _createEvent();
101
102 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_ACCELERATOR_ALLOW_REUSE_COMMAND", true))
103 m_is_allow_reuse_command = (v.value() != 0);
104}
105
106/*---------------------------------------------------------------------------*/
107/*---------------------------------------------------------------------------*/
108
109RunCommandImpl* RunCommandImpl::
110create(RunQueueImpl* r)
111{
112 RunCommandImpl* c = r->_internalCreateOrGetRunCommandImpl();
113 c->_reset();
114 return c;
115}
116
117/*---------------------------------------------------------------------------*/
118/*---------------------------------------------------------------------------*/
122void RunCommandImpl::
123notifyBeginLaunchKernel()
124{
127 ARCANE_FATAL("Command has already been launched. You can not re-use the same command.\n"
128 " You can temporarily allow it if you set environment variable\n"
129 " ARCANE_ACCELERATOR_ALLOW_REUSE_COMMAND to 1\n");
130 }
131 IRunQueueStream* stream = internalStream();
132 stream->notifyBeginLaunchKernel(*this);
133 // TODO: utiliser la bonne stream en séquentiel
134 m_has_been_launched = true;
135 if (m_use_profiling) {
136 m_start_event->recordQueue(stream);
138 m_loop_one_exec_stat_ptr = &m_loop_one_exec_stat;
139 m_loop_one_exec_stat.setBeginTime(m_begin_time);
140 }
141}
142
143/*---------------------------------------------------------------------------*/
144/*---------------------------------------------------------------------------*/
150void RunCommandImpl::
151notifyEndLaunchKernel()
152{
153 IRunQueueStream* stream = internalStream();
154 // TODO: utiliser la bonne stream en séquentiel
155 if (m_use_profiling)
156 m_stop_event->recordQueue(stream);
157 stream->notifyEndLaunchKernel(*this);
158 m_queue->_addRunningCommand(this);
159}
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
170void RunCommandImpl::
171notifyLaunchKernelSyclEvent(void* sycl_event_ptr)
172{
173 IRunQueueStream* stream = internalStream();
174 stream->_setSyclLastCommandEvent(sycl_event_ptr);
175 // Il faut enregistrer à nouveau la file associée à l'évènement
176 // car lors de l'appel à notifyBeginLaunchKernel() il n'y avait pas
177 // encore l'évènement associé à cette file.
178 m_start_event->recordQueue(stream);
179}
180
181/*---------------------------------------------------------------------------*/
182/*---------------------------------------------------------------------------*/
190void RunCommandImpl::
191notifyEndExecuteKernel()
192{
193 // Ne fait rien si la commande n'a pas été lancée.
195 return;
196
197 Int64 diff_time_ns = 0;
198 if (m_use_profiling){
199 diff_time_ns = m_stop_event->elapsedTime(m_start_event);
200 runner()->addTime((double)diff_time_ns / 1.0e9);
201 }
202
203 ForLoopOneExecStat* exec_info = m_loop_one_exec_stat_ptr;
204 if (exec_info) {
205 exec_info->setEndTime(m_begin_time + diff_time_ns);
206 //std::cout << "END_EXEC exec_info=" << m_loop_run_info.traceInfo().traceInfo() << "\n";
207 ForLoopTraceInfo flti(traceInfo(), kernelName());
208 ProfilingRegistry::_threadLocalForLoopInstance()->merge(*exec_info, flti);
209 }
210}
211
212/*---------------------------------------------------------------------------*/
213/*---------------------------------------------------------------------------*/
214
215void RunCommandImpl::
216_reset()
217{
218 m_kernel_name = String();
219 m_trace_info = TraceInfo();
220 m_nb_thread_per_block = 0;
221 m_use_profiling = ProfilingRegistry::hasProfiling();
222 m_parallel_loop_options = ConcurrencyBase::defaultParallelLoopOptions();
223 m_begin_time = 0;
224 m_loop_one_exec_stat.reset();
225 m_loop_one_exec_stat_ptr = nullptr;
226 m_has_been_launched = false;
227 m_has_living_run_command = false;
228 m_may_be_put_in_pool = false;
229}
230
231/*---------------------------------------------------------------------------*/
232/*---------------------------------------------------------------------------*/
233
234IReduceMemoryImpl* RunCommandImpl::
235getOrCreateReduceMemoryImpl()
236{
237 ReduceMemoryImpl* p = _getOrCreateReduceMemoryImpl();
238 if (p) {
239 m_active_reduce_memory_list.insert(p);
240 }
241 return p;
242}
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
246
247void RunCommandImpl::
248releaseReduceMemoryImpl(ReduceMemoryImpl* p)
249{
250 auto x = m_active_reduce_memory_list.find(p);
251 if (x == m_active_reduce_memory_list.end())
252 ARCANE_FATAL("ReduceMemoryImpl in not in active list");
253 m_active_reduce_memory_list.erase(x);
254 m_reduce_memory_pool.push(p);
255}
256
257/*---------------------------------------------------------------------------*/
258/*---------------------------------------------------------------------------*/
259
260IRunQueueStream* RunCommandImpl::
261internalStream() const
262{
263 return m_queue->_internalStream();
264}
265
266/*---------------------------------------------------------------------------*/
267/*---------------------------------------------------------------------------*/
268
269RunnerImpl* RunCommandImpl::
270runner() const
271{
272 return m_queue->runner();
273}
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
277
278ReduceMemoryImpl* RunCommandImpl::
279_getOrCreateReduceMemoryImpl()
280{
281 // Pas besoin d'allouer de la mémoire spécifique si on n'est pas
282 // sur un accélérateur
283 if (!m_use_accelerator)
284 return nullptr;
285
286 auto& pool = m_reduce_memory_pool;
287
288 if (!pool.empty()) {
289 ReduceMemoryImpl* p = pool.top();
290 pool.pop();
291 return p;
292 }
293 return new ReduceMemoryImpl(this);
294}
295
296/*---------------------------------------------------------------------------*/
297/*---------------------------------------------------------------------------*/
301void RunCommandImpl::
302_notifyDestroyRunCommand()
303{
304 // Si la commande n'a pas été lancé, il faut la remettre dans le pool
305 // des commandes de la file (sinon on aura une fuite mémoire)
307 m_queue->_putInCommandPool(this);
308}
309
310/*---------------------------------------------------------------------------*/
311/*---------------------------------------------------------------------------*/
312
313} // namespace Arcane::Accelerator::impl
314
315/*---------------------------------------------------------------------------*/
316/*---------------------------------------------------------------------------*/
bool isAcceleratorPolicy(eExecutionPolicy exec_policy)
Indique si exec_policy correspond à un accélérateur.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Interface d'un flux d'exécution pour une RunQueue.
virtual void notifyBeginLaunchKernel(impl::RunCommandImpl &command)=0
Notification avant le lancement de la commande.
virtual void _setSyclLastCommandEvent(void *sycl_event_ptr)
Pour SYCL, positionne l'évènement associé à la dernière commande exécutée.
virtual void notifyEndLaunchKernel(impl::RunCommandImpl &command)=0
Notification de fin de lancement de la commande.
IRunQueueEventImpl * m_stop_event
Évènements pour la fin de l'exécution.
bool m_has_been_launched
Indique si la commande a été lancée.
IRunQueueEventImpl * m_start_event
Évènements pour le début et la fin de l'exécution.
bool m_is_allow_reuse_command
Indique si on autorise à utiliser plusieurs fois la même commande.
Int64 m_begin_time
Temps au lancement de la commande.
bool m_may_be_put_in_pool
Indique si on peut remettre la commande dans le pool associé à la RunQueue.
bool m_use_profiling
Indique si on souhaite le profiling.
File d'exécution pour accélérateur.
static const ParallelLoopOptions & defaultParallelLoopOptions()
Valeurs par défaut d'exécution d'une boucle parallèle.
Classe pour gérer le profiling d'une seule exécution d'une boucle.
void setEndTime(Int64 v)
Positionne le temps de fin de la boucle en nanoseconde.
Informations de trace pour une boucle 'for'.
static Impl::ForLoopStatInfoList * _threadLocalForLoopInstance()
Definition Profiling.cc:194
static bool hasProfiling()
Indique si le profilage est actif.
Chaîne de caractères unicode.
ARCCORE_BASE_EXPORT Int64 getRealTimeNS()
Temps horloge en nano-secondes.
std::int64_t Int64
Type entier signé sur 64 bits.