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