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
41#define ARCANE_SYCL_FUNC_NOT_HANDLED \
42 std::cout << "WARNING: SYCL: function not handled " << A_FUNCINFO << "\n"
52sycl::queue global_default_queue;
55 sycl::queue& _defaultQueue()
57 return global_default_queue;
66class SyclMemoryAllocatorBase
67:
public AlignedMemoryAllocator
71 SyclMemoryAllocatorBase()
72 : AlignedMemoryAllocator(128)
78 sycl::queue& q = _defaultQueue();
80 _allocate(&out, new_size, args, q);
82 ARCCORE_FATAL(
"Can not allocate memory size={0}", new_size);
85 ARCCORE_FATAL(
"Bad alignment for SYCL allocator: offset={0}", (a % 128));
86 return { out, new_size };
90 sycl::queue& q = _defaultQueue();
92 q.submit([&](sycl::handler& cgh) {
93 cgh.memcpy(a.baseAddress(), current_ptr.
baseAddress(), current_ptr.
size());
102 sycl::queue& q = _defaultQueue();
116:
public SyclMemoryAllocatorBase
122 *ptr = sycl::malloc_shared(new_size, q);
135:
public SyclMemoryAllocatorBase
142 *ptr = sycl::malloc_host(new_size, q);
155:
public SyclMemoryAllocatorBase
161 *ptr = sycl::malloc_device(new_size, q);
175 UnifiedMemorySyclMemoryAllocator unified_memory_sycl_memory_allocator;
176 HostPinnedSyclMemoryAllocator host_pinned_sycl_memory_allocator;
177 DeviceSyclMemoryAllocator device_sycl_memory_allocator;
183class SyclRunQueueStream
189 ~SyclRunQueueStream()
override
197 return m_runtime->notifyBeginLaunchKernel();
201 return m_runtime->notifyEndLaunchKernel();
205 m_sycl_stream->wait_and_throw();
209 m_sycl_stream->wait();
214 auto source_bytes = args.source().
bytes();
215 m_sycl_stream->memcpy(args.destination().
data(), source_bytes.data(),
216 source_bytes.size());
222 auto source_bytes = args.source().bytes();
223 Int64 nb_byte = source_bytes.size();
226 m_sycl_stream->prefetch(source_bytes.data(), nb_byte);
237 sycl::event last_event;
239 last_event = *(
reinterpret_cast<sycl::event*
>(sycl_event_ptr));
240 m_last_command_event = last_event;
245 static sycl::async_handler _getAsyncHandler()
247 auto err_handler = [](
const sycl::exception_list& exceptions) {
248 std::ostringstream ostr;
249 ostr <<
"Error in SYCL runtime\n";
250 for (
const std::exception_ptr& e : exceptions) {
252 std::rethrow_exception(e);
254 catch (
const sycl::exception& e) {
255 ostr <<
"SYCL exception: " << e.what() <<
"\n";
258 ARCCORE_FATAL(ostr.str());
268 sycl::queue& trueStream()
const
270 return *m_sycl_stream;
276 std::unique_ptr<sycl::queue> m_sycl_stream;
277 sycl::event m_last_command_event;
283class SyclRunQueueEvent
288 explicit SyclRunQueueEvent([[maybe_unused]]
bool has_timer)
291 ~SyclRunQueueEvent()
override
300 ARCCORE_CHECK_POINTER(stream);
303#if defined(__ADAPTIVECPP__)
304 m_recorded_stream = stream;
306#elif defined(__INTEL_LLVM_COMPILER)
309 ARCCORE_THROW(
NotSupportedException,
"Only supported for AdaptiveCpp and Intel DPC++ implementation");
322#if defined(__ADAPTIVECPP__)
324 m_sycl_event.wait(rq->trueStream().get_wait_list());
325#elif defined(__INTEL_LLVM_COMPILER)
326 std::vector<sycl::event> events;
327 events.push_back(m_sycl_event);
329 rq->trueStream().ext_oneapi_submit_barrier(events);
335 Int64 elapsedTime([[maybe_unused]] IRunQueueEventImpl* start_event)
final
337 ARCCORE_CHECK_POINTER(start_event);
340 sycl::event
event = (
static_cast<SyclRunQueueEvent*
>(start_event))->m_sycl_event;
342 if (event==sycl::event())
345 bool is_submitted =
event.get_info<sycl::info::event::command_execution_status>() == sycl::info::event_command_status::complete;
348 Int64 start =
event.get_profiling_info<sycl::info::event_profiling::command_start>();
349 Int64 end =
event.get_profiling_info<sycl::info::event_profiling::command_end>();
350 return (end - start);
353 bool hasPendingWork()
final
360 sycl::event m_sycl_event;
370 friend class SyclRunQueueStream;
374 void notifyBeginLaunchKernel()
override
377 void notifyEndLaunchKernel()
override
380 void barrier()
override
384 m_default_queue->wait();
392 return new SyclRunQueueStream(
this, bi);
403 [[maybe_unused]]
DeviceId device_id)
override
411 void setCurrentDevice([[maybe_unused]]
DeviceId device_id)
final
413 ARCANE_SYCL_FUNC_NOT_HANDLED;
415 const IDeviceInfoList* deviceInfoList()
override {
return &m_device_info_list; }
417 void getPointerAttribute(
PointerAttribute& attribute,
const void* ptr)
override
419 sycl::usm::alloc sycl_mem_type = sycl::get_pointer_type(ptr, *m_default_context);
421 const void* host_ptr =
nullptr;
422 const void* device_ptr =
nullptr;
423 if (sycl_mem_type == sycl::usm::alloc::host) {
426 mem_type = ePointerMemoryType::Host;
431 else if (sycl_mem_type == sycl::usm::alloc::device) {
432 mem_type = ePointerMemoryType::Device;
435 else if (sycl_mem_type == sycl::usm::alloc::shared) {
436 mem_type = ePointerMemoryType::Managed;
444 _fillPointerAttribute(attribute, mem_type, device_id, ptr, device_ptr, host_ptr);
452 void fillDevicesAndSetDefaultQueue(
bool is_verbose);
453 sycl::queue& defaultQueue()
const {
return *m_default_queue; }
454 sycl::device& defaultDevice()
const {
return *m_default_device; }
459 global_default_queue = sycl::queue{};
465 std::unique_ptr<sycl::device> m_default_device;
466 std::unique_ptr<sycl::context> m_default_context;
467 std::unique_ptr<sycl::queue> m_default_queue;
471 void _init(sycl::device& device)
473 m_default_device = std::make_unique<sycl::device>(device);
474 m_default_queue = std::make_unique<sycl::queue>(device);
475 m_default_context = std::make_unique<sycl::context>(device);
486 sycl::device& d = runtime->defaultDevice();
489 auto queue_property = sycl::property::queue::in_order();
491 auto profiling_property = sycl::property::queue::enable_profiling();
492 sycl::property_list queue_properties(queue_property, profiling_property);
495 sycl::async_handler err_handler;
496 err_handler = _getAsyncHandler();
498 m_sycl_stream = std::make_unique<sycl::queue>(d, err_handler, queue_properties);
500 ARCANE_SYCL_FUNC_NOT_HANDLED;
501 m_sycl_stream = std::make_unique<sycl::queue>(d, err_handler, queue_properties);
508void SyclRunnerRuntime::
509fillDevicesAndSetDefaultQueue(
bool is_verbose)
512 for (
auto platform : sycl::platform::get_platforms()) {
513 std::cout <<
"Platform: "
514 <<
platform.get_info<sycl::info::platform::name>()
519 sycl::device device{ sycl::gpu_selector_v };
521 std::cout <<
"\nDevice: " << device.get_info<sycl::info::device::name>()
522 <<
"\nVersion=" << device.get_info<sycl::info::device::version>()
528 DeviceInfo device_info;
529 device_info.setDescription(
"No description info");
530 device_info.setDeviceId(DeviceId(0));
531 device_info.setName(device.get_info<sycl::info::device::name>());
532 m_device_info_list.addDevice(device_info);
560namespace Arcane::Accelerator::Sycl
566void SyclMemoryCopier::
575 sycl::queue& q = global_sycl_runtime.defaultQueue();
586extern "C" ARCCORE_EXPORT
void
590 using namespace Arcane::Accelerator::Sycl;
591 Arcane::Accelerator::impl::setUsingSYCLRuntime(
true);
592 Arcane::Accelerator::impl::setSYCLRunQueueRuntime(&global_sycl_runtime);
600 mrm->
setCopier(&global_sycl_memory_copier);
601 global_sycl_runtime.fillDevicesAndSetDefaultQueue(init_info.isVerbose());
602 global_default_queue = global_sycl_runtime.defaultQueue();
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
Identifiant d'un composant du système.
Information mémoire d'un accélérateur.
Interface d'une liste de devices.
Type opaque pour encapsuler une 'stream' native.
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 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.
void notifyBeginLaunchKernel(impl::RunCommandImpl &c) override
Notification avant le lancement de la commande.
eMemoryResource memoryResource() const override
Ressource mémoire fournie par l'allocateur.
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.
Implémentation d'une commande pour accélérateur.
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.