14#include "arccore/accelerator_native/SyclAccelerator.h"
16#include "arccore/base/FatalErrorException.h"
17#include "arccore/base/NotImplementedException.h"
18#include "arccore/base/NotSupportedException.h"
20#include "arccore/common/AlignedMemoryAllocator.h"
21#include "arccore/common/AllocatedMemoryInfo.h"
22#include "arccore/common/internal/MemoryUtilsInternal.h"
23#include "arccore/common/internal/IMemoryResourceMngInternal.h"
25#include "arccore/common/accelerator/RunQueueBuildInfo.h"
26#include "arccore/common/accelerator/Memory.h"
27#include "arccore/common/accelerator/DeviceInfoList.h"
28#include "arccore/common/accelerator/KernelLaunchArgs.h"
29#include "arccore/common/accelerator/RunQueue.h"
30#include "arccore/common/accelerator/DeviceMemoryInfo.h"
31#include "arccore/common/accelerator/NativeStream.h"
32#include "arccore/common/accelerator/internal/IRunnerRuntime.h"
33#include "arccore/common/accelerator/internal/RegisterRuntimeInfo.h"
34#include "arccore/common/accelerator/internal/RunCommandImpl.h"
35#include "arccore/common/accelerator/internal/IRunQueueStream.h"
36#include "arccore/common/accelerator/internal/IRunQueueEventImpl.h"
38namespace Arcane::Accelerator::Sycl
40using Arcane::Accelerator::Impl::KernelLaunchArgs;
42#define ARCCORE_SYCL_FUNC_NOT_HANDLED \
43 std::cout << "WARNING: SYCL: function not handled " << A_FUNCINFO << "\n"
53sycl::queue global_default_queue;
56 sycl::queue& _defaultQueue()
58 return global_default_queue;
67class SyclMemoryAllocatorBase
68:
public AlignedMemoryAllocator
72 SyclMemoryAllocatorBase()
73 : AlignedMemoryAllocator(128)
79 sycl::queue& q = _defaultQueue();
81 _allocate(&out, new_size, args, q);
86 ARCCORE_FATAL(
"Bad alignment for SYCL allocator: offset={0}", (a % 128));
87 return { out, new_size };
91 sycl::queue& q = _defaultQueue();
93 q.submit([&](sycl::handler& cgh) {
94 cgh.memcpy(a.baseAddress(), current_ptr.
baseAddress(), current_ptr.
size());
103 sycl::queue& q = _defaultQueue();
117:
public SyclMemoryAllocatorBase
123 *ptr = sycl::malloc_shared(new_size, q);
136:
public SyclMemoryAllocatorBase
143 *ptr = sycl::malloc_host(new_size, q);
156:
public SyclMemoryAllocatorBase
162 *ptr = sycl::malloc_device(new_size, q);
176 UnifiedMemorySyclMemoryAllocator unified_memory_sycl_memory_allocator;
177 HostPinnedSyclMemoryAllocator host_pinned_sycl_memory_allocator;
178 DeviceSyclMemoryAllocator device_sycl_memory_allocator;
184class SyclRunQueueStream
190 ~SyclRunQueueStream()
override
198 return m_runtime->notifyBeginLaunchKernel();
202 return m_runtime->notifyEndLaunchKernel();
206 m_sycl_stream->wait_and_throw();
210 m_sycl_stream->wait();
215 auto source_bytes = args.source().
bytes();
216 m_sycl_stream->memcpy(args.destination().
data(), source_bytes.data(),
217 source_bytes.size());
223 auto source_bytes = args.source().bytes();
224 Int64 nb_byte = source_bytes.size();
227 m_sycl_stream->prefetch(source_bytes.data(), nb_byte);
238 sycl::event last_event;
240 last_event = *(
reinterpret_cast<sycl::event*
>(sycl_event_ptr));
241 m_last_command_event = last_event;
246 static sycl::async_handler _getAsyncHandler()
248 auto err_handler = [](
const sycl::exception_list& exceptions) {
249 std::ostringstream ostr;
250 ostr <<
"Error in SYCL runtime\n";
251 for (
const std::exception_ptr& e : exceptions) {
253 std::rethrow_exception(e);
255 catch (
const sycl::exception& e) {
256 ostr <<
"SYCL exception: " << e.what() <<
"\n";
269 sycl::queue& trueStream()
const
271 return *m_sycl_stream;
277 std::unique_ptr<sycl::queue> m_sycl_stream;
278 sycl::event m_last_command_event;
284class SyclRunQueueEvent
289 explicit SyclRunQueueEvent([[maybe_unused]]
bool has_timer)
292 ~SyclRunQueueEvent()
override
304#if defined(__ADAPTIVECPP__)
305 m_recorded_stream = stream;
307#elif defined(__INTEL_LLVM_COMPILER)
323#if defined(__ADAPTIVECPP__)
325 m_sycl_event.wait(rq->trueStream().get_wait_list());
326#elif defined(__INTEL_LLVM_COMPILER)
327 std::vector<sycl::event> events;
328 events.push_back(m_sycl_event);
330 rq->trueStream().ext_oneapi_submit_barrier(events);
336 Int64 elapsedTime([[maybe_unused]] IRunQueueEventImpl* start_event)
final
341 sycl::event
event = (
static_cast<SyclRunQueueEvent*
>(start_event))->m_sycl_event;
343 if (event == sycl::event())
346 bool is_submitted =
event.get_info<sycl::info::event::command_execution_status>() == sycl::info::event_command_status::complete;
349 Int64 start =
event.get_profiling_info<sycl::info::event_profiling::command_start>();
350 Int64 end =
event.get_profiling_info<sycl::info::event_profiling::command_end>();
351 return (end - start);
354 bool hasPendingWork()
final
361 sycl::event m_sycl_event;
371 friend class SyclRunQueueStream;
375 void notifyBeginLaunchKernel()
override
378 void notifyEndLaunchKernel()
override
381 void barrier()
override
385 m_default_queue->wait();
393 return new SyclRunQueueStream(
this, bi);
404 [[maybe_unused]]
DeviceId device_id)
override
412 void setCurrentDevice([[maybe_unused]]
DeviceId device_id)
final
414 ARCCORE_SYCL_FUNC_NOT_HANDLED;
416 const IDeviceInfoList* deviceInfoList()
override {
return &m_device_info_list; }
418 void getPointerAttribute(
PointerAttribute& attribute,
const void* ptr)
override
420 sycl::usm::alloc sycl_mem_type = sycl::get_pointer_type(ptr, *m_default_context);
422 const void* host_ptr =
nullptr;
423 const void* device_ptr =
nullptr;
424 if (sycl_mem_type == sycl::usm::alloc::host) {
427 mem_type = ePointerMemoryType::Host;
432 else if (sycl_mem_type == sycl::usm::alloc::device) {
433 mem_type = ePointerMemoryType::Device;
436 else if (sycl_mem_type == sycl::usm::alloc::shared) {
437 mem_type = ePointerMemoryType::Managed;
445 _fillPointerAttribute(attribute, mem_type, device_id, ptr, device_ptr, host_ptr);
454 const void* kernel_ptr,
455 Int64 total_loop_size)
override
466 int nb_block_per_sm = 4;
467 int max_block = nb_block_per_sm * m_multi_processor_count;
468 if (nb_block > max_block) {
471 return modified_args;
477 void fillDevicesAndSetDefaultQueue(
bool is_verbose);
478 sycl::queue& defaultQueue()
const {
return *m_default_queue; }
479 sycl::device& defaultDevice()
const {
return *m_default_device; }
484 global_default_queue = sycl::queue{};
490 std::unique_ptr<sycl::device> m_default_device;
491 std::unique_ptr<sycl::context> m_default_context;
492 std::unique_ptr<sycl::queue> m_default_queue;
493 int m_multi_processor_count = 0;
497 void _init(sycl::device& device)
499 m_default_device = std::make_unique<sycl::device>(device);
500 m_default_queue = std::make_unique<sycl::queue>(device);
501 m_default_context = std::make_unique<sycl::context>(device);
512 sycl::device& d = runtime->defaultDevice();
515 auto queue_property = sycl::property::queue::in_order();
517 auto profiling_property = sycl::property::queue::enable_profiling();
518 sycl::property_list queue_properties(queue_property, profiling_property);
521 sycl::async_handler err_handler;
522 err_handler = _getAsyncHandler();
524 m_sycl_stream = std::make_unique<sycl::queue>(d, err_handler, queue_properties);
526 ARCCORE_SYCL_FUNC_NOT_HANDLED;
527 m_sycl_stream = std::make_unique<sycl::queue>(d, err_handler, queue_properties);
534void SyclRunnerRuntime::
535fillDevicesAndSetDefaultQueue(
bool is_verbose)
538 for (
auto platform : sycl::platform::get_platforms()) {
539 std::cout <<
"Platform: "
540 <<
platform.get_info<sycl::info::platform::name>()
545 sycl::device device{ sycl::gpu_selector_v };
547 std::cout <<
"\nDevice: " << device.get_info<sycl::info::device::name>()
548 <<
"\nVersion=" << device.get_info<sycl::info::device::version>()
549 <<
"\nDriverVersion=" << device.get_info<sycl::info::device::driver_version>()
550 <<
"\nMaxComputeUnits=" << device.get_info<sycl::info::device::max_compute_units>()
551 <<
"\nMaxWorkGroupSize=" << device.get_info<sycl::info::device::max_work_group_size>()
552 <<
"\nLocalMemSize=" << device.get_info<sycl::info::device::local_mem_size>()
553 <<
"\nGlobalMemSize=" << device.get_info<sycl::info::device::global_mem_size>()
554 <<
"\nMaxMemAllocSize=" << device.get_info<sycl::info::device::max_mem_alloc_size>()
556 m_multi_processor_count = device.get_info<sycl::info::device::max_compute_units>();
561 DeviceInfo device_info;
562 device_info.setDescription(
"No description info");
563 device_info.setDeviceId(DeviceId(0));
564 device_info.setName(device.get_info<sycl::info::device::name>());
565 m_device_info_list.addDevice(device_info);
593namespace Arcane::Accelerator::Sycl
599void SyclMemoryCopier::
608 sycl::queue& q = global_sycl_runtime.defaultQueue();
619extern "C" ARCCORE_EXPORT
void
623 using namespace Arcane::Accelerator::Sycl;
624 Arcane::Accelerator::Impl::setUsingSYCLRuntime(
true);
625 Arcane::Accelerator::Impl::setSYCLRunQueueRuntime(&global_sycl_runtime);
633 mrm->
setCopier(&global_sycl_memory_copier);
634 global_sycl_runtime.fillDevicesAndSetDefaultQueue(init_info.isVerbose());
635 global_default_queue = global_sycl_runtime.defaultQueue();
#define ARCCORE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCCORE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCCORE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
Identifiant d'un composant du système.
Information mémoire d'un accélérateur.
Interface d'une liste de devices.
Interface d'une liste de devices.
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.
Arguments pour lancer un kernel.
bool isCooperative() const
Indique si on lance en mode coopératif (i.e. cudaLaunchCooperativeKernel)
Int32 nbBlockPerGrid() const
Nombre de blocs de la grille.
void setNbBlockPerGrid(Int32 v)
Nombre de blocs de la grille.
Int32 sharedMemorySize() const
Mémoire partagée à allouer pour le noyau.
Type opaque pour encapsuler une 'stream' native.
Implémentation d'une commande pour accélérateur.
Arguments pour la copie mémoire.
Arguments pour le préfetching mémoire.
Informations sur une adresse mémoire.
Informations pour initialiser le runtime accélérateur.
Informations pour créer une RunQueue.
bool isDefault() const
Indique si l'instance a uniquement les valeurs par défaut.
File d'exécution pour un accélérateur.
bool isAsync() const
Indique si la file d'exécution est asynchrone.
void copyMemory(const MemoryCopyArgs &args) const
Copie des informations entre deux zones mémoires.
eMemoryResource memoryResource() const override
Ressource mémoire fournie par l'allocateur.
eMemoryResource memoryResource() const override
Ressource mémoire fournie par l'allocateur.
bool hasRealloc(MemoryAllocationArgs) const override
Indique si l'allocateur supporte la sémantique de realloc.
AllocatedMemoryInfo reallocate(MemoryAllocationArgs args, AllocatedMemoryInfo current_ptr, Int64 new_size) override
Réalloue de la mémoire pour new_size octets et retourne le pointeur.
AllocatedMemoryInfo allocate(MemoryAllocationArgs args, Int64 new_size) override
void deallocate(MemoryAllocationArgs args, AllocatedMemoryInfo ptr) override
Libère la mémoire dont l'adresse de base est ptr.
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 barrier() override
Bloque jusqu'à ce que toutes les actions associées à cette file soient terminées.
sycl::event lastCommandEvent()
Évènement correspondant à la dernière commande.
void prefetchMemory(const MemoryPrefetchArgs &args) override
Effectue un pré-chargement d'une zone mémoire.
Impl::NativeStream nativeStream() override
Pointeur sur la structure interne dépendante de l'implémentation.
void copyMemory(const MemoryCopyArgs &args) override
Effectue une copie entre deux zones mémoire.
bool _barrierNoException() override
Barrière sans exception. Retourne true en cas d'erreur.
void _setSyclLastCommandEvent(void *sycl_event_ptr) override
Pour SYCL, positionne l'évènement associé à la dernière commande exécutée.
void notifyEndLaunchKernel(Impl::RunCommandImpl &) override
Notification de fin de lancement de la commande.
eMemoryResource memoryResource() const override
Ressource mémoire fournie par l'allocateur.
Informations sur une zone mémoire allouée.
void * baseAddress() const
Adresse du début de la zone allouée.
Int64 size() const
Taille en octets de la zone mémoire utilisée. (-1) si inconnue.
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.
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 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.
Classe contenant des informations pour spécialiser les allocations.
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.
Exception lorsqu'une fonction n'est pas implémentée.
Exception lorsqu'une opération n'est pas supportée.
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
eMemoryAdvice
Conseils pour la gestion mémoire.
ePointerMemoryType
Type de mémoire pour un pointeur.
eExecutionPolicy
Politique d'exécution pour un Runner.
@ SYCL
Politique d'exécution utilisant l'environnement SYCL.
ARCCORE_COMMON_EXPORT IMemoryRessourceMng * getDataMemoryResourceMng()
Gestionnaire de ressource mémoire pour les données.
ARCCORE_COMMON_EXPORT IMemoryAllocator * setAcceleratorHostMemoryAllocator(IMemoryAllocator *a)
Positionne l'allocateur spécifique pour les accélérateurs.
ARCCORE_COMMON_EXPORT 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.
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.