Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
HipAcceleratorRuntime.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/* HipAcceleratorRuntime.cc (C) 2000-2026 */
9/* */
10/* Runtime pour 'HIP'. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/accelerator_native/HipAccelerator.h"
15
16#include "arccore/base/CheckedConvert.h"
17#include "arccore/base/FatalErrorException.h"
18
19#include "arccore/common/internal/MemoryUtilsInternal.h"
20#include "arccore/common/internal/IMemoryResourceMngInternal.h"
21
22#include "arccore/common/accelerator/RunQueueBuildInfo.h"
23#include "arccore/common/accelerator/Memory.h"
24#include "arccore/common/accelerator/DeviceInfoList.h"
25#include "arccore/common/accelerator/KernelLaunchArgs.h"
26#include "arccore/common/accelerator/RunQueue.h"
27#include "arccore/common/accelerator/DeviceMemoryInfo.h"
28#include "arccore/common/accelerator/NativeStream.h"
29#include "arccore/common/accelerator/internal/IRunnerRuntime.h"
30#include "arccore/common/accelerator/internal/RegisterRuntimeInfo.h"
31#include "arccore/common/accelerator/internal/RunCommandImpl.h"
32#include "arccore/common/accelerator/internal/IRunQueueStream.h"
33#include "arccore/common/accelerator/internal/IRunQueueEventImpl.h"
34#include "arccore/common/accelerator/internal/AcceleratorMemoryAllocatorBase.h"
35
36#include <sstream>
37#include <algorithm>
38#include <iostream>
39
40#ifdef ARCCORE_HAS_ROCTX
41#include <roctx.h>
42#endif
43
44using namespace Arccore;
45
46namespace Arcane::Accelerator::Hip
47{
48using Impl::KernelLaunchArgs;
49
50/*---------------------------------------------------------------------------*/
51/*---------------------------------------------------------------------------*/
52
54{
55 public:
56
57 virtual ~ConcreteAllocator() = default;
58
59 public:
60
61 virtual hipError_t _allocate(void** ptr, size_t new_size) = 0;
62 virtual hipError_t _deallocate(void* ptr) = 0;
63};
64
65/*---------------------------------------------------------------------------*/
66/*---------------------------------------------------------------------------*/
67
68template <typename ConcreteAllocatorType>
69class UnderlyingAllocator
71{
72 public:
73
74 UnderlyingAllocator() = default;
75
76 public:
77
78 void* allocateMemory(Int64 size) final
79 {
80 void* out = nullptr;
81 ARCCORE_CHECK_HIP(m_concrete_allocator._allocate(&out, size));
82 return out;
83 }
84 void freeMemory(void* ptr, [[maybe_unused]] Int64 size) final
85 {
86 ARCCORE_CHECK_HIP_NOTHROW(m_concrete_allocator._deallocate(ptr));
87 }
88
89 void doMemoryCopy(void* destination, const void* source, Int64 size) final
90 {
91 ARCCORE_CHECK_HIP(hipMemcpy(destination, source, size, hipMemcpyDefault));
92 }
93
94 eMemoryResource memoryResource() const final
95 {
96 return m_concrete_allocator.memoryResource();
97 }
98
99 public:
100
101 ConcreteAllocatorType m_concrete_allocator;
102};
103
104/*---------------------------------------------------------------------------*/
105/*---------------------------------------------------------------------------*/
106
108: public ConcreteAllocator
109{
110 public:
111
112 hipError_t _deallocate(void* ptr) final
113 {
114 return ::hipFree(ptr);
115 }
116
117 hipError_t _allocate(void** ptr, size_t new_size) final
118 {
119 auto r = ::hipMallocManaged(ptr, new_size, hipMemAttachGlobal);
120 return r;
121 }
122
123 constexpr eMemoryResource memoryResource() const { return eMemoryResource::UnifiedMemory; }
124};
125
126/*---------------------------------------------------------------------------*/
127/*---------------------------------------------------------------------------*/
128
129class UnifiedMemoryHipMemoryAllocator
130: public AcceleratorMemoryAllocatorBase
131{
132 public:
133
134 UnifiedMemoryHipMemoryAllocator()
135 : AcceleratorMemoryAllocatorBase("UnifiedMemoryHipMemory", new UnderlyingAllocator<UnifiedMemoryConcreteAllocator>())
136 {
137 }
138
139 public:
140
141 void initialize()
142 {
143 _doInitializeUVM(true);
144 }
145};
146
147/*---------------------------------------------------------------------------*/
148/*---------------------------------------------------------------------------*/
149
151: public ConcreteAllocator
152{
153 public:
154
155 hipError_t _allocate(void** ptr, size_t new_size) final
156 {
157 return ::hipHostMalloc(ptr, new_size);
158 }
159 hipError_t _deallocate(void* ptr) final
160 {
161 return ::hipHostFree(ptr);
162 }
163 constexpr eMemoryResource memoryResource() const { return eMemoryResource::HostPinned; }
164};
165
166/*---------------------------------------------------------------------------*/
167/*---------------------------------------------------------------------------*/
168
169class HostPinnedHipMemoryAllocator
170: public AcceleratorMemoryAllocatorBase
171{
172 public:
173 public:
174
175 HostPinnedHipMemoryAllocator()
176 : AcceleratorMemoryAllocatorBase("HostPinnedHipMemory", new UnderlyingAllocator<HostPinnedConcreteAllocator>())
177 {
178 }
179
180 public:
181
182 void initialize()
183 {
185 }
186};
187
188/*---------------------------------------------------------------------------*/
189/*---------------------------------------------------------------------------*/
190
191class DeviceConcreteAllocator
192: public ConcreteAllocator
193{
194 public:
195
196 DeviceConcreteAllocator()
197 {
198 }
199
200 hipError_t _allocate(void** ptr, size_t new_size) final
201 {
202 hipError_t r = ::hipMalloc(ptr, new_size);
203 return r;
204 }
205 hipError_t _deallocate(void* ptr) final
206 {
207 return ::hipFree(ptr);
208 }
209
210 constexpr eMemoryResource memoryResource() const { return eMemoryResource::Device; }
211};
212
213/*---------------------------------------------------------------------------*/
214/*---------------------------------------------------------------------------*/
215
216class DeviceHipMemoryAllocator
217: public AcceleratorMemoryAllocatorBase
218{
219
220 public:
221
222 DeviceHipMemoryAllocator()
223 : AcceleratorMemoryAllocatorBase("DeviceHipMemoryAllocator", new UnderlyingAllocator<DeviceConcreteAllocator>())
224 {
225 }
226
227 public:
228
229 void initialize()
230 {
232 }
233};
234
235/*---------------------------------------------------------------------------*/
236/*---------------------------------------------------------------------------*/
237
238namespace
239{
240 UnifiedMemoryHipMemoryAllocator unified_memory_hip_memory_allocator;
241 HostPinnedHipMemoryAllocator host_pinned_hip_memory_allocator;
242 DeviceHipMemoryAllocator device_hip_memory_allocator;
243} // namespace
244
245/*---------------------------------------------------------------------------*/
246/*---------------------------------------------------------------------------*/
247
248void initializeHipMemoryAllocators()
249{
250 unified_memory_hip_memory_allocator.initialize();
251 device_hip_memory_allocator.initialize();
252 host_pinned_hip_memory_allocator.initialize();
253}
254
255void finalizeHipMemoryAllocators(ITraceMng* tm)
256{
257 unified_memory_hip_memory_allocator.finalize(tm);
258 device_hip_memory_allocator.finalize(tm);
259 host_pinned_hip_memory_allocator.finalize(tm);
260}
261
262/*---------------------------------------------------------------------------*/
263/*---------------------------------------------------------------------------*/
264
265class HipRunQueueStream
267{
268 public:
269
270 HipRunQueueStream(Impl::IRunnerRuntime* runtime, const RunQueueBuildInfo& bi)
271 : m_runtime(runtime)
272 {
273 if (bi.isDefault())
274 ARCCORE_CHECK_HIP(hipStreamCreate(&m_hip_stream));
275 else {
276 int priority = bi.priority();
277 ARCCORE_CHECK_HIP(hipStreamCreateWithPriority(&m_hip_stream, hipStreamDefault, priority));
278 }
279 }
280 ~HipRunQueueStream() override
281 {
282 ARCCORE_CHECK_HIP_NOTHROW(hipStreamDestroy(m_hip_stream));
283 }
284
285 public:
286
287 void notifyBeginLaunchKernel([[maybe_unused]] Impl::RunCommandImpl& c) override
288 {
289#ifdef ARCCORE_HAS_ROCTX
290 auto kname = c.kernelName();
291 if (kname.empty())
292 roctxRangePush(c.traceInfo().name());
293 else
294 roctxRangePush(kname.localstr());
295#endif
296 return m_runtime->notifyBeginLaunchKernel();
297 }
299 {
300#ifdef ARCCORE_HAS_ROCTX
301 roctxRangePop();
302#endif
303 return m_runtime->notifyEndLaunchKernel();
304 }
305 void barrier() override
306 {
307 ARCCORE_CHECK_HIP(hipStreamSynchronize(m_hip_stream));
308 }
309 bool _barrierNoException() override
310 {
311 return hipStreamSynchronize(m_hip_stream) != hipSuccess;
312 }
313 void copyMemory(const MemoryCopyArgs& args) override
314 {
315 auto r = hipMemcpyAsync(args.destination().data(), args.source().data(),
316 args.source().bytes().size(), hipMemcpyDefault, m_hip_stream);
317 ARCCORE_CHECK_HIP(r);
318 if (!args.isAsync())
319 barrier();
320 }
321 void prefetchMemory(const MemoryPrefetchArgs& args) override
322 {
323 auto src = args.source().bytes();
324 if (src.size() == 0)
325 return;
326 DeviceId d = args.deviceId();
327 int device = hipCpuDeviceId;
328 if (!d.isHost())
329 device = d.asInt32();
330 auto r = hipMemPrefetchAsync(src.data(), src.size(), device, m_hip_stream);
331 ARCCORE_CHECK_HIP(r);
332 if (!args.isAsync())
333 barrier();
334 }
336 {
337 return Impl::NativeStream(&m_hip_stream);
338 }
339
340 public:
341
342 hipStream_t trueStream() const
343 {
344 return m_hip_stream;
345 }
346
347 private:
348
349 Impl::IRunnerRuntime* m_runtime;
350 hipStream_t m_hip_stream;
351};
352
353/*---------------------------------------------------------------------------*/
354/*---------------------------------------------------------------------------*/
355
356class HipRunQueueEvent
358{
359 public:
360
361 explicit HipRunQueueEvent(bool has_timer)
362 {
363 if (has_timer)
364 ARCCORE_CHECK_HIP(hipEventCreate(&m_hip_event));
365 else
366 ARCCORE_CHECK_HIP(hipEventCreateWithFlags(&m_hip_event, hipEventDisableTiming));
367 }
368 ~HipRunQueueEvent() override
369 {
370 ARCCORE_CHECK_HIP_NOTHROW(hipEventDestroy(m_hip_event));
371 }
372
373 public:
374
375 // Enregistre l'événement au sein d'une RunQueue
376 void recordQueue(Impl::IRunQueueStream* stream) final
377 {
378 auto* rq = static_cast<HipRunQueueStream*>(stream);
379 ARCCORE_CHECK_HIP(hipEventRecord(m_hip_event, rq->trueStream()));
380 }
381
382 void wait() final
383 {
384 ARCCORE_CHECK_HIP(hipEventSynchronize(m_hip_event));
385 }
386
387 void waitForEvent(Impl::IRunQueueStream* stream) final
388 {
389 auto* rq = static_cast<HipRunQueueStream*>(stream);
390 ARCCORE_CHECK_HIP(hipStreamWaitEvent(rq->trueStream(), m_hip_event, 0));
391 }
392
393 Int64 elapsedTime(IRunQueueEventImpl* from_event) final
394 {
395 auto* true_from_event = static_cast<HipRunQueueEvent*>(from_event);
396 ARCCORE_CHECK_POINTER(true_from_event);
397 float time_in_ms = 0.0;
398 ARCCORE_CHECK_HIP(hipEventElapsedTime(&time_in_ms, true_from_event->m_hip_event, m_hip_event));
399 double x = time_in_ms * 1.0e6;
400 Int64 nano_time = static_cast<Int64>(x);
401 return nano_time;
402 }
403
404 bool hasPendingWork() final
405 {
406 hipError_t v = hipEventQuery(m_hip_event);
407 if (v == hipErrorNotReady)
408 return true;
409 ARCCORE_CHECK_HIP(v);
410 return false;
411 }
412
413 private:
414
415 hipEvent_t m_hip_event;
416};
417/*---------------------------------------------------------------------------*/
418/*---------------------------------------------------------------------------*/
419
422{
423 public:
424
425 ~HipRunnerRuntime() override = default;
426
427 public:
428
429 void notifyBeginLaunchKernel() override
430 {
431 ++m_nb_kernel_launched;
432 if (m_is_verbose)
433 std::cout << "BEGIN HIP KERNEL!\n";
434 }
435 void notifyEndLaunchKernel() override
436 {
437 ARCCORE_CHECK_HIP(hipGetLastError());
438 if (m_is_verbose)
439 std::cout << "END HIP KERNEL!\n";
440 }
441 void barrier() override
442 {
443 ARCCORE_CHECK_HIP(hipDeviceSynchronize());
444 }
445 eExecutionPolicy executionPolicy() const override
446 {
448 }
449 Impl::IRunQueueStream* createStream(const RunQueueBuildInfo& bi) override
450 {
451 return new HipRunQueueStream(this, bi);
452 }
453 Impl::IRunQueueEventImpl* createEventImpl() override
454 {
455 return new HipRunQueueEvent(false);
456 }
457 Impl::IRunQueueEventImpl* createEventImplWithTimer() override
458 {
459 return new HipRunQueueEvent(true);
460 }
461 void setMemoryAdvice(ConstMemoryView buffer, eMemoryAdvice advice, DeviceId device_id) override
462 {
463 auto v = buffer.bytes();
464 const void* ptr = v.data();
465 size_t count = v.size();
466 int device = device_id.asInt32();
467 hipMemoryAdvise hip_advise;
468
469 if (advice == eMemoryAdvice::MostlyRead)
470 hip_advise = hipMemAdviseSetReadMostly;
472 hip_advise = hipMemAdviseSetPreferredLocation;
473 else if (advice == eMemoryAdvice::AccessedByDevice)
474 hip_advise = hipMemAdviseSetAccessedBy;
475 else if (advice == eMemoryAdvice::PreferredLocationHost) {
476 hip_advise = hipMemAdviseSetPreferredLocation;
477 device = hipCpuDeviceId;
478 }
479 else if (advice == eMemoryAdvice::AccessedByHost) {
480 hip_advise = hipMemAdviseSetAccessedBy;
481 device = hipCpuDeviceId;
482 }
483 else
484 return;
485 //std::cout << "MEMADVISE p=" << ptr << " size=" << count << " advise = " << hip_advise << " id = " << device << "\n";
486 ARCCORE_CHECK_HIP(hipMemAdvise(ptr, count, hip_advise, device));
487 }
488 void unsetMemoryAdvice(ConstMemoryView buffer, eMemoryAdvice advice, DeviceId device_id) override
489 {
490 auto v = buffer.bytes();
491 const void* ptr = v.data();
492 size_t count = v.size();
493 int device = device_id.asInt32();
494 hipMemoryAdvise hip_advise;
495
496 if (advice == eMemoryAdvice::MostlyRead)
497 hip_advise = hipMemAdviseUnsetReadMostly;
499 hip_advise = hipMemAdviseUnsetPreferredLocation;
500 else if (advice == eMemoryAdvice::AccessedByDevice)
501 hip_advise = hipMemAdviseUnsetAccessedBy;
502 else if (advice == eMemoryAdvice::PreferredLocationHost) {
503 hip_advise = hipMemAdviseUnsetPreferredLocation;
504 device = hipCpuDeviceId;
505 }
506 else if (advice == eMemoryAdvice::AccessedByHost) {
507 hip_advise = hipMemAdviseUnsetAccessedBy;
508 device = hipCpuDeviceId;
509 }
510 else
511 return;
512 ARCCORE_CHECK_HIP(hipMemAdvise(ptr, count, hip_advise, device));
513 }
514
515 void setCurrentDevice(DeviceId device_id) final
516 {
517 Int32 id = device_id.asInt32();
518 ARCCORE_FATAL_IF(!device_id.isAccelerator(), "Device {0} is not an accelerator device", id);
519 ARCCORE_CHECK_HIP(hipSetDevice(id));
520 }
521 const IDeviceInfoList* deviceInfoList() override { return &m_device_info_list; }
522
523 void getPointerAttribute(PointerAttribute& attribute, const void* ptr) override
524 {
525 hipPointerAttribute_t pa;
526 hipError_t ret_value = hipPointerGetAttributes(&pa, ptr);
527 auto mem_type = ePointerMemoryType::Unregistered;
528 // Si \a ptr n'a pas été alloué dynamiquement (i.e: il est sur la pile),
529 // hipPointerGetAttribute() retourne une erreur. Dans ce cas on considère
530 // la mémoire comme non enregistrée.
531 if (ret_value == hipSuccess) {
532#if HIP_VERSION_MAJOR >= 6
533 auto rocm_memory_type = pa.type;
534#else
535 auto rocm_memory_type = pa.memoryType;
536#endif
537 if (pa.isManaged)
538 mem_type = ePointerMemoryType::Managed;
539 else if (rocm_memory_type == hipMemoryTypeHost)
540 mem_type = ePointerMemoryType::Host;
541 else if (rocm_memory_type == hipMemoryTypeDevice)
542 mem_type = ePointerMemoryType::Device;
543 }
544
545 //std::cout << "HIP Info: hip_memory_type=" << (int)pa.memoryType << " is_managed?=" << pa.isManaged
546 // << " flags=" << pa.allocationFlags
547 // << " my_memory_type=" << (int)mem_type
548 // << "\n";
549 _fillPointerAttribute(attribute, mem_type, pa.device,
550 ptr, pa.devicePointer, pa.hostPointer);
551 }
552
553 DeviceMemoryInfo getDeviceMemoryInfo(DeviceId device_id) override
554 {
555 int d = 0;
556 int wanted_d = device_id.asInt32();
557 ARCCORE_CHECK_HIP(hipGetDevice(&d));
558 if (d != wanted_d)
559 ARCCORE_CHECK_HIP(hipSetDevice(wanted_d));
560 size_t free_mem = 0;
561 size_t total_mem = 0;
562 ARCCORE_CHECK_HIP(hipMemGetInfo(&free_mem, &total_mem));
563 if (d != wanted_d)
564 ARCCORE_CHECK_HIP(hipSetDevice(d));
566 dmi.setFreeMemory(free_mem);
567 dmi.setTotalMemory(total_mem);
568 return dmi;
569 }
570
571 void pushProfilerRange(const String& name, [[maybe_unused]] Int32 color) override
572 {
573#ifdef ARCCORE_HAS_ROCTX
574 roctxRangePush(name.localstr());
575#endif
576 }
577 void popProfilerRange() override
578 {
579#ifdef ARCCORE_HAS_ROCTX
580 roctxRangePop();
581#endif
582 }
583
584 void finalize(ITraceMng* tm) override
585 {
586 finalizeHipMemoryAllocators(tm);
587 }
588
589 KernelLaunchArgs computeKernalLaunchArgs(const KernelLaunchArgs& orig_args,
590 const void* kernel_ptr,
591 Int64 total_loop_size) override
592 {
593 Int32 shared_memory = orig_args.sharedMemorySize();
594 if (orig_args.isCooperative()) {
595 // En mode coopératif, s'assure qu'on ne lance pas plus de blocs
596 // que le maximum qui peut résider sur le GPU.
597 Int32 nb_thread = orig_args.nbThreadPerBlock();
598 Int32 nb_block = orig_args.nbBlockPerGrid();
599 int nb_block_per_sm = 0;
600 ARCCORE_CHECK_HIP(hipOccupancyMaxActiveBlocksPerMultiprocessor(&nb_block_per_sm, kernel_ptr, nb_thread, shared_memory));
601
602 int max_block = static_cast<int>((nb_block_per_sm * m_multi_processor_count) * m_cooperative_ratio);
603 max_block = std::max(max_block, 1);
604 if (nb_block > max_block) {
605 KernelLaunchArgs modified_args(orig_args);
606 modified_args.setNbBlockPerGrid(max_block);
607 return modified_args;
608 }
609 }
610 return orig_args;
611 }
612
613 public:
614
615 void fillDevices(bool is_verbose);
616
617 void build()
618 {
619 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_ACCELERATOR_COOPERATIVE_RATIO", true)) {
620 Int32 x = v.value();
621 x = std::clamp(x, 10, 100);
622 m_cooperative_ratio = x / 100.0;
623 }
624 }
625
626 private:
627
628 Int64 m_nb_kernel_launched = 0;
629 bool m_is_verbose = false;
630 Int32 m_multi_processor_count = 0;
631 double m_cooperative_ratio = 1.0;
632 Impl::DeviceInfoList m_device_info_list;
633};
634
635/*---------------------------------------------------------------------------*/
636/*---------------------------------------------------------------------------*/
637
638void HipRunnerRuntime::
639fillDevices(bool is_verbose)
640{
641 int nb_device = 0;
642 ARCCORE_CHECK_HIP(hipGetDeviceCount(&nb_device));
643 std::ostream& omain = std::cout;
644 if (is_verbose)
645 omain << "ArcaneHIP: Initialize Arcane HIP runtime nb_available_device=" << nb_device << "\n";
646 for (int i = 0; i < nb_device; ++i) {
647 std::ostringstream ostr;
648 std::ostream& o = ostr;
649
650 hipDeviceProp_t dp;
651 ARCCORE_CHECK_HIP(hipGetDeviceProperties(&dp, i));
652
653 int has_managed_memory = 0;
654 ARCCORE_CHECK_HIP(hipDeviceGetAttribute(&has_managed_memory, hipDeviceAttributeManagedMemory, i));
655
656 // Le format des versions dans HIP est :
657 // HIP_VERSION = (HIP_VERSION_MAJOR * 10000000 + HIP_VERSION_MINOR * 100000 + HIP_VERSION_PATCH)
658
659 int runtime_version = 0;
660 ARCCORE_CHECK_HIP(hipRuntimeGetVersion(&runtime_version));
661 //runtime_version /= 10000;
662 int runtime_major = runtime_version / 10000000;
663 int runtime_minor = (runtime_version / 100000) % 100;
664
665 int driver_version = 0;
666 ARCCORE_CHECK_HIP(hipDriverGetVersion(&driver_version));
667 //driver_version /= 10000;
668 int driver_major = driver_version / 10000000;
669 int driver_minor = (driver_version / 100000) % 100;
670
671 o << "\nDevice " << i << " name=" << dp.name << "\n";
672 o << " Driver version = " << driver_major << "." << (driver_minor) << "." << (driver_version % 100000) << "\n";
673 o << " Runtime version = " << runtime_major << "." << (runtime_minor) << "." << (runtime_version % 100000) << "\n";
674 o << " computeCapability = " << dp.major << "." << dp.minor << "\n";
675 o << " totalGlobalMem = " << dp.totalGlobalMem << "\n";
676 o << " regsPerBlock = " << dp.regsPerBlock << "\n";
677 o << " warpSize = " << dp.warpSize << "\n";
678 o << " memPitch = " << dp.memPitch << "\n";
679 o << " maxThreadsPerBlock = " << dp.maxThreadsPerBlock << "\n";
680 o << " maxBlocksPerMultiProcessor = " << dp.maxBlocksPerMultiProcessor << "\n";
681 o << " maxThreadsPerMultiProcessor = " << dp.maxThreadsPerMultiProcessor << "\n";
682 o << " totalConstMem = " << dp.totalConstMem << "\n";
683 o << " clockRate = " << dp.clockRate << "\n";
684 //o << " deviceOverlap = " << dp.deviceOverlap<< "\n";
685 o << " multiProcessorCount = " << dp.multiProcessorCount << "\n";
686 o << " kernelExecTimeoutEnabled = " << dp.kernelExecTimeoutEnabled << "\n";
687 o << " integrated = " << dp.integrated << "\n";
688 o << " canMapHostMemory = " << dp.canMapHostMemory << "\n";
689 o << " computeMode = " << dp.computeMode << "\n";
690 o << " maxThreadsDim = " << dp.maxThreadsDim[0] << " " << dp.maxThreadsDim[1]
691 << " " << dp.maxThreadsDim[2] << "\n";
692 o << " maxGridSize = " << dp.maxGridSize[0] << " " << dp.maxGridSize[1]
693 << " " << dp.maxGridSize[2] << "\n";
694 o << " concurrentManagedAccess = " << dp.concurrentManagedAccess << "\n";
695 o << " directManagedMemAccessFromHost = " << dp.directManagedMemAccessFromHost << "\n";
696 o << " gcnArchName = " << dp.gcnArchName << "\n";
697 o << " pageableMemoryAccess = " << dp.pageableMemoryAccess << "\n";
698 o << " pageableMemoryAccessUsesHostPageTables = " << dp.pageableMemoryAccessUsesHostPageTables << "\n";
699 o << " hasManagedMemory = " << has_managed_memory << "\n";
700 o << " pciInfo = " << dp.pciDomainID << " " << dp.pciBusID << " " << dp.pciDeviceID << "\n";
701 o << " memoryBusWitdh = " << dp.memoryBusWidth << " bits\n";
702
703 int clock_rate = 0;
704 ARCCORE_CHECK_HIP(hipDeviceGetAttribute(&clock_rate, hipDeviceAttributeClockRate, i));
705 o << " clockRate = " << (clock_rate / 1000) << " MHz\n";
706
707 int memory_clock_rate = 0;
708 ARCCORE_CHECK_HIP(hipDeviceGetAttribute(&memory_clock_rate, hipDeviceAttributeMemoryClockRate, i));
709 o << " memoryClockRate = " << (memory_clock_rate / 1000) << " MHz\n";
710
711 // Sur AMD, la fréquence donnée pour la mémoire doit être multipliée par 8
712 // pour avoir la bande passante d'un bit du bus (comme il faut aussi diviser par 8
713 // pour avoir la valeur en octet, on supprime simplement cette division)
714 Real memory_bandwith = (dp.memoryBusWidth * memory_clock_rate * 2.0) / 1.0e6;
715 o << " MemoryBandwith = " << memory_bandwith << " GB/s\n";
716
717#if HIP_VERSION_MAJOR >= 6
718 o << " sharedMemPerMultiprocessor = " << dp.sharedMemPerMultiprocessor << "\n";
719 o << " sharedMemPerBlock = " << dp.sharedMemPerBlock << "\n";
720 o << " sharedMemPerBlockOptin = " << dp.sharedMemPerBlockOptin << "\n";
721 o << " gpuDirectRDMASupported = " << dp.gpuDirectRDMASupported << "\n";
722 o << " hostNativeAtomicSupported = " << dp.hostNativeAtomicSupported << "\n";
723 o << " unifiedFunctionPointers = " << dp.unifiedFunctionPointers << "\n";
724#endif
725
726 // TODO: On suppose que tous les GPUs sont les mêmes et donc
727 // que le nombre de SM par GPU est le même. Cela est utilisé pour
728 // calculer le nombre de blocs en mode coopératif.
729 m_multi_processor_count = dp.multiProcessorCount;
730
731 std::ostringstream device_uuid_ostr;
732 {
733 hipDevice_t device;
734 ARCCORE_CHECK_HIP(hipDeviceGet(&device, i));
735 hipUUID device_uuid;
736 ARCCORE_CHECK_HIP(hipDeviceGetUuid(&device_uuid, device));
737 o << " deviceUuid=";
738 Impl::printUUID(device_uuid_ostr, device_uuid.bytes);
739 o << device_uuid_ostr.str();
740 o << "\n";
741 }
742
743 String description(ostr.str());
744 if (is_verbose)
745 omain << description;
746
747 DeviceInfo device_info;
748 device_info.setDescription(description);
749 device_info.setDeviceId(DeviceId(i));
750 device_info.setName(dp.name);
751 device_info.setWarpSize(dp.warpSize);
752 device_info.setUUIDAsString(device_uuid_ostr.str());
753 device_info.setSharedMemoryPerBlock(static_cast<Int32>(dp.sharedMemPerBlock));
754#if HIP_VERSION_MAJOR >= 6
755 device_info.setSharedMemoryPerMultiprocessor(static_cast<Int32>(dp.sharedMemPerMultiprocessor));
756 device_info.setSharedMemoryPerBlockOptin(static_cast<Int32>(dp.sharedMemPerBlockOptin));
757#endif
758 device_info.setTotalConstMemory(static_cast<Int32>(dp.totalConstMem));
759 device_info.setPCIDomainID(dp.pciDomainID);
760 device_info.setPCIBusID(dp.pciBusID);
761 device_info.setPCIDeviceID(dp.pciDeviceID);
762 m_device_info_list.addDevice(device_info);
763 }
764}
765
766/*---------------------------------------------------------------------------*/
767/*---------------------------------------------------------------------------*/
768
770: public IMemoryCopier
771{
772 void copy(ConstMemoryView from, [[maybe_unused]] eMemoryResource from_mem,
773 MutableMemoryView to, [[maybe_unused]] eMemoryResource to_mem,
774 const RunQueue* queue) override
775 {
776 if (queue) {
777 queue->copyMemory(MemoryCopyArgs(to.bytes(), from.bytes()).addAsync(queue->isAsync()));
778 return;
779 }
780 // 'hipMemcpyDefault' sait automatiquement ce qu'il faut faire en tenant
781 // uniquement compte de la valeur des pointeurs. Il faudrait voir si
782 // utiliser \a from_mem et \a to_mem peut améliorer les performances.
783 ARCCORE_CHECK_HIP(hipMemcpy(to.data(), from.data(), from.bytes().size(), hipMemcpyDefault));
784 }
785};
786
787/*---------------------------------------------------------------------------*/
788/*---------------------------------------------------------------------------*/
789
790} // End namespace Arcane::Accelerator::Hip
791
792using namespace Arcane;
793
794namespace
795{
797Arcane::Accelerator::Hip::HipMemoryCopier global_hip_memory_copier;
798
799void _setAllocator(Accelerator::AcceleratorMemoryAllocatorBase* allocator)
800{
802 eMemoryResource mem = allocator->memoryResource();
803 mrm->setAllocator(mem, allocator);
804 mrm->setMemoryPool(mem, allocator->memoryPool());
805}
806} // namespace
807
808/*---------------------------------------------------------------------------*/
809/*---------------------------------------------------------------------------*/
810
811// Cette fonction est le point d'entrée utilisé lors du chargement
812// dynamique de cette bibliothèque
813extern "C" ARCCORE_EXPORT void
814arcaneRegisterAcceleratorRuntimehip(Arcane::Accelerator::RegisterRuntimeInfo& init_info)
815{
816 using namespace Arcane::Accelerator::Hip;
817 global_hip_runtime.build();
818 Arcane::Accelerator::Impl::setUsingHIPRuntime(true);
819 Arcane::Accelerator::Impl::setHIPRunQueueRuntime(&global_hip_runtime);
820 initializeHipMemoryAllocators();
822 MemoryUtils::setAcceleratorHostMemoryAllocator(&unified_memory_hip_memory_allocator);
823 IMemoryResourceMngInternal* mrm = MemoryUtils::getDataMemoryResourceMng()->_internal();
824 mrm->setIsAccelerator(true);
825 _setAllocator(&unified_memory_hip_memory_allocator);
826 _setAllocator(&host_pinned_hip_memory_allocator);
827 _setAllocator(&device_hip_memory_allocator);
828 mrm->setCopier(&global_hip_memory_copier);
829 global_hip_runtime.fillDevices(init_info.isVerbose());
830}
831
832/*---------------------------------------------------------------------------*/
833/*---------------------------------------------------------------------------*/
#define ARCCORE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCCORE_FATAL_IF(cond,...)
Macro envoyant une exception FatalErrorException si cond est vrai.
Classe de base d'un allocateur spécifique pour accélérateur.
eMemoryResource memoryResource() const final
Ressource mémoire fournie par l'allocateur.
void _doInitializeDevice(bool default_use_memory_pool=false)
Initialisation pour la mémoire Device.
void _doInitializeHostPinned(bool default_use_memory_pool=false)
Initialisation pour la mémoire HostPinned.
void _doInitializeUVM(bool default_use_memory_pool=false)
Initialisation pour la mémoire UVM.
bool isHost() const
Indique si l'instance est associée à l'hôte.
bool isAccelerator() const
Indique si l'instance est associée à un accélérateur.
void copy(ConstMemoryView from, eMemoryResource from_mem, MutableMemoryView to, eMemoryResource to_mem, const RunQueue *queue) override
Copie les données de from vers to avec la queue queue.
void notifyBeginLaunchKernel(Impl::RunCommandImpl &c) override
Notification avant le lancement de la commande.
void notifyEndLaunchKernel(Impl::RunCommandImpl &) override
Notification de fin de lancement de la commande.
bool _barrierNoException() override
Barrière sans exception. Retourne true en cas d'erreur.
void barrier() override
Bloque jusqu'à ce que toutes les actions associées à cette file soient terminées.
void prefetchMemory(const MemoryPrefetchArgs &args) override
Effectue un pré-chargement d'une zone mémoire.
void copyMemory(const MemoryCopyArgs &args) override
Effectue une copie entre deux zones mémoire.
Impl::NativeStream nativeStream() override
Pointeur sur la structure interne dépendante de l'implémentation.
void freeMemory(void *ptr, Int64 size) final
Libère le bloc situé à l'adresse address contenant size octets.
void * allocateMemory(Int64 size) final
Alloue un bloc pour size octets.
Interface de l'implémentation d'un évènement.
Interface d'un flux d'exécution pour une RunQueue.
Interface du runtime associé à un accélérateur.
bool isCooperative() const
Indique si on lance en mode coopératif (i.e. cudaLaunchCooperativeKernel).
bool isDefault() const
Indique si l'instance a uniquement les valeurs par défaut.
bool isAsync() const
Indique si la file d'exécution est asynchrone.
Definition RunQueue.cc:320
void copyMemory(const MemoryCopyArgs &args) const
Copie des informations entre deux zones mémoires.
Definition RunQueue.cc:237
Vue constante sur une zone mémoire contigue contenant des éléments de taille fixe.
constexpr SpanType bytes() const
Vue sous forme d'octets.
constexpr const std::byte * data() const
Pointeur sur la zone mémoire.
Classe template pour convertir un type.
Interface pour les copies mémoire avec support des accélérateurs.
Partie interne à Arcane de 'IMemoryRessourceMng'.
virtual void setAllocator(eMemoryResource r, IMemoryAllocator *allocator)=0
Positionne l'allocateur pour la ressource r.
virtual void setMemoryPool(eMemoryResource r, IMemoryPool *pool)=0
Positionne le pool mémoire pour la ressource r.
virtual void setIsAccelerator(bool v)=0
Indique si un accélérateur est disponible.
virtual void setCopier(IMemoryCopier *copier)=0
Positionne l'instance gérant les copies.
virtual IMemoryResourceMngInternal * _internal()=0
Interface interne.
Interface du gestionnaire de traces.
Vue modifiable sur une zone mémoire contigue contenant des éléments de taille fixe.
constexpr std::byte * data() const
Pointeur sur la zone mémoire.
constexpr SpanType bytes() const
Vue sous forme d'octets.
constexpr __host__ __device__ pointer data() const noexcept
Pointeur sur le début de la vue.
Definition Span.h:537
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:325
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
@ AccessedByHost
Indique que la zone mémoire est accédée par l'hôte.
@ PreferredLocationDevice
Privilégié le positionnement de la mémoire sur l'accélérateur.
@ MostlyRead
Indique que la zone mémoire est principalement en lecture seule.
@ PreferredLocationHost
Privilégié le positionnement de la mémoire sur l'hôte.
@ AccessedByDevice
Indique que la zone mémoire est accédée par l'accélérateur.
eExecutionPolicy
Politique d'exécution pour un Runner.
@ HIP
Politique d'exécution utilisant l'environnement HIP.
IMemoryRessourceMng * getDataMemoryResourceMng()
Gestionnaire de ressource mémoire pour les données.
IMemoryAllocator * setAcceleratorHostMemoryAllocator(IMemoryAllocator *a)
Positionne l'allocateur spécifique pour les accélérateurs.
void setDefaultDataMemoryResource(eMemoryResource mem_resource)
Positionne la ressource mémoire utilisée pour l'allocateur mémoire des données.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Type entier signé sur 64 bits.
double Real
Type représentant un réel.
eMemoryResource
Liste des ressources mémoire disponibles.
@ HostPinned
Alloue sur l'hôte.
@ UnifiedMemory
Alloue en utilisant la mémoire unifiée.
@ Device
Alloue sur le device.
std::int32_t Int32
Type entier signé sur 32 bits.
Espace de nom de Arccore.