Arcane  v3.15.0.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
RunCommandImpl.cc
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/* RunCommandImpl.cc (C) 2000-2024 */
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 "arcane/utils/ForLoopTraceInfo.h"
19#include "arcane/utils/PlatformUtils.h"
20#include "arcane/utils/ValueConvert.h"
21
22#include "arcane/accelerator/core/Runner.h"
23#include "arcane/accelerator/core/internal/IRunQueueEventImpl.h"
24#include "arcane/accelerator/core/internal/IRunQueueStream.h"
25#include "arcane/accelerator/core/internal/IRunnerRuntime.h"
26#include "arcane/accelerator/core/internal/RunQueueImpl.h"
27#include "arcane/accelerator/core/internal/ReduceMemoryImpl.h"
28#include "arcane/accelerator/core/internal/RunnerImpl.h"
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33namespace Arcane::Accelerator::impl
34{
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42RunCommandImpl::
43RunCommandImpl(RunQueueImpl* queue)
44: m_queue(queue)
45, m_use_accelerator(impl::isAcceleratorPolicy(queue->runner()->executionPolicy()))
46{
47 _init();
48}
49
50/*---------------------------------------------------------------------------*/
51/*---------------------------------------------------------------------------*/
52
53RunCommandImpl::
54~RunCommandImpl()
55{
56 _freePools();
57 delete m_start_event;
58 delete m_stop_event;
59}
60
61/*---------------------------------------------------------------------------*/
62/*---------------------------------------------------------------------------*/
63
64void RunCommandImpl::
65_freePools()
66{
67 while (!m_reduce_memory_pool.empty()) {
68 delete m_reduce_memory_pool.top();
69 m_reduce_memory_pool.pop();
70 }
71}
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
76IRunQueueEventImpl* RunCommandImpl::
77_createEvent()
78{
79 if (m_use_sequential_timer_event)
80 return getSequentialRunQueueRuntime()->createEventImplWithTimer();
81 return runner()->_createEventWithTimer();
82}
83
84/*---------------------------------------------------------------------------*/
85/*---------------------------------------------------------------------------*/
86
87void RunCommandImpl::
88_init()
89{
90 // N'utilise les timers accélérateur que si le profiling est activé.
91 // On fait cela pour éviter d'appeler les évènements accélérateurs car on
92 // ne connait pas encore leur influence sur les performances. Si elle est
93 // négligeable alors on pourra l'activer par défaut.
94
95 // TODO: il faudrait éventuellement avoir une instance séquentielle et
96 // une associée à runner() pour gérer le cas ou ProfilingRegistry::hasProfiling()
97 // change en cours d'exécution.
98 if (m_use_accelerator && !ProfilingRegistry::hasProfiling())
99 m_use_sequential_timer_event = true;
100
101 m_start_event = _createEvent();
102 m_stop_event = _createEvent();
103
104 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_ACCELERATOR_ALLOW_REUSE_COMMAND", true))
105 m_is_allow_reuse_command = (v.value() != 0);
106}
107
108/*---------------------------------------------------------------------------*/
109/*---------------------------------------------------------------------------*/
110
111RunCommandImpl* RunCommandImpl::
112create(RunQueueImpl* r)
113{
114 RunCommandImpl* c = r->_internalCreateOrGetRunCommandImpl();
115 c->_reset();
116 return c;
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121/*!
122 * \brief Notification du début d'exécution de la commande.
123 */
124void RunCommandImpl::
125notifyBeginLaunchKernel()
126{
127 if (m_has_been_launched) {
128 if (!m_is_allow_reuse_command)
129 ARCANE_FATAL("Command has already been launched. You can not re-use the same command.\n"
130 " You can temporarily allow it if you set environment variable\n"
131 " ARCANE_ACCELERATOR_ALLOW_REUSE_COMMAND to 1\n");
132 }
133 IRunQueueStream* stream = internalStream();
134 stream->notifyBeginLaunchKernel(*this);
135 // TODO: utiliser la bonne stream en séquentiel
136 m_has_been_launched = true;
137 if (m_use_profiling) {
138 m_start_event->recordQueue(stream);
139 m_begin_time = platform::getRealTimeNS();
140 m_loop_one_exec_stat_ptr = &m_loop_one_exec_stat;
141 m_loop_one_exec_stat.setBeginTime(m_begin_time);
142 }
143}
144
145/*---------------------------------------------------------------------------*/
146/*---------------------------------------------------------------------------*/
147/*!
148 * \brief Notification de la fin de lancement de la commande.
149 *
150 * La commande continue à s'exécuter en tâche de fond.
151 */
152void RunCommandImpl::
153notifyEndLaunchKernel()
154{
155 IRunQueueStream* stream = internalStream();
156 // TODO: utiliser la bonne stream en séquentiel
157 if (m_use_profiling)
158 m_stop_event->recordQueue(stream);
159 stream->notifyEndLaunchKernel(*this);
160 m_queue->_addRunningCommand(this);
161}
162
163/*---------------------------------------------------------------------------*/
164/*---------------------------------------------------------------------------*/
165/*!
166 * \brief Notification du lancement d'un kernel SYCL.
167 *
168 * \a sycl_event_ptr est de type sycl::event* et contient
169 * l'évènement associé à la commande qui est retourné lors
170 * des appels à sycl::queue::submit().
171 */
172void RunCommandImpl::
173notifyLaunchKernelSyclEvent(void* sycl_event_ptr)
174{
175 IRunQueueStream* stream = internalStream();
176 stream->_setSyclLastCommandEvent(sycl_event_ptr);
177 // Il faut enregistrer à nouveau la file associée à l'évènement
178 // car lors de l'appel à notifyBeginLaunchKernel() il n'y avait pas
179 // encore l'évènement associé à cette file.
180 m_start_event->recordQueue(stream);
181}
182
183/*---------------------------------------------------------------------------*/
184/*---------------------------------------------------------------------------*/
185/*!
186 * \brief Notification de la fin d'exécution du noyau.
187 *
188 * Après cet appel, on est sur que la commande a fini de s'exécuter et on
189 * peut la recycler. En asynchrone, cette méthode est appelée lors de la
190 * synchronisation d'une file.
191 */
192void RunCommandImpl::
193notifyEndExecuteKernel()
194{
195 // Ne fait rien si la commande n'a pas été lancée.
196 if (!m_has_been_launched)
197 return;
198
199 Int64 diff_time_ns = 0;
200 if (m_use_profiling){
201 diff_time_ns = m_stop_event->elapsedTime(m_start_event);
202 runner()->addTime((double)diff_time_ns / 1.0e9);
203 }
204
205 ForLoopOneExecStat* exec_info = m_loop_one_exec_stat_ptr;
206 if (exec_info) {
207 exec_info->setEndTime(m_begin_time + diff_time_ns);
208 //std::cout << "END_EXEC exec_info=" << m_loop_run_info.traceInfo().traceInfo() << "\n";
209 ForLoopTraceInfo flti(traceInfo(), kernelName());
210 ProfilingRegistry::_threadLocalForLoopInstance()->merge(*exec_info, flti);
211 }
212}
213
214/*---------------------------------------------------------------------------*/
215/*---------------------------------------------------------------------------*/
216
217void RunCommandImpl::
218_reset()
219{
220 m_kernel_name = String();
221 m_trace_info = TraceInfo();
222 m_nb_thread_per_block = 0;
223 m_use_profiling = ProfilingRegistry::hasProfiling();
224 m_parallel_loop_options = TaskFactory::defaultParallelLoopOptions();
225 m_begin_time = 0;
226 m_loop_one_exec_stat.reset();
227 m_loop_one_exec_stat_ptr = nullptr;
228 m_has_been_launched = false;
229 m_has_living_run_command = false;
230 m_may_be_put_in_pool = false;
231}
232
233/*---------------------------------------------------------------------------*/
234/*---------------------------------------------------------------------------*/
235
236IReduceMemoryImpl* RunCommandImpl::
237getOrCreateReduceMemoryImpl()
238{
239 ReduceMemoryImpl* p = _getOrCreateReduceMemoryImpl();
240 if (p) {
241 m_active_reduce_memory_list.insert(p);
242 }
243 return p;
244}
245
246/*---------------------------------------------------------------------------*/
247/*---------------------------------------------------------------------------*/
248
249void RunCommandImpl::
250releaseReduceMemoryImpl(ReduceMemoryImpl* p)
251{
252 auto x = m_active_reduce_memory_list.find(p);
253 if (x == m_active_reduce_memory_list.end())
254 ARCANE_FATAL("ReduceMemoryImpl in not in active list");
255 m_active_reduce_memory_list.erase(x);
256 m_reduce_memory_pool.push(p);
257}
258
259/*---------------------------------------------------------------------------*/
260/*---------------------------------------------------------------------------*/
261
262IRunQueueStream* RunCommandImpl::
263internalStream() const
264{
265 return m_queue->_internalStream();
266}
267
268/*---------------------------------------------------------------------------*/
269/*---------------------------------------------------------------------------*/
270
271RunnerImpl* RunCommandImpl::
272runner() const
273{
274 return m_queue->runner();
275}
276
277/*---------------------------------------------------------------------------*/
278/*---------------------------------------------------------------------------*/
279
280ReduceMemoryImpl* RunCommandImpl::
281_getOrCreateReduceMemoryImpl()
282{
283 // Pas besoin d'allouer de la mémoire spécifique si on n'est pas
284 // sur un accélérateur
285 if (!m_use_accelerator)
286 return nullptr;
287
288 auto& pool = m_reduce_memory_pool;
289
290 if (!pool.empty()) {
291 ReduceMemoryImpl* p = pool.top();
292 pool.pop();
293 return p;
294 }
295 return new ReduceMemoryImpl(this);
296}
297
298/*---------------------------------------------------------------------------*/
299/*---------------------------------------------------------------------------*/
300/*!
301 * \brief Méthode appelée quand l'instance RunCommand associée est détruite.
302 */
303void RunCommandImpl::
304_notifyDestroyRunCommand()
305{
306 // Si la commande n'a pas été lancé, il faut la remettre dans le pool
307 // des commandes de la file (sinon on aura une fuite mémoire)
308 if (!m_has_been_launched || m_may_be_put_in_pool)
309 m_queue->_putInCommandPool(this);
310}
311
312/*---------------------------------------------------------------------------*/
313/*---------------------------------------------------------------------------*/
314
315} // namespace Arcane::Accelerator::impl
316
317/*---------------------------------------------------------------------------*/
318/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Classes, Types et macros pour gérer la concurrence.
bool isAcceleratorPolicy(eExecutionPolicy exec_policy)
Indique si exec_policy correspond à un accélérateur.