Arcane  4.1.12.0
User documentation
Loading...
Searching...
No Matches
Runner.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/* Runner.cc (C) 2000-2025 */
9/* */
10/* Accelerator execution management. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/common/accelerator/Runner.h"
15
16#include "arccore/base/FatalErrorException.h"
17#include "arccore/base/NotImplementedException.h"
18#include "arccore/base/ArgumentException.h"
19#include "arccore/base/MemoryView.h"
20#include "arccore/base/Profiling.h"
21#include "arccore/base/Convert.h"
22#include "arccore/base/internal/ProfilingInternal.h"
23
24#include "arccore/common/accelerator/RunQueueBuildInfo.h"
25#include "arccore/common/accelerator/DeviceId.h"
26#include "arccore/common/accelerator/DeviceMemoryInfo.h"
27#include "arccore/common/accelerator/IDeviceInfoList.h"
28#include "arccore/common/accelerator/PointerAttribute.h"
29#include "arccore/common/accelerator/KernelLaunchArgs.h"
30#include "arccore/common/accelerator/internal/IRunnerRuntime.h"
31#include "arccore/common/accelerator/internal/AcceleratorCoreGlobalInternal.h"
32#include "arccore/common/accelerator/internal/RunQueueImpl.h"
33#include "arccore/common/accelerator/internal/RunnerImpl.h"
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace Arcane::Accelerator
39{
40
41namespace
42{
43 inline Impl::IRunnerRuntime*
44 _getRuntimeNoCheck(eExecutionPolicy p)
45 {
46 Impl::IRunnerRuntime* runtime = nullptr;
47 switch (p) {
49 ARCCORE_FATAL("No runtime for eExecutionPolicy::None");
51 return Impl::getSYCLRunQueueRuntime();
53 return Impl::getHIPRunQueueRuntime();
55 return Impl::getCUDARunQueueRuntime();
57 return Impl::getSequentialRunQueueRuntime();
59 return Impl::getThreadRunQueueRuntime();
60 }
61 return runtime;
62 }
63
64 inline Impl::IRunnerRuntime*
65 _getRuntime(eExecutionPolicy p)
66 {
67 auto* x = _getRuntimeNoCheck(p);
68 if (!x)
69 ARCCORE_FATAL("No runtime is available for execution policy '{0}'", p);
70 return x;
71 }
72
73 inline void
74 _stopProfiling(eExecutionPolicy p)
75 {
76 auto* x = _getRuntimeNoCheck(p);
77 if (x)
78 x->stopProfiling();
79 }
80 inline void
81 _finalize(eExecutionPolicy p, ITraceMng* tm)
82 {
83 auto* x = _getRuntimeNoCheck(p);
84 if (x) {
85 x->stopProfiling();
86 x->finalize(tm);
87 }
88 }
89} // namespace
90
91} // namespace Arcane::Accelerator
92
93/*---------------------------------------------------------------------------*/
94/*---------------------------------------------------------------------------*/
95
96namespace Arcane::Accelerator::Impl
97{
98
99/*---------------------------------------------------------------------------*/
100/*---------------------------------------------------------------------------*/
101
102void RunnerImpl::
103initialize(Runner* runner, eExecutionPolicy v, DeviceId device)
104{
105 if (m_is_init)
106 ARCCORE_FATAL("Runner is already initialized");
107 if (v == eExecutionPolicy::None)
108 ARCCORE_THROW(ArgumentException, "executionPolicy should not be eExecutionPolicy::None");
109 if (device.isHost() || device.isNull())
110 ARCCORE_THROW(ArgumentException, "device should not be Device::hostDevice() or Device::nullDevice()");
111
112 m_execution_policy = v;
113 m_device_id = device;
114 m_runtime = _getRuntime(v);
115 m_device_info = m_runtime->deviceInfoList()->deviceInfo(m_device_id.asInt32());
116 m_is_init = true;
117 m_is_auto_prefetch_command = false;
118
119 // For testing
120 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_ACCELERATOR_PREFETCH_COMMAND", true))
121 m_is_auto_prefetch_command = (v.value() != 0);
122
123 // The pool must be initialized at the end because it needs to access \a m_runtime
124 m_run_queue_pool.initialize(runner->_impl());
125}
126
127/*---------------------------------------------------------------------------*/
128/*---------------------------------------------------------------------------*/
129
130void RunnerImpl::
131_checkIsInit() const
132{
133 if (!m_is_init)
134 ARCCORE_FATAL("Runner is not initialized. Call method initialize() before");
135}
136
137/*---------------------------------------------------------------------------*/
138/*---------------------------------------------------------------------------*/
139
140void RunnerImpl::
141_freePool()
142{
143 RunQueueImplStack& s = m_run_queue_pool;
144 while (!s.empty()) {
145 RunQueueImpl* q = s.top();
146 RunQueueImpl::_destroy(q);
147 s.pop();
148 }
149}
150
151/*---------------------------------------------------------------------------*/
152/*---------------------------------------------------------------------------*/
153
154RunQueueImplStack* RunnerImpl::
155getPool()
156{
157 return &m_run_queue_pool;
158}
159
160/*---------------------------------------------------------------------------*/
161/*---------------------------------------------------------------------------*/
162
163void RunnerImpl::
164_internalPutRunQueueImplInPool(RunQueueImpl* p)
165{
166 RunnerImpl::Lock my_lock(this);
167 getPool()->push(p);
168}
169
170/*---------------------------------------------------------------------------*/
171/*---------------------------------------------------------------------------*/
172
173Impl::RunQueueImpl* RunnerImpl::
174_internalCreateOrGetRunQueueImpl()
175{
176 _checkIsInit();
177
178 auto pool = getPool();
179
180 {
181 Impl::RunnerImpl::Lock my_lock(this);
182 if (!pool->empty()) {
183 Impl::RunQueueImpl* p = pool->top();
184 pool->pop();
185 return p;
186 }
187 }
188
189 return pool->createRunQueue(RunQueueBuildInfo{});
190}
191
192/*---------------------------------------------------------------------------*/
193/*---------------------------------------------------------------------------*/
194
195Impl::RunQueueImpl* RunnerImpl::
196_internalCreateOrGetRunQueueImpl(const RunQueueBuildInfo& bi)
197{
198 _checkIsInit();
199 // If we use the default parameters, we can use a RunQueueImpl
200 // from the pool.
201 if (bi.isDefault())
202 return _internalCreateOrGetRunQueueImpl();
203 Impl::IRunnerRuntime* runtime = m_runtime;
204 ARCCORE_CHECK_POINTER(runtime);
205 auto* queue = new Impl::RunQueueImpl(this, 0, bi);
206 return queue;
207}
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211
212RunQueueImpl* RunQueueImplStack::
213createRunQueue(const RunQueueBuildInfo& bi)
214{
215 if (!m_runner_impl)
216 ARCCORE_FATAL("RunQueueImplStack is not initialized");
217 Int32 x = ++m_nb_created;
218 auto* q = new Impl::RunQueueImpl(m_runner_impl, x, bi);
219 q->m_is_in_pool = true;
220 return q;
221}
222
223/*---------------------------------------------------------------------------*/
224/*---------------------------------------------------------------------------*/
225
226IRunQueueEventImpl* RunnerImpl::
227_createEvent()
228{
229 _checkIsInit();
230 return m_runtime->createEventImpl();
231}
232
233/*---------------------------------------------------------------------------*/
234/*---------------------------------------------------------------------------*/
235
236IRunQueueEventImpl* RunnerImpl::
237_createEventWithTimer()
238{
239 _checkIsInit();
240 return m_runtime->createEventImplWithTimer();
241}
242
243/*---------------------------------------------------------------------------*/
244/*---------------------------------------------------------------------------*/
245
246} // namespace Arcane::Accelerator::Impl
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
250
251namespace Arcane::Accelerator
252{
253
254/*---------------------------------------------------------------------------*/
255/*---------------------------------------------------------------------------*/
256
257/*---------------------------------------------------------------------------*/
258/*---------------------------------------------------------------------------*/
259
261Runner()
262: m_p(std::make_shared<Impl::RunnerImpl>())
263{
264}
265
266/*---------------------------------------------------------------------------*/
267/*---------------------------------------------------------------------------*/
268
271: Runner()
272{
273 initialize(p);
274}
275
276/*---------------------------------------------------------------------------*/
277/*---------------------------------------------------------------------------*/
278
280Runner(eExecutionPolicy p, DeviceId device_id)
281: Runner()
282{
283 initialize(p, device_id);
284}
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
288
289/*---------------------------------------------------------------------------*/
290/*---------------------------------------------------------------------------*/
291
292Impl::IRunnerRuntime* Runner::
293_internalRuntime() const
294{
295 _checkIsInit();
296 return m_p->runtime();
297}
298
299/*---------------------------------------------------------------------------*/
300/*---------------------------------------------------------------------------*/
301
303executionPolicy() const
304{
305 return m_p->executionPolicy();
306}
307
308/*---------------------------------------------------------------------------*/
309/*---------------------------------------------------------------------------*/
310
312isInitialized() const
313{
314 return m_p->isInit();
315}
316
317/*---------------------------------------------------------------------------*/
318/*---------------------------------------------------------------------------*/
319
322{
323 // Always thread-safe;
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328
331{
332 return true;
333}
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
337
340{
342 std::cout << "Warning: Runner::setDeviceReducePolicy(): only 'eDeviceReducePolicy::Grid' is supported\n";
343}
344
345/*---------------------------------------------------------------------------*/
346/*---------------------------------------------------------------------------*/
347
349deviceReducePolicy() const
350{
351 return m_p->m_reduce_policy;
352}
353
354/*---------------------------------------------------------------------------*/
355/*---------------------------------------------------------------------------*/
356
359{
360 m_p->initialize(this, v, DeviceId());
361}
362
363/*---------------------------------------------------------------------------*/
364/*---------------------------------------------------------------------------*/
365
368{
369 m_p->initialize(this, v, device_id);
370}
371
372/*---------------------------------------------------------------------------*/
373/*---------------------------------------------------------------------------*/
374
375void Runner::
376_checkIsInit() const
377{
378 if (!m_p->m_is_init)
379 ARCCORE_FATAL("Runner is not initialized. Call method initialize() before");
380}
381
382/*---------------------------------------------------------------------------*/
383/*---------------------------------------------------------------------------*/
384
387{
388 return m_p->cumulativeCommandTime();
389}
390
391/*---------------------------------------------------------------------------*/
392/*---------------------------------------------------------------------------*/
393
396{
397 _checkIsInit();
398 m_p->runtime()->setMemoryAdvice(buffer, advice, m_p->m_device_id);
399}
400
401/*---------------------------------------------------------------------------*/
402/*---------------------------------------------------------------------------*/
403
406{
407 _checkIsInit();
408 m_p->runtime()->unsetMemoryAdvice(buffer, advice, m_p->m_device_id);
409}
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
416{
417 _checkIsInit();
418 m_p->runtime()->setCurrentDevice(m_p->m_device_id);
419}
420
421/*---------------------------------------------------------------------------*/
422/*---------------------------------------------------------------------------*/
423
425deviceId() const
426{
427 return m_p->m_device_id;
428}
429
430/*---------------------------------------------------------------------------*/
431/*---------------------------------------------------------------------------*/
432
434deviceInfo() const
435{
436 _checkIsInit();
438 Int32 nb_device = dlist->nbDevice();
439 if (nb_device == 0)
440 ARCCORE_FATAL("Internal error: no device available");
441 Int32 device_id = deviceId().asInt32();
442 if (device_id >= nb_device)
443 device_id = 0;
444 return dlist->deviceInfo(device_id);
445}
446
447/*---------------------------------------------------------------------------*/
448/*---------------------------------------------------------------------------*/
449
452{
453 if (policy == eExecutionPolicy::None)
454 return nullptr;
455 Impl::IRunnerRuntime* r = _getRuntime(policy);
456 return r->deviceInfoList();
457}
458
459/*---------------------------------------------------------------------------*/
460/*---------------------------------------------------------------------------*/
461
463deviceMemoryInfo() const
464{
465 _checkIsInit();
466 return m_p->runtime()->getDeviceMemoryInfo(deviceId());
467}
468
469/*---------------------------------------------------------------------------*/
470/*---------------------------------------------------------------------------*/
471
473fillPointerAttribute(PointerAttribute& attr, const void* ptr)
474{
475 _checkIsInit();
476 m_p->runtime()->getPointerAttribute(attr, ptr);
477}
478
479/*---------------------------------------------------------------------------*/
480/*---------------------------------------------------------------------------*/
481
482bool Runner::
483_isAutoPrefetchCommand() const
484{
485 return m_p->isAutoPrefetchCommand();
486}
487
488/*---------------------------------------------------------------------------*/
489/*---------------------------------------------------------------------------*/
490
491RunnerInternal* Runner::
493{
494 return m_p->_internalApi();
495}
496
497/*---------------------------------------------------------------------------*/
498/*---------------------------------------------------------------------------*/
499
500/*!
501 * \brief Stops all ongoing profiling in all runtimes.
502 *
503 * Generally, this is used at the end of computation.
504 */
505void RunnerInternal::
506stopAllProfiling()
507{
508 _stopProfiling(eExecutionPolicy::CUDA);
509 _stopProfiling(eExecutionPolicy::HIP);
510 _stopProfiling(eExecutionPolicy::Sequential);
511 _stopProfiling(eExecutionPolicy::Thread);
512}
513
514/*---------------------------------------------------------------------------*/
515/*---------------------------------------------------------------------------*/
516
517void RunnerInternal::
518finalize(ITraceMng* tm)
519{
520 _finalize(eExecutionPolicy::CUDA, tm);
521 _finalize(eExecutionPolicy::HIP, tm);
522 _finalize(eExecutionPolicy::Sequential, tm);
523 _finalize(eExecutionPolicy::Thread, tm);
524}
525
526/*---------------------------------------------------------------------------*/
527/*---------------------------------------------------------------------------*/
528
529void RunnerInternal::
530startProfiling()
531{
532 m_runner_impl->runtime()->startProfiling();
533}
534
535/*---------------------------------------------------------------------------*/
536/*---------------------------------------------------------------------------*/
537
538void RunnerInternal::
539stopProfiling()
540{
541 m_runner_impl->runtime()->stopProfiling();
542}
543
544/*---------------------------------------------------------------------------*/
545/*---------------------------------------------------------------------------*/
546
547bool RunnerInternal::
548isProfilingActive()
549{
550 return m_runner_impl->runtime()->isProfilingActive();
551}
552
553/*---------------------------------------------------------------------------*/
554/*---------------------------------------------------------------------------*/
555
556void RunnerInternal::
557printProfilingInfos(std::ostream& o)
558{
559 bool is_active = isProfilingActive();
560 if (is_active)
561 stopProfiling();
562
563 {
564 // Displays profiling statistics.
565 using Arcane::Impl::AcceleratorStatInfoList;
566 auto f = [&](const AcceleratorStatInfoList& stat_list) {
567 stat_list.print(o);
568 };
570 }
571
572 if (is_active)
573 startProfiling();
574}
575
576/*---------------------------------------------------------------------------*/
577/*---------------------------------------------------------------------------*/
578
579extern "C++" ePointerAccessibility
580getPointerAccessibility(Runner* runner, const void* ptr, PointerAttribute* ptr_attr)
581{
582 if (!runner)
584 return Impl::RuntimeStaticInfo::getPointerAccessibility(runner->executionPolicy(), ptr, ptr_attr);
585}
586
587extern "C++" void Impl::
588arcaneCheckPointerIsAccessible(const Runner* runner, const void* ptr,
589 const char* name, const TraceInfo& ti)
590{
591 if (!runner)
592 return;
593 return Impl::RuntimeStaticInfo::checkPointerIsAcccessible(runner->executionPolicy(), ptr, name, ti);
594}
595
596/*---------------------------------------------------------------------------*/
597/*---------------------------------------------------------------------------*/
598
599/*---------------------------------------------------------------------------*/
600/*---------------------------------------------------------------------------*/
601
602void Impl::IRunnerRuntime::
603_fillPointerAttribute(PointerAttribute& attribute,
604 ePointerMemoryType mem_type,
605 int device, const void* pointer, const void* device_pointer,
606 const void* host_pointer)
607{
608 attribute = PointerAttribute(mem_type, device, pointer, device_pointer, host_pointer);
609}
610
611/*---------------------------------------------------------------------------*/
612/*---------------------------------------------------------------------------*/
613
614void Impl::IRunnerRuntime::
615_fillPointerAttribute(PointerAttribute& attribute, const void* pointer)
616{
617 attribute = PointerAttribute(pointer);
618}
619
620/*---------------------------------------------------------------------------*/
621/*---------------------------------------------------------------------------*/
622
623Impl::KernelLaunchArgs Impl::IRunnerRuntime::
624computeKernalLaunchArgs(const Impl::KernelLaunchArgs& orig_args,
625 [[maybe_unused]] const void* kernel_ptr,
626 [[maybe_unused]] Int64 total_loop_size)
627{
628 return orig_args;
629}
630
631/*---------------------------------------------------------------------------*/
632/*---------------------------------------------------------------------------*/
633
634} // namespace Arcane::Accelerator
635
636/*---------------------------------------------------------------------------*/
637/*---------------------------------------------------------------------------*/
#define ARCCORE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCCORE_THROW(exception_class,...)
Macro to throw an exception with formatting.
#define ARCCORE_CHECK_POINTER(ptr)
Macro that returns the pointer ptr if it is not null or throws an exception if it is null.
virtual const DeviceInfo & deviceInfo(Int32 i) const =0
Information about the i-th device.
virtual Int32 nbDevice() const =0
Number of devices in the list.
void fillPointerAttribute(PointerAttribute &attr, const void *ptr)
Fills attr with information concerning the memory region pointed to by ptr.
Definition Runner.cc:473
void setConcurrentQueueCreation(bool v)
Indicates whether multiple threads are allowed to create RunQueues.
Definition Runner.cc:321
static const IDeviceInfoList * deviceInfoList(eExecutionPolicy policy)
List of devices for the execution policy policy.
Definition Runner.cc:451
bool isInitialized() const
Indicates whether the instance has been initialized.
Definition Runner.cc:312
Runner()
Creates an uninitialized execution manager.
Definition Runner.cc:261
RunnerInternal * _internalApi()
Internal API for Arcane.
Definition Runner.cc:492
double cumulativeCommandTime() const
Total time spent in commands associated with this instance.
Definition Runner.cc:386
bool isConcurrentQueueCreation() const
Indicates whether concurrent creation of multiple RunQueues is allowed.
Definition Runner.cc:330
DeviceId deviceId() const
Device associated with this instance.
Definition Runner.cc:425
void setDeviceReducePolicy(eDeviceReducePolicy v)
Sets the execution policy for reductions.
Definition Runner.cc:339
const DeviceInfo & deviceInfo() const
Information about the device associated with this instance.
Definition Runner.cc:434
DeviceMemoryInfo deviceMemoryInfo() const
Information about the device associated with this instance.
Definition Runner.cc:463
void initialize(eExecutionPolicy v)
Initializes the instance. This method must be called only once.
Definition Runner.cc:358
void setAsCurrentDevice()
Sets the device associated with this instance as the default context device.
Definition Runner.cc:415
eDeviceReducePolicy deviceReducePolicy() const
Reduction execution policy.
Definition Runner.cc:349
void setMemoryAdvice(ConstMemoryView buffer, eMemoryAdvice advice)
Sets memory advice for a memory region.
Definition Runner.cc:395
void unsetMemoryAdvice(ConstMemoryView buffer, eMemoryAdvice advice)
Unsets memory advice for a memory region.
Definition Runner.cc:405
eExecutionPolicy executionPolicy() const
Associated execution policy.
Definition Runner.cc:303
Constant view on a contiguous memory region containing fixed-size elements.
static std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
static void visitAcceleratorStat(const std::function< void(const Impl::AcceleratorStatInfoList &)> &f)
Visits the accelerator statistics list.
Definition Profiling.cc:300
Namespace for accelerator usage.
ePointerAccessibility getPointerAccessibility(eExecutionPolicy policy, const void *ptr, PointerAttribute *ptr_attr)
Accessibility of address ptr for execution policypolicy.
eDeviceReducePolicy
Reduction operation policy on accelerators.
@ Grid
Uses a compute kernel with synchronization between blocks.
ePointerAccessibility
Accessibility information of a memory address.
ePointerMemoryType
Memory type for a pointer.
eExecutionPolicy
Execution policy for a Runner.
@ SYCL
Execution policy using the SYCL environment.
@ HIP
Execution policy using the HIP environment.
@ CUDA
Execution policy using the CUDA environment.
@ Thread
Multi-threaded execution policy.
std::int64_t Int64
Signed integer type of 64 bits.
std::int32_t Int32
Signed integer type of 32 bits.