14#include "arccore/accelerator_native/HipAccelerator.h"
16#include "arccore/base/CheckedConvert.h"
17#include "arccore/base/FatalErrorException.h"
19#include "arccore/common/internal/MemoryUtilsInternal.h"
20#include "arccore/common/internal/IMemoryResourceMngInternal.h"
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"
40#ifdef ARCCORE_HAS_ROCTX
46namespace Arcane::Accelerator::Hip
48using Impl::KernelLaunchArgs;
61 virtual hipError_t _allocate(
void** ptr,
size_t new_size) = 0;
62 virtual hipError_t _deallocate(
void* ptr) = 0;
68template <
typename ConcreteAllocatorType>
69class UnderlyingAllocator
74 UnderlyingAllocator() =
default;
81 ARCCORE_CHECK_HIP(m_concrete_allocator._allocate(&out, size));
86 ARCCORE_CHECK_HIP_NOTHROW(m_concrete_allocator._deallocate(ptr));
89 void doMemoryCopy(
void* destination,
const void* source,
Int64 size)
final
91 ARCCORE_CHECK_HIP(hipMemcpy(destination, source, size, hipMemcpyDefault));
96 return m_concrete_allocator.memoryResource();
101 ConcreteAllocatorType m_concrete_allocator;
112 hipError_t _deallocate(
void* ptr)
final
114 return ::hipFree(ptr);
117 hipError_t _allocate(
void** ptr,
size_t new_size)
final
119 auto r = ::hipMallocManaged(ptr, new_size, hipMemAttachGlobal);
129class UnifiedMemoryHipMemoryAllocator
130:
public AcceleratorMemoryAllocatorBase
134 UnifiedMemoryHipMemoryAllocator()
155 hipError_t _allocate(
void** ptr,
size_t new_size)
final
157 return ::hipHostMalloc(ptr, new_size);
159 hipError_t _deallocate(
void* ptr)
final
161 return ::hipHostFree(ptr);
169class HostPinnedHipMemoryAllocator
170:
public AcceleratorMemoryAllocatorBase
175 HostPinnedHipMemoryAllocator()
191class DeviceConcreteAllocator
196 DeviceConcreteAllocator()
200 hipError_t _allocate(
void** ptr,
size_t new_size)
final
202 hipError_t r = ::hipMalloc(ptr, new_size);
205 hipError_t _deallocate(
void* ptr)
final
207 return ::hipFree(ptr);
216class DeviceHipMemoryAllocator
217:
public AcceleratorMemoryAllocatorBase
222 DeviceHipMemoryAllocator()
248void initializeHipMemoryAllocators()
250 unified_memory_hip_memory_allocator.initialize();
251 device_hip_memory_allocator.initialize();
252 host_pinned_hip_memory_allocator.initialize();
255void finalizeHipMemoryAllocators(
ITraceMng* tm)
257 unified_memory_hip_memory_allocator.finalize(tm);
258 device_hip_memory_allocator.finalize(tm);
259 host_pinned_hip_memory_allocator.finalize(tm);
265class HipRunQueueStream
274 ARCCORE_CHECK_HIP(hipStreamCreate(&m_hip_stream));
276 int priority = bi.priority();
277 ARCCORE_CHECK_HIP(hipStreamCreateWithPriority(&m_hip_stream, hipStreamDefault, priority));
280 ~HipRunQueueStream()
override
282 ARCCORE_CHECK_HIP_NOTHROW(hipStreamDestroy(m_hip_stream));
289#ifdef ARCCORE_HAS_ROCTX
290 auto kname = c.kernelName();
292 roctxRangePush(c.traceInfo().name());
294 roctxRangePush(kname.localstr());
296 return m_runtime->notifyBeginLaunchKernel();
300#ifdef ARCCORE_HAS_ROCTX
303 return m_runtime->notifyEndLaunchKernel();
307 ARCCORE_CHECK_HIP(hipStreamSynchronize(m_hip_stream));
311 return hipStreamSynchronize(m_hip_stream) != hipSuccess;
315 auto r = hipMemcpyAsync(args.destination().
data(), args.source().
data(),
316 args.source().
bytes().
size(), hipMemcpyDefault, m_hip_stream);
317 ARCCORE_CHECK_HIP(r);
323 auto src = args.source().
bytes();
327 int device = hipCpuDeviceId;
330 auto r = hipMemPrefetchAsync(src.data(), src.size(), device, m_hip_stream);
331 ARCCORE_CHECK_HIP(r);
342 hipStream_t trueStream()
const
350 hipStream_t m_hip_stream;
356class HipRunQueueEvent
361 explicit HipRunQueueEvent(
bool has_timer)
364 ARCCORE_CHECK_HIP(hipEventCreate(&m_hip_event));
366 ARCCORE_CHECK_HIP(hipEventCreateWithFlags(&m_hip_event, hipEventDisableTiming));
368 ~HipRunQueueEvent()
override
370 ARCCORE_CHECK_HIP_NOTHROW(hipEventDestroy(m_hip_event));
379 ARCCORE_CHECK_HIP(hipEventRecord(m_hip_event, rq->trueStream()));
384 ARCCORE_CHECK_HIP(hipEventSynchronize(m_hip_event));
390 ARCCORE_CHECK_HIP(hipStreamWaitEvent(rq->trueStream(), m_hip_event, 0));
393 Int64 elapsedTime(IRunQueueEventImpl* from_event)
final
395 auto* true_from_event =
static_cast<HipRunQueueEvent*
>(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;
404 bool hasPendingWork()
final
406 hipError_t v = hipEventQuery(m_hip_event);
407 if (v == hipErrorNotReady)
409 ARCCORE_CHECK_HIP(v);
415 hipEvent_t m_hip_event;
430 void notifyBeginLaunchKernel()
override
432 ++m_nb_kernel_launched;
434 std::cout <<
"BEGIN HIP KERNEL!\n";
436 void notifyEndLaunchKernel()
override
438 ARCCORE_CHECK_HIP(hipGetLastError());
440 std::cout <<
"END HIP KERNEL!\n";
442 void barrier()
override
444 ARCCORE_CHECK_HIP(hipDeviceSynchronize());
464 auto v = buffer.
bytes();
465 const void* ptr = v.
data();
466 size_t count = v.size();
467 int device = device_id.
asInt32();
468 hipMemoryAdvise hip_advise;
471 hip_advise = hipMemAdviseSetReadMostly;
473 hip_advise = hipMemAdviseSetPreferredLocation;
475 hip_advise = hipMemAdviseSetAccessedBy;
477 hip_advise = hipMemAdviseSetPreferredLocation;
478 device = hipCpuDeviceId;
481 hip_advise = hipMemAdviseSetAccessedBy;
482 device = hipCpuDeviceId;
487 ARCCORE_CHECK_HIP(hipMemAdvise(ptr, count, hip_advise, device));
491 auto v = buffer.
bytes();
492 const void* ptr = v.
data();
493 size_t count = v.size();
494 int device = device_id.
asInt32();
495 hipMemoryAdvise hip_advise;
498 hip_advise = hipMemAdviseUnsetReadMostly;
500 hip_advise = hipMemAdviseUnsetPreferredLocation;
502 hip_advise = hipMemAdviseUnsetAccessedBy;
504 hip_advise = hipMemAdviseUnsetPreferredLocation;
505 device = hipCpuDeviceId;
508 hip_advise = hipMemAdviseUnsetAccessedBy;
509 device = hipCpuDeviceId;
513 ARCCORE_CHECK_HIP(hipMemAdvise(ptr, count, hip_advise, device));
516 void setCurrentDevice(
DeviceId device_id)
final
520 ARCCORE_CHECK_HIP(hipSetDevice(
id));
522 const IDeviceInfoList* deviceInfoList()
override {
return &m_device_info_list; }
524 void getPointerAttribute(
PointerAttribute& attribute,
const void* ptr)
override
526 hipPointerAttribute_t pa;
527 hipError_t ret_value = hipPointerGetAttributes(&pa, ptr);
528 auto mem_type = ePointerMemoryType::Unregistered;
532 if (ret_value == hipSuccess) {
533#if HIP_VERSION_MAJOR >= 6
534 auto rocm_memory_type = pa.type;
536 auto rocm_memory_type = pa.memoryType;
539 mem_type = ePointerMemoryType::Managed;
540 else if (rocm_memory_type == hipMemoryTypeHost)
541 mem_type = ePointerMemoryType::Host;
542 else if (rocm_memory_type == hipMemoryTypeDevice)
543 mem_type = ePointerMemoryType::Device;
550 _fillPointerAttribute(attribute, mem_type, pa.device,
551 ptr, pa.devicePointer, pa.hostPointer);
557 int wanted_d = device_id.
asInt32();
558 ARCCORE_CHECK_HIP(hipGetDevice(&d));
560 ARCCORE_CHECK_HIP(hipSetDevice(wanted_d));
562 size_t total_mem = 0;
563 ARCCORE_CHECK_HIP(hipMemGetInfo(&free_mem, &total_mem));
565 ARCCORE_CHECK_HIP(hipSetDevice(d));
567 dmi.setFreeMemory(free_mem);
568 dmi.setTotalMemory(total_mem);
572 void pushProfilerRange(
const String& name, [[maybe_unused]]
Int32 color)
override
574#ifdef ARCCORE_HAS_ROCTX
578 void popProfilerRange()
override
580#ifdef ARCCORE_HAS_ROCTX
587 finalizeHipMemoryAllocators(tm);
591 const void* kernel_ptr,
592 Int64 total_loop_size)
override
600 int nb_block_per_sm = 0;
601 ARCCORE_CHECK_HIP(hipOccupancyMaxActiveBlocksPerMultiprocessor(&nb_block_per_sm, kernel_ptr, nb_thread, shared_memory));
603 int max_block =
static_cast<int>((nb_block_per_sm * m_multi_processor_count) * m_cooperative_ratio);
604 max_block = std::max(max_block, 1);
605 if (nb_block > max_block) {
608 return modified_args;
616 void fillDevices(
bool is_verbose);
622 x = std::clamp(x, 10, 100);
623 m_cooperative_ratio = x / 100.0;
629 Int64 m_nb_kernel_launched = 0;
630 bool m_is_verbose =
false;
631 Int32 m_multi_processor_count = 0;
632 double m_cooperative_ratio = 1.0;
639void HipRunnerRuntime::
640fillDevices(
bool is_verbose)
643 ARCCORE_CHECK_HIP(hipGetDeviceCount(&nb_device));
644 std::ostream& omain = std::cout;
646 omain <<
"ArcaneHIP: Initialize Arcane HIP runtime nb_available_device=" << nb_device <<
"\n";
647 for (
int i = 0; i < nb_device; ++i) {
648 std::ostringstream ostr;
649 std::ostream& o = ostr;
652 ARCCORE_CHECK_HIP(hipGetDeviceProperties(&dp, i));
654 int has_managed_memory = 0;
655 ARCCORE_CHECK_HIP(hipDeviceGetAttribute(&has_managed_memory, hipDeviceAttributeManagedMemory, i));
660 int runtime_version = 0;
661 ARCCORE_CHECK_HIP(hipRuntimeGetVersion(&runtime_version));
663 int runtime_major = runtime_version / 10000000;
664 int runtime_minor = (runtime_version / 100000) % 100;
666 int driver_version = 0;
667 ARCCORE_CHECK_HIP(hipDriverGetVersion(&driver_version));
669 int driver_major = driver_version / 10000000;
670 int driver_minor = (driver_version / 100000) % 100;
672 o <<
"\nDevice " << i <<
" name=" << dp.name <<
"\n";
673 o <<
" Driver version = " << driver_major <<
"." << (driver_minor) <<
"." << (driver_version % 100000) <<
"\n";
674 o <<
" Runtime version = " << runtime_major <<
"." << (runtime_minor) <<
"." << (runtime_version % 100000) <<
"\n";
675 o <<
" computeCapability = " << dp.major <<
"." << dp.minor <<
"\n";
676 o <<
" totalGlobalMem = " << dp.totalGlobalMem <<
"\n";
677 o <<
" regsPerBlock = " << dp.regsPerBlock <<
"\n";
678 o <<
" warpSize = " << dp.warpSize <<
"\n";
679 o <<
" memPitch = " << dp.memPitch <<
"\n";
680 o <<
" maxThreadsPerBlock = " << dp.maxThreadsPerBlock <<
"\n";
681 o <<
" maxBlocksPerMultiProcessor = " << dp.maxBlocksPerMultiProcessor <<
"\n";
682 o <<
" maxThreadsPerMultiProcessor = " << dp.maxThreadsPerMultiProcessor <<
"\n";
683 o <<
" totalConstMem = " << dp.totalConstMem <<
"\n";
684 o <<
" clockRate = " << dp.clockRate <<
"\n";
686 o <<
" multiProcessorCount = " << dp.multiProcessorCount <<
"\n";
687 o <<
" kernelExecTimeoutEnabled = " << dp.kernelExecTimeoutEnabled <<
"\n";
688 o <<
" integrated = " << dp.integrated <<
"\n";
689 o <<
" canMapHostMemory = " << dp.canMapHostMemory <<
"\n";
690 o <<
" computeMode = " << dp.computeMode <<
"\n";
691 o <<
" maxThreadsDim = " << dp.maxThreadsDim[0] <<
" " << dp.maxThreadsDim[1]
692 <<
" " << dp.maxThreadsDim[2] <<
"\n";
693 o <<
" maxGridSize = " << dp.maxGridSize[0] <<
" " << dp.maxGridSize[1]
694 <<
" " << dp.maxGridSize[2] <<
"\n";
695 o <<
" concurrentManagedAccess = " << dp.concurrentManagedAccess <<
"\n";
696 o <<
" directManagedMemAccessFromHost = " << dp.directManagedMemAccessFromHost <<
"\n";
697 o <<
" gcnArchName = " << dp.gcnArchName <<
"\n";
698 o <<
" pageableMemoryAccess = " << dp.pageableMemoryAccess <<
"\n";
699 o <<
" pageableMemoryAccessUsesHostPageTables = " << dp.pageableMemoryAccessUsesHostPageTables <<
"\n";
700 o <<
" hasManagedMemory = " << has_managed_memory <<
"\n";
701 o <<
" pciInfo = " << dp.pciDomainID <<
" " << dp.pciBusID <<
" " << dp.pciDeviceID <<
"\n";
702 o <<
" memoryBusWitdh = " << dp.memoryBusWidth <<
" bits\n";
705 ARCCORE_CHECK_HIP(hipDeviceGetAttribute(&clock_rate, hipDeviceAttributeClockRate, i));
706 o <<
" clockRate = " << (clock_rate / 1000) <<
" MHz\n";
708 int memory_clock_rate = 0;
709 ARCCORE_CHECK_HIP(hipDeviceGetAttribute(&memory_clock_rate, hipDeviceAttributeMemoryClockRate, i));
710 o <<
" memoryClockRate = " << (memory_clock_rate / 1000) <<
" MHz\n";
715 Real memory_bandwith = (dp.memoryBusWidth * memory_clock_rate * 2.0) / 1.0e6;
716 o <<
" MemoryBandwith = " << memory_bandwith <<
" GB/s\n";
718#if HIP_VERSION_MAJOR >= 6
719 o <<
" sharedMemPerMultiprocessor = " << dp.sharedMemPerMultiprocessor <<
"\n";
720 o <<
" sharedMemPerBlock = " << dp.sharedMemPerBlock <<
"\n";
721 o <<
" sharedMemPerBlockOptin = " << dp.sharedMemPerBlockOptin <<
"\n";
722 o <<
" gpuDirectRDMASupported = " << dp.gpuDirectRDMASupported <<
"\n";
723 o <<
" hostNativeAtomicSupported = " << dp.hostNativeAtomicSupported <<
"\n";
724 o <<
" unifiedFunctionPointers = " << dp.unifiedFunctionPointers <<
"\n";
730 m_multi_processor_count = dp.multiProcessorCount;
732 std::ostringstream device_uuid_ostr;
735 ARCCORE_CHECK_HIP(hipDeviceGet(&device, i));
737 ARCCORE_CHECK_HIP(hipDeviceGetUuid(&device_uuid, device));
739 Impl::printUUID(device_uuid_ostr, device_uuid.bytes);
740 o << device_uuid_ostr.str();
744 String description(ostr.str());
746 omain << description;
749 device_info.setDescription(description);
750 device_info.setDeviceId(
DeviceId(i));
751 device_info.setName(dp.name);
752 device_info.setWarpSize(dp.warpSize);
753 device_info.setUUIDAsString(device_uuid_ostr.str());
754 device_info.setSharedMemoryPerBlock(
static_cast<Int32>(dp.sharedMemPerBlock));
755#if HIP_VERSION_MAJOR >= 6
756 device_info.setSharedMemoryPerMultiprocessor(
static_cast<Int32>(dp.sharedMemPerMultiprocessor));
757 device_info.setSharedMemoryPerBlockOptin(
static_cast<Int32>(dp.sharedMemPerBlockOptin));
759 device_info.setTotalConstMemory(
static_cast<Int32>(dp.totalConstMem));
760 device_info.setPCIDomainID(dp.pciDomainID);
761 device_info.setPCIBusID(dp.pciBusID);
762 device_info.setPCIDeviceID(dp.pciDeviceID);
763 m_device_info_list.addDevice(device_info);
784 ARCCORE_CHECK_HIP(hipMemcpy(to.
data(), from.
data(), from.
bytes().
size(), hipMemcpyDefault));
814extern "C" ARCCORE_EXPORT
void
815arcaneRegisterAcceleratorRuntimehip(Arcane::Accelerator::RegisterRuntimeInfo& init_info)
817 using namespace Arcane::Accelerator::Hip;
818 global_hip_runtime.build();
819 Arcane::Accelerator::Impl::setUsingHIPRuntime(
true);
820 Arcane::Accelerator::Impl::setHIPRunQueueRuntime(&global_hip_runtime);
821 initializeHipMemoryAllocators();
826 _setAllocator(&unified_memory_hip_memory_allocator);
827 _setAllocator(&host_pinned_hip_memory_allocator);
828 _setAllocator(&device_hip_memory_allocator);
829 mrm->
setCopier(&global_hip_memory_copier);
830 global_hip_runtime.fillDevices(init_info.isVerbose());
#define ARCCORE_CHECK_POINTER(ptr)
Macro that returns the pointer ptr if it is not null or throws an exception if it is null.
#define ARCCORE_FATAL_IF(cond,...)
Macro throwing a FatalErrorException if cond is true.
Base class of a specific allocator for accelerator.
eMemoryResource memoryResource() const final
Memory resource provided by the allocator.
void _doInitializeDevice(bool default_use_memory_pool=false)
Initialization for Device memory.
void _doInitializeHostPinned(bool default_use_memory_pool=false)
Initialization for HostPinned memory.
void _doInitializeUVM(bool default_use_memory_pool=false)
Initialization for UVM memory.
Identifier of a system component.
bool isHost() const
Indicates if the instance is associated with the host.
Int32 asInt32() const
Numerical value of the device.
bool isAccelerator() const
Indicates if the instance is associated with an accelerator.
Information about an accelerator.
Accelerator memory information.
void copy(ConstMemoryView from, eMemoryResource from_mem, MutableMemoryView to, eMemoryResource to_mem, const RunQueue *queue) override
Copies the data from from to to with the queue queue.
void notifyBeginLaunchKernel(Impl::RunCommandImpl &c) override
Notification before command launch.
void notifyEndLaunchKernel(Impl::RunCommandImpl &) override
Notification of command launch completion.
bool _barrierNoException() override
Barrier without exception. Returns true in case of error.
void barrier() override
Blocks until all actions associated with this queue are finished.
void prefetchMemory(const MemoryPrefetchArgs &args) override
Performs a prefetch of a memory region.
void copyMemory(const MemoryCopyArgs &args) override
Performs a copy between two memory regions.
Impl::NativeStream nativeStream() override
Pointer to the internal structure dependent on the implementation.
void freeMemory(void *ptr, Int64 size) final
Frees the block located at address address containing size bytes.
void * allocateMemory(Int64 size) final
Allocates a block for size bytes.
Interface of a list of devices.
Interface for a list of devices.
Interface for event implementation.
Interface of an execution stream for a RunQueue.
Interface of the runtime associated with an accelerator.
Arguments for launching a kernel.
bool isCooperative() const
Indicates if running in cooperative mode (i.e. cudaLaunchCooperativeKernel).
Int32 nbBlockPerGrid() const
Number of grid blocks.
void setNbBlockPerGrid(Int32 v)
Number of grid blocks.
Int32 nbThreadPerBlock() const
Number of threads per block.
Int32 sharedMemorySize() const
Shared memory to allocate for the kernel.
Opaque type to encapsulate a native 'stream'.
Implementation of a command for accelerator.
Memory prefetching arguments.
Information about a memory address.
Information to create a RunQueue.
bool isDefault() const
Indicates if the instance only has default values.
Execution queue for an accelerator.
bool isAsync() const
Indicates if the execution queue is asynchronous.
void copyMemory(const MemoryCopyArgs &args) const
Copies information between two memory regions.
Constant view on a contiguous memory region containing fixed-size elements.
constexpr SpanType bytes() const
View in byte form.
constexpr const std::byte * data() const
Pointer to the memory region.
Template class for converting a type.
Interface for memory copies with accelerator support.
Internal part of Arcane's 'IMemoryResourceMng'.
virtual void setAllocator(eMemoryResource r, IMemoryAllocator *allocator)=0
Sets the allocator for resource r.
virtual void setMemoryPool(eMemoryResource r, IMemoryPool *pool)=0
Sets the memory pool for resource r.
virtual void setIsAccelerator(bool v)=0
Indicates if an accelerator is available.
virtual void setCopier(IMemoryCopier *copier)=0
Sets the copying instance.
virtual IMemoryResourceMngInternal * _internal()=0
Internal interface.
Mutable view on a contiguous memory region containing fixed-size elements.
constexpr std::byte * data() const
Pointer to the memory region.
constexpr SpanType bytes() const
View in byte form.
constexpr __host__ __device__ pointer data() const noexcept
Pointer to the start of the view.
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Unicode character string.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
eMemoryAdvice
Memory management advice.
@ AccessedByHost
Indicates that the memory region is accessed by the host.
@ PreferredLocationDevice
Prefers memory placement on the accelerator.
@ MostlyRead
Indicates that the memory region is primarily read-only.
@ PreferredLocationHost
Prefers memory placement on the host.
@ AccessedByDevice
Indicates that the memory region is accessed by the device.
eExecutionPolicy
Execution policy for a Runner.
@ HIP
Execution policy using the HIP environment.
IMemoryRessourceMng * getDataMemoryResourceMng()
Memory resource manager for data.
IMemoryAllocator * setAcceleratorHostMemoryAllocator(IMemoryAllocator *a)
Sets the specific allocator for accelerators.
void setDefaultDataMemoryResource(eMemoryResource mem_resource)
Sets the memory resource used for the data memory allocator.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
double Real
Type representing a real number.
eMemoryResource
List of available memory resources.
@ HostPinned
Allocates on the host.
@ UnifiedMemory
Allocates using unified memory.
@ Device
Allocates on the device.
std::int32_t Int32
Signed integer type of 32 bits.