Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
RunQueueImpl.cc
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/* RunQueueImpl.cc (C) 2000-2026 */
9/* */
10/* Management of a run queue on an accelerator. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/common/accelerator/internal/RunQueueImpl.h"
15
17#include "arccore/common/SmallArray.h"
18
19#include "arccore/common/accelerator/internal/IRunnerRuntime.h"
20#include "arccore/common/accelerator/internal/IRunQueueStream.h"
21#include "arccore/common/accelerator/internal/RunCommandImpl.h"
22#include "arccore/common/accelerator/internal/RunnerImpl.h"
23#include "arccore/common/accelerator/internal/IRunQueueEventImpl.h"
24
25#include "arccore/common/accelerator/Runner.h"
26#include "arccore/common/accelerator/DeviceId.h"
27#include "arccore/common/accelerator/RunQueueEvent.h"
28#include "arccore/common/accelerator/KernelLaunchArgs.h"
29
30#include <unordered_set>
31#include <iostream>
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36namespace Arcane::Accelerator::Impl
37{
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
44{
45 public:
46
47 explicit Lock(RunQueueImpl* p)
48 {
49 if (p->m_use_pool_mutex) {
50 m_mutex = p->m_pool_mutex.get();
51 if (m_mutex) {
52 m_mutex->lock();
53 }
54 }
55 }
56 ~Lock()
57 {
58 if (m_mutex)
59 m_mutex->unlock();
60 }
61 Lock(const Lock&) = delete;
62 Lock& operator=(const Lock&) = delete;
63
64 private:
65
66 std::mutex* m_mutex = nullptr;
67};
68
69/*---------------------------------------------------------------------------*/
70/*---------------------------------------------------------------------------*/
71
72RunQueueImpl::
73RunQueueImpl(RunnerImpl* runner_impl, Int32 id, const RunQueueBuildInfo& bi)
74: m_runner_impl(runner_impl)
75, m_execution_policy(runner_impl->executionPolicy())
76, m_runtime(runner_impl->runtime())
77, m_queue_stream(m_runtime->createStream(bi))
78, m_id(id)
79{
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
84
85RunQueueImpl::
86~RunQueueImpl()
87{
88 delete m_queue_stream;
89}
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
93
94/*---------------------------------------------------------------------------*/
95/*---------------------------------------------------------------------------*/
96
97void RunQueueImpl::
98_freeCommandsInPool()
99{
100 bool is_check = arccoreIsCheck();
101 std::unordered_set<RunCommandImpl*> command_set;
102 while (!m_run_command_pool.empty()) {
103 RunCommandImpl* c = m_run_command_pool.top();
104 if (is_check) {
105 if (command_set.find(c) != command_set.end())
106 std::cerr << "Command is present several times in the command pool\n";
107 command_set.insert(c);
108 }
109 RunCommand::_internalDestroyImpl(c);
110 m_run_command_pool.pop();
111 }
112}
113
114/*---------------------------------------------------------------------------*/
115/*---------------------------------------------------------------------------*/
116
117void RunQueueImpl::
118_destroy(RunQueueImpl* q)
119{
120 q->_freeCommandsInPool();
121 delete q;
122}
123
124/*---------------------------------------------------------------------------*/
125/*---------------------------------------------------------------------------*/
126
127/*---------------------------------------------------------------------------*/
128/*---------------------------------------------------------------------------*/
129
130void RunQueueImpl::
131_release()
132{
133 // If there are commands currently running when releasing
134 // the run queue, we must wait to avoid memory leaks because
135 // the commands will not be deallocated.
136 // TODO: Check if it should rather indicate this to the user
137 // or throw a fatal error.
138 if (!m_active_run_command_list.empty()) {
139 if (!_internalStream()->_barrierNoException()) {
141 }
142 else
143 std::cerr << "WARNING: Error in internal accelerator barrier\n";
144 }
145 if (_isInPool())
146 m_runner_impl->_internalPutRunQueueImplInPool(this);
147 else {
148 RunQueueImpl::_destroy(this);
149 }
150}
151
152/*---------------------------------------------------------------------------*/
153/*---------------------------------------------------------------------------*/
154
155void RunQueueImpl::
156_setDefaultMemoryRessource()
157{
159 if (isAcceleratorPolicy(m_execution_policy))
161}
162
163/*---------------------------------------------------------------------------*/
164/*---------------------------------------------------------------------------*/
165
166MemoryAllocationOptions RunQueueImpl::
167allocationOptions() const
168{
169 MemoryAllocationOptions opt = MemoryUtils::getAllocationOptions(m_memory_ressource);
170 Int16 device_id = static_cast<Int16>(m_runner_impl->deviceId().asInt32());
171 opt.setDevice(device_id);
172 return opt;
173}
174
175/*---------------------------------------------------------------------------*/
176/*---------------------------------------------------------------------------*/
177
178bool RunQueueImpl::
179isAutoPrefetchCommand() const
180{
181 return m_runner_impl->isAutoPrefetchCommand();
182}
183
184/*---------------------------------------------------------------------------*/
185/*---------------------------------------------------------------------------*/
186
187void RunQueueImpl::
188copyMemory(const MemoryCopyArgs& args) const
189{
190 _internalStream()->copyMemory(args);
191}
192
193/*---------------------------------------------------------------------------*/
194/*---------------------------------------------------------------------------*/
195
196void RunQueueImpl::
197prefetchMemory(const MemoryPrefetchArgs& args) const
198{
199 _internalStream()->prefetchMemory(args);
200}
201
202/*---------------------------------------------------------------------------*/
203/*---------------------------------------------------------------------------*/
204
205void RunQueueImpl::
206recordEvent(RunQueueEvent& event)
207{
208 auto* p = event._internalEventImpl();
209 return p->recordQueue(_internalStream());
210}
211
212/*---------------------------------------------------------------------------*/
213/*---------------------------------------------------------------------------*/
214
215void RunQueueImpl::
216waitEvent(RunQueueEvent& event)
217{
218 auto* p = event._internalEventImpl();
219 return p->waitForEvent(_internalStream());
220}
221
222/*---------------------------------------------------------------------------*/
223/*---------------------------------------------------------------------------*/
224
225RunQueueImpl* RunQueueImpl::
226create(RunnerImpl* r)
227{
228 return _reset(r->_internalCreateOrGetRunQueueImpl());
229}
230
231/*---------------------------------------------------------------------------*/
232/*---------------------------------------------------------------------------*/
233
234RunQueueImpl* RunQueueImpl::
235create(RunnerImpl* r, const RunQueueBuildInfo& bi)
236{
237 return _reset(r->_internalCreateOrGetRunQueueImpl(bi));
238}
239
240/*---------------------------------------------------------------------------*/
241/*---------------------------------------------------------------------------*/
242
243RunCommandImpl* RunQueueImpl::
244_internalCreateOrGetRunCommandImpl()
245{
246 RunCommandImpl* p = nullptr;
247
248 {
249 auto& pool = m_run_command_pool;
250 Lock my_lock(this);
251 if (!pool.empty()) {
252 p = pool.top();
253 pool.pop();
254 }
255 }
256 if (!p)
257 p = RunCommand::_internalCreateImpl(this);
258 p->_reset();
259 return p;
260}
261
262/*---------------------------------------------------------------------------*/
263/*---------------------------------------------------------------------------*/
264
273{
274 if (m_use_pool_mutex) {
275 SmallArray<RunCommandImpl*> command_list;
276 // Copy the commands into a local array because m_active_run_command_list
277 // may be modified by another thread.
278 {
279 Lock my_lock(this);
280 for (RunCommandImpl* p : m_active_run_command_list) {
281 command_list.add(p);
282 }
284 }
285 for (RunCommandImpl* p : command_list) {
286 p->notifyEndExecuteKernel();
287 }
288 {
289 Lock my_lock(this);
290 for (RunCommandImpl* p : command_list) {
292 }
293 }
294 }
295 else {
296 for (RunCommandImpl* p : m_active_run_command_list) {
297 p->notifyEndExecuteKernel();
299 }
301 }
302}
303
304/*---------------------------------------------------------------------------*/
305/*---------------------------------------------------------------------------*/
306
318_checkPutCommandInPoolNoLock(RunCommandImpl* p)
319{
321 p->m_may_be_put_in_pool = true;
322 else
323 m_run_command_pool.push(p);
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328
329void RunQueueImpl::
330_addRunningCommand(RunCommandImpl* p)
331{
332 Lock my_lock(this);
334}
335
336/*---------------------------------------------------------------------------*/
337/*---------------------------------------------------------------------------*/
338
339void RunQueueImpl::
340_putInCommandPool(RunCommandImpl* p)
341{
342 Lock my_lock(this);
343 m_run_command_pool.push(p);
344}
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
348
354{
355 _internalStream()->barrier();
357}
358
359/*---------------------------------------------------------------------------*/
360/*---------------------------------------------------------------------------*/
361
369RunQueueImpl* RunQueueImpl::
370_reset(RunQueueImpl* p)
371{
372 p->m_is_async = false;
373 p->_setDefaultMemoryRessource();
374 return p;
375}
376
377/*---------------------------------------------------------------------------*/
378/*---------------------------------------------------------------------------*/
379
380void RunQueueImpl::
381setConcurrentCommandCreation(bool v)
382{
383 m_use_pool_mutex = v;
384 if (!m_pool_mutex.get())
385 m_pool_mutex = std::make_unique<std::mutex>();
386}
387
388/*---------------------------------------------------------------------------*/
389/*---------------------------------------------------------------------------*/
390
391void RunQueueImpl::
392dumpStats(std::ostream& ostr) const
393{
394 ostr << "nb_pool=" << m_run_command_pool.size()
395 << " nb_active=" << m_active_run_command_list.size() << "\n";
396}
397
398/*---------------------------------------------------------------------------*/
399/*---------------------------------------------------------------------------*/
400
401} // namespace Arcane::Accelerator::Impl
402
403/*---------------------------------------------------------------------------*/
404/*---------------------------------------------------------------------------*/
Memory management utility functions.
bool m_may_be_put_in_pool
Indicates if the command can be returned to the pool associated with the RunQueue.
bool m_has_living_run_command
Indicates if a RunCommand has a reference to this instance.
Lock for the RunCommand pool in multi-thread.
void _checkPutCommandInPoolNoLock(RunCommandImpl *p)
Returns the command to the pool if possible.
UniqueArray< RunCommandImpl * > m_active_run_command_list
List of running commands.
void _internalFreeRunningCommands()
Frees running commands.
static RunQueueImpl * _reset(RunQueueImpl *p)
Resets the implementation.
void _internalBarrier()
Blocks until all commands are finished.
void add(ConstReferenceType val)
Adds element val to the end of the array.
1D data array with pre-allocated stack buffer.
bool isAcceleratorPolicy(eExecutionPolicy exec_policy)
Indicates if exec_policy corresponds to an accelerator.
MemoryAllocationOptions getAllocationOptions(eMemoryResource mem_resource)
Default allocation for the resource mem_resource.
eMemoryResource getDefaultDataMemoryResource()
Memory resource used by the default allocator for data.
std::int16_t Int16
Signed integer type of 16 bits.
bool arccoreIsCheck()
True if in check mode.
@ Host
Allocates on the host.
std::int32_t Int32
Signed integer type of 32 bits.