Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
CudaAcceleratorRuntime.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/* CudaAcceleratorRuntime.cc (C) 2000-2026 */
9/* */
10/* Runtime pour 'Cuda'. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/accelerator_native/CudaAccelerator.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 "arccore/accelerator_native/runtime/Cupti.h"
37
38#include <sstream>
39#include <unordered_map>
40#include <mutex>
41#include <algorithm>
42#include <iostream>
43
44#include <cuda.h>
45
46// Pour std::memset
47#include <cstring>
48
49#ifdef ARCCORE_HAS_CUDA_NVTOOLSEXT
50#include <nvtx3/nvToolsExt.h>
51#endif
52
53namespace Arcane::Accelerator::Cuda
54{
55using Impl::KernelLaunchArgs;
56
57namespace
58{
59 Int32 global_cupti_flush = 0;
60 CuptiInfo global_cupti_info;
61} // namespace
62
63/*---------------------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
65
66// À partir de CUDA 13, il existe un nouveau type cudaMemLocation
67// pour des méthodes telles que cudeMemAdvise ou cudaMemPrefetch
68#if defined(ARCCORE_USING_CUDA13_OR_GREATER)
69inline cudaMemLocation
70_getMemoryLocation(int device_id)
71{
72 cudaMemLocation mem_location;
73 mem_location.type = cudaMemLocationTypeDevice;
74 mem_location.id = device_id;
75 if (device_id == cudaCpuDeviceId)
76 mem_location.type = cudaMemLocationTypeHost;
77 else {
78 mem_location.type = cudaMemLocationTypeDevice;
79 mem_location.id = device_id;
80 }
81 return mem_location;
82}
83#else
84inline int
85_getMemoryLocation(int device_id)
86{
87 return device_id;
88}
89#endif
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
93
95{
96 public:
97
98 virtual ~ConcreteAllocator() = default;
99
100 public:
101
102 virtual cudaError_t _allocate(void** ptr, size_t new_size) = 0;
103 virtual cudaError_t _deallocate(void* ptr) = 0;
104};
105
106/*---------------------------------------------------------------------------*/
107/*---------------------------------------------------------------------------*/
108
109template <typename ConcreteAllocatorType>
110class UnderlyingAllocator
112{
113 public:
114
115 UnderlyingAllocator() = default;
116
117 public:
118
119 void* allocateMemory(Int64 size) final
120 {
121 void* out = nullptr;
122 ARCCORE_CHECK_CUDA(m_concrete_allocator._allocate(&out, size));
123 return out;
124 }
125 void freeMemory(void* ptr, [[maybe_unused]] Int64 size) final
126 {
127 ARCCORE_CHECK_CUDA_NOTHROW(m_concrete_allocator._deallocate(ptr));
128 }
129
130 void doMemoryCopy(void* destination, const void* source, Int64 size) final
131 {
132 ARCCORE_CHECK_CUDA(cudaMemcpy(destination, source, size, cudaMemcpyDefault));
133 }
134
135 eMemoryResource memoryResource() const final
136 {
137 return m_concrete_allocator.memoryResource();
138 }
139
140 public:
141
142 ConcreteAllocatorType m_concrete_allocator;
143};
144
145/*---------------------------------------------------------------------------*/
146/*---------------------------------------------------------------------------*/
147
148class UnifiedMemoryConcreteAllocator
149: public ConcreteAllocator
150{
151 public:
152
153 UnifiedMemoryConcreteAllocator()
154 {
155 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CUDA_USE_ALLOC_ATS", true))
156 m_use_ats = v.value();
157 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CUDA_MEMORY_HINT_ON_DEVICE", true))
158 m_use_hint_as_mainly_device = (v.value() != 0);
159 }
160
161 cudaError_t _deallocate(void* ptr) final
162 {
163 if (m_use_ats) {
164 ::free(ptr);
165 return cudaSuccess;
166 }
167 //std::cout << "CUDA_MANAGED_FREE ptr=" << ptr << "\n";
168 return ::cudaFree(ptr);
169 }
170
171 cudaError_t _allocate(void** ptr, size_t new_size) final
172 {
173 if (m_use_ats) {
174 *ptr = ::aligned_alloc(128, new_size);
175 }
176 else {
177 auto r = ::cudaMallocManaged(ptr, new_size, cudaMemAttachGlobal);
178 //std::cout << "CUDA_MANAGED_MALLOC ptr=" << (*ptr) << " size=" << new_size << "\n";
179 //if (new_size < 4000)
180 //std::cout << "STACK=" << platform::getStackTrace() << "\n";
181
182 if (r != cudaSuccess)
183 return r;
184
185 // Si demandé, indique qu'on préfère allouer sur le GPU.
186 // NOTE: Dans ce cas, on récupère le device actuel pour positionner la localisation
187 // préférée. Dans le cas où on utilise MemoryPool, cette allocation ne sera effectuée
188 // qu'une seule fois. Si le device par défaut pour un thread change au cours du calcul
189 // il y aura une incohérence. Pour éviter cela, on pourrait faire un cudaMemAdvise()
190 // pour chaque allocation (via _applyHint()) mais ces opérations sont assez couteuses
191 // et s'il y a beaucoup d'allocation il peut en résulter une perte de performance.
193 int device_id = 0;
194 void* p = *ptr;
195 cudaGetDevice(&device_id);
196 ARCCORE_CHECK_CUDA(cudaMemAdvise(p, new_size, cudaMemAdviseSetPreferredLocation, _getMemoryLocation(device_id)));
197 ARCCORE_CHECK_CUDA(cudaMemAdvise(p, new_size, cudaMemAdviseSetAccessedBy, _getMemoryLocation(cudaCpuDeviceId)));
198 }
199 }
200
201 return cudaSuccess;
202 }
203
204 constexpr eMemoryResource memoryResource() const { return eMemoryResource::UnifiedMemory; }
205
206 public:
207
208 bool m_use_ats = false;
211};
212
213/*---------------------------------------------------------------------------*/
214/*---------------------------------------------------------------------------*/
215
223class UnifiedMemoryCudaMemoryAllocator
224: public AcceleratorMemoryAllocatorBase
225{
226 public:
227 public:
228
229 UnifiedMemoryCudaMemoryAllocator()
230 : AcceleratorMemoryAllocatorBase("UnifiedMemoryCudaMemory", new UnderlyingAllocator<UnifiedMemoryConcreteAllocator>())
231 {
232 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CUDA_MALLOC_TRACE", true))
233 _setTraceLevel(v.value());
234 }
235
236 void initialize()
237 {
238 _doInitializeUVM(true);
239 }
240
241 public:
242
243 void notifyMemoryArgsChanged([[maybe_unused]] MemoryAllocationArgs old_args,
244 MemoryAllocationArgs new_args, AllocatedMemoryInfo ptr) final
245 {
246 void* p = ptr.baseAddress();
247 Int64 s = ptr.capacity();
248 if (p && s > 0)
249 _applyHint(ptr.baseAddress(), ptr.size(), new_args);
250 }
251
252 protected:
253
254 void _applyHint(void* p, size_t new_size, MemoryAllocationArgs args)
255 {
256 eMemoryLocationHint hint = args.memoryLocationHint();
257 // Utilise le device actif pour positionner le GPU par défaut
258 // On ne le fait que si le \a hint le nécessite pour éviter d'appeler
259 // cudaGetDevice() à chaque fois.
260 int device_id = 0;
262 cudaGetDevice(&device_id);
263 }
264 auto device_memory_location = _getMemoryLocation(device_id);
265 auto cpu_memory_location = _getMemoryLocation(cudaCpuDeviceId);
266
267 //std::cout << "SET_MEMORY_HINT name=" << args.arrayName() << " size=" << new_size << " hint=" << (int)hint << "\n";
269 ARCCORE_CHECK_CUDA(cudaMemAdvise(p, new_size, cudaMemAdviseSetPreferredLocation, device_memory_location));
270 ARCCORE_CHECK_CUDA(cudaMemAdvise(p, new_size, cudaMemAdviseSetAccessedBy, cpu_memory_location));
271 }
273 ARCCORE_CHECK_CUDA(cudaMemAdvise(p, new_size, cudaMemAdviseSetPreferredLocation, cpu_memory_location));
274 //ARCCORE_CHECK_CUDA(cudaMemAdvise(p, new_size, cudaMemAdviseSetAccessedBy, 0));
275 }
277 ARCCORE_CHECK_CUDA(cudaMemAdvise(p, new_size, cudaMemAdviseSetReadMostly, device_memory_location));
278 }
279 }
280 void _removeHint(void* p, size_t size, MemoryAllocationArgs args)
281 {
282 eMemoryLocationHint hint = args.memoryLocationHint();
283 if (hint == eMemoryLocationHint::None)
284 return;
285 int device_id = 0;
286 ARCCORE_CHECK_CUDA(cudaMemAdvise(p, size, cudaMemAdviseUnsetReadMostly, _getMemoryLocation(device_id)));
287 }
288
289 private:
290
291 bool m_use_ats = false;
292};
293
294/*---------------------------------------------------------------------------*/
295/*---------------------------------------------------------------------------*/
296
298: public ConcreteAllocator
299{
300 public:
301
302 cudaError_t _allocate(void** ptr, size_t new_size) final
303 {
304 return ::cudaMallocHost(ptr, new_size);
305 }
306 cudaError_t _deallocate(void* ptr) final
307 {
308 return ::cudaFreeHost(ptr);
309 }
310 constexpr eMemoryResource memoryResource() const { return eMemoryResource::HostPinned; }
311};
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
316class HostPinnedCudaMemoryAllocator
317: public AcceleratorMemoryAllocatorBase
318{
319 public:
320 public:
321
322 HostPinnedCudaMemoryAllocator()
323 : AcceleratorMemoryAllocatorBase("HostPinnedCudaMemory", new UnderlyingAllocator<HostPinnedConcreteAllocator>())
324 {
325 }
326
327 public:
328
329 void initialize()
330 {
332 }
333};
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
337
338class DeviceConcreteAllocator
339: public ConcreteAllocator
340{
341 public:
342
343 DeviceConcreteAllocator()
344 {
345 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CUDA_USE_ALLOC_ATS", true))
346 m_use_ats = v.value();
347 }
348
349 cudaError_t _allocate(void** ptr, size_t new_size) final
350 {
351 if (m_use_ats) {
352 // FIXME: it does not work on WIN32
353 *ptr = std::aligned_alloc(128, new_size);
354 if (*ptr)
355 return cudaSuccess;
356 return cudaErrorMemoryAllocation;
357 }
358 cudaError_t r = ::cudaMalloc(ptr, new_size);
359 //std::cout << "ALLOCATE_DEVICE ptr=" << (*ptr) << " size=" << new_size << " r=" << (int)r << "\n";
360 return r;
361 }
362 cudaError_t _deallocate(void* ptr) final
363 {
364 if (m_use_ats) {
365 std::free(ptr);
366 return cudaSuccess;
367 }
368 //std::cout << "FREE_DEVICE ptr=" << ptr << "\n";
369 return ::cudaFree(ptr);
370 }
371
372 constexpr eMemoryResource memoryResource() const { return eMemoryResource::Device; }
373
374 private:
375
376 bool m_use_ats = false;
377};
378
379/*---------------------------------------------------------------------------*/
380/*---------------------------------------------------------------------------*/
381
382class DeviceCudaMemoryAllocator
383: public AcceleratorMemoryAllocatorBase
384{
385
386 public:
387
388 DeviceCudaMemoryAllocator()
389 : AcceleratorMemoryAllocatorBase("DeviceCudaMemoryAllocator", new UnderlyingAllocator<DeviceConcreteAllocator>())
390 {
391 }
392
393 public:
394
395 void initialize()
396 {
398 }
399};
400
401/*---------------------------------------------------------------------------*/
402/*---------------------------------------------------------------------------*/
403
404namespace
405{
406 UnifiedMemoryCudaMemoryAllocator unified_memory_cuda_memory_allocator;
407 HostPinnedCudaMemoryAllocator host_pinned_cuda_memory_allocator;
408 DeviceCudaMemoryAllocator device_cuda_memory_allocator;
409} // namespace
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
414void initializeCudaMemoryAllocators()
415{
416 unified_memory_cuda_memory_allocator.initialize();
417 device_cuda_memory_allocator.initialize();
418 host_pinned_cuda_memory_allocator.initialize();
419}
420
421void finalizeCudaMemoryAllocators(ITraceMng* tm)
422{
423 unified_memory_cuda_memory_allocator.finalize(tm);
424 device_cuda_memory_allocator.finalize(tm);
425 host_pinned_cuda_memory_allocator.finalize(tm);
426}
427
428/*---------------------------------------------------------------------------*/
429/*---------------------------------------------------------------------------*/
430
431void arcaneCheckCudaErrors(const TraceInfo& ti, CUresult e)
432{
433 if (e == CUDA_SUCCESS)
434 return;
435 const char* error_name = nullptr;
436 CUresult e2 = cuGetErrorName(e, &error_name);
437 if (e2 != CUDA_SUCCESS)
438 error_name = "Unknown";
439
440 const char* error_message = nullptr;
441 CUresult e3 = cuGetErrorString(e, &error_message);
442 if (e3 != CUDA_SUCCESS)
443 error_message = "Unknown";
444
445 ARCCORE_FATAL("CUDA Error trace={0} e={1} name={2} message={3}",
446 ti, e, error_name, error_message);
447}
448
449/*---------------------------------------------------------------------------*/
450/*---------------------------------------------------------------------------*/
451
461{
462 public:
463
464 Int32 getNbThreadPerBlock(const void* kernel_ptr)
465 {
466 std::scoped_lock lock(m_mutex);
467 auto x = m_nb_thread_per_block_map.find(kernel_ptr);
468 if (x != m_nb_thread_per_block_map.end())
469 return x->second;
470 int min_grid_size = 0;
471 int computed_block_size = 0;
472 int wanted_shared_memory = 0;
473 cudaError_t r = cudaOccupancyMaxPotentialBlockSize(&min_grid_size, &computed_block_size, kernel_ptr, wanted_shared_memory);
474 if (r != cudaSuccess)
475 computed_block_size = 0;
476 int num_block_0 = 0;
477 cudaOccupancyMaxActiveBlocksPerMultiprocessor(&num_block_0, kernel_ptr, 256, wanted_shared_memory);
478 int num_block_1 = 0;
479 cudaOccupancyMaxActiveBlocksPerMultiprocessor(&num_block_1, kernel_ptr, 1024, wanted_shared_memory);
480
481 cudaFuncAttributes func_attr;
482 cudaFuncGetAttributes(&func_attr, kernel_ptr);
483 m_nb_thread_per_block_map[kernel_ptr] = computed_block_size;
484 std::cout << "ComputedBlockSize=" << computed_block_size << " n0=" << num_block_0 << " n1=" << num_block_1
485 << " min_grid_size=" << min_grid_size << " nb_reg=" << func_attr.numRegs;
486
487#if CUDART_VERSION >= 12040
488 // cudaFuncGetName n'est disponible qu'en 12.4
489 const char* func_name = nullptr;
490 cudaFuncGetName(&func_name, kernel_ptr);
491 std::cout << " name=" << func_name << "\n";
492#endif
493
494 return computed_block_size;
495 }
496
497 private:
498
499 std::unordered_map<const void*, Int32> m_nb_thread_per_block_map;
500 std::mutex m_mutex;
501};
502
503/*---------------------------------------------------------------------------*/
504/*---------------------------------------------------------------------------*/
505
506class CudaRunQueueStream
508{
509 public:
510
511 CudaRunQueueStream(Impl::IRunnerRuntime* runtime, const RunQueueBuildInfo& bi)
512 : m_runtime(runtime)
513 {
514 if (bi.isDefault())
515 ARCCORE_CHECK_CUDA(cudaStreamCreate(&m_cuda_stream));
516 else {
517 int priority = bi.priority();
518 ARCCORE_CHECK_CUDA(cudaStreamCreateWithPriority(&m_cuda_stream, cudaStreamDefault, priority));
519 }
520 }
521 ~CudaRunQueueStream() override
522 {
523 ARCCORE_CHECK_CUDA_NOTHROW(cudaStreamDestroy(m_cuda_stream));
524 }
525
526 public:
527
528 void notifyBeginLaunchKernel([[maybe_unused]] Impl::RunCommandImpl& c) override
529 {
530#ifdef ARCCORE_HAS_CUDA_NVTOOLSEXT
531 auto kname = c.kernelName();
532 if (kname.empty())
533 nvtxRangePush(c.traceInfo().name());
534 else
535 nvtxRangePush(kname.localstr());
536#endif
537 return m_runtime->notifyBeginLaunchKernel();
538 }
540 {
541#ifdef ARCCORE_HAS_CUDA_NVTOOLSEXT
542 nvtxRangePop();
543#endif
544 return m_runtime->notifyEndLaunchKernel();
545 }
546 void barrier() override
547 {
548 ARCCORE_CHECK_CUDA(cudaStreamSynchronize(m_cuda_stream));
549 if (global_cupti_flush > 0)
550 global_cupti_info.flush();
551 }
552 bool _barrierNoException() override
553 {
554 return (cudaStreamSynchronize(m_cuda_stream) != cudaSuccess);
555 }
556 void copyMemory(const MemoryCopyArgs& args) override
557 {
558 auto source_bytes = args.source().bytes();
559 auto r = cudaMemcpyAsync(args.destination().data(), source_bytes.data(),
560 source_bytes.size(), cudaMemcpyDefault, m_cuda_stream);
561 ARCCORE_CHECK_CUDA(r);
562 if (!args.isAsync())
563 barrier();
564 }
565 void prefetchMemory(const MemoryPrefetchArgs& args) override
566 {
567 auto src = args.source().bytes();
568 if (src.size() == 0)
569 return;
570 DeviceId d = args.deviceId();
571 int device = cudaCpuDeviceId;
572 if (!d.isHost())
573 device = d.asInt32();
574 //std::cout << "PREFETCH device=" << device << " host(id)=" << cudaCpuDeviceId
575 // << " size=" << args.source().size() << " data=" << src.data() << "\n";
576 auto mem_location = _getMemoryLocation(device);
577#if defined(ARCCORE_USING_CUDA13_OR_GREATER)
578 auto r = cudaMemPrefetchAsync(src.data(), src.size(), mem_location, 0, m_cuda_stream);
579#else
580 auto r = cudaMemPrefetchAsync(src.data(), src.size(), mem_location, m_cuda_stream);
581#endif
582 ARCCORE_CHECK_CUDA(r);
583 if (!args.isAsync())
584 barrier();
585 }
587 {
588 return Impl::NativeStream(&m_cuda_stream);
589 }
590
591 public:
592
593 cudaStream_t trueStream() const
594 {
595 return m_cuda_stream;
596 }
597
598 private:
599
600 Impl::IRunnerRuntime* m_runtime = nullptr;
601 cudaStream_t m_cuda_stream = nullptr;
602};
603
604/*---------------------------------------------------------------------------*/
605/*---------------------------------------------------------------------------*/
606
607class CudaRunQueueEvent
609{
610 public:
611
612 explicit CudaRunQueueEvent(bool has_timer)
613 {
614 if (has_timer)
615 ARCCORE_CHECK_CUDA(cudaEventCreate(&m_cuda_event));
616 else
617 ARCCORE_CHECK_CUDA(cudaEventCreateWithFlags(&m_cuda_event, cudaEventDisableTiming));
618 }
619 ~CudaRunQueueEvent() override
620 {
621 ARCCORE_CHECK_CUDA_NOTHROW(cudaEventDestroy(m_cuda_event));
622 }
623
624 public:
625
626 // Enregistre l'événement au sein d'une RunQueue
627 void recordQueue(Impl::IRunQueueStream* stream) final
628 {
629 auto* rq = static_cast<CudaRunQueueStream*>(stream);
630 ARCCORE_CHECK_CUDA(cudaEventRecord(m_cuda_event, rq->trueStream()));
631 }
632
633 void wait() final
634 {
635 ARCCORE_CHECK_CUDA(cudaEventSynchronize(m_cuda_event));
636 }
637
638 void waitForEvent(Impl::IRunQueueStream* stream) final
639 {
640 auto* rq = static_cast<CudaRunQueueStream*>(stream);
641 ARCCORE_CHECK_CUDA(cudaStreamWaitEvent(rq->trueStream(), m_cuda_event, cudaEventWaitDefault));
642 }
643
644 Int64 elapsedTime(IRunQueueEventImpl* start_event) final
645 {
646 // NOTE : Les événements doivent avoir été créés avec le timer activé
647 ARCCORE_CHECK_POINTER(start_event);
648 auto* true_start_event = static_cast<CudaRunQueueEvent*>(start_event);
649 float time_in_ms = 0.0;
650
651 // TODO: regarder si nécessaire
652 // ARCCORE_CHECK_CUDA(cudaEventSynchronize(m_cuda_event));
653
654 ARCCORE_CHECK_CUDA(cudaEventElapsedTime(&time_in_ms, true_start_event->m_cuda_event, m_cuda_event));
655 double x = time_in_ms * 1.0e6;
656 Int64 nano_time = static_cast<Int64>(x);
657 return nano_time;
658 }
659
660 bool hasPendingWork() final
661 {
662 cudaError_t v = cudaEventQuery(m_cuda_event);
663 if (v == cudaErrorNotReady)
664 return true;
665 ARCCORE_CHECK_CUDA(v);
666 return false;
667 }
668
669 private:
670
671 cudaEvent_t m_cuda_event;
672};
673
674/*---------------------------------------------------------------------------*/
675/*---------------------------------------------------------------------------*/
676
679{
680 public:
681
682 ~CudaRunnerRuntime() override = default;
683
684 public:
685
686 void notifyBeginLaunchKernel() override
687 {
688 ++m_nb_kernel_launched;
689 if (m_is_verbose)
690 std::cout << "BEGIN CUDA KERNEL!\n";
691 }
692 void notifyEndLaunchKernel() override
693 {
694 ARCCORE_CHECK_CUDA(cudaGetLastError());
695 if (m_is_verbose)
696 std::cout << "END CUDA KERNEL!\n";
697 }
698 void barrier() override
699 {
700 ARCCORE_CHECK_CUDA(cudaDeviceSynchronize());
701 }
702 eExecutionPolicy executionPolicy() const override
703 {
705 }
706 Impl::IRunQueueStream* createStream(const RunQueueBuildInfo& bi) override
707 {
708 return new CudaRunQueueStream(this, bi);
709 }
710 Impl::IRunQueueEventImpl* createEventImpl() override
711 {
712 return new CudaRunQueueEvent(false);
713 }
714 Impl::IRunQueueEventImpl* createEventImplWithTimer() override
715 {
716 return new CudaRunQueueEvent(true);
717 }
718 void setMemoryAdvice(ConstMemoryView buffer, eMemoryAdvice advice, DeviceId device_id) override
719 {
720 auto v = buffer.bytes();
721 const void* ptr = v.data();
722 size_t count = v.size();
723 int device = device_id.asInt32();
724 cudaMemoryAdvise cuda_advise;
725
726 if (advice == eMemoryAdvice::MostlyRead)
727 cuda_advise = cudaMemAdviseSetReadMostly;
729 cuda_advise = cudaMemAdviseSetPreferredLocation;
730 else if (advice == eMemoryAdvice::AccessedByDevice)
731 cuda_advise = cudaMemAdviseSetAccessedBy;
732 else if (advice == eMemoryAdvice::PreferredLocationHost) {
733 cuda_advise = cudaMemAdviseSetPreferredLocation;
734 device = cudaCpuDeviceId;
735 }
736 else if (advice == eMemoryAdvice::AccessedByHost) {
737 cuda_advise = cudaMemAdviseSetAccessedBy;
738 device = cudaCpuDeviceId;
739 }
740 else
741 return;
742 //std::cout << "MEMADVISE p=" << ptr << " size=" << count << " advise = " << cuda_advise << " id = " << device << "\n";
743 ARCCORE_CHECK_CUDA(cudaMemAdvise(ptr, count, cuda_advise, _getMemoryLocation(device)));
744 }
745 void unsetMemoryAdvice(ConstMemoryView buffer, eMemoryAdvice advice, DeviceId device_id) override
746 {
747 auto v = buffer.bytes();
748 const void* ptr = v.data();
749 size_t count = v.size();
750 int device = device_id.asInt32();
751 cudaMemoryAdvise cuda_advise;
752
753 if (advice == eMemoryAdvice::MostlyRead)
754 cuda_advise = cudaMemAdviseUnsetReadMostly;
756 cuda_advise = cudaMemAdviseUnsetPreferredLocation;
757 else if (advice == eMemoryAdvice::AccessedByDevice)
758 cuda_advise = cudaMemAdviseUnsetAccessedBy;
759 else if (advice == eMemoryAdvice::PreferredLocationHost) {
760 cuda_advise = cudaMemAdviseUnsetPreferredLocation;
761 device = cudaCpuDeviceId;
762 }
763 else if (advice == eMemoryAdvice::AccessedByHost) {
764 cuda_advise = cudaMemAdviseUnsetAccessedBy;
765 device = cudaCpuDeviceId;
766 }
767 else
768 return;
769 ARCCORE_CHECK_CUDA(cudaMemAdvise(ptr, count, cuda_advise, _getMemoryLocation(device)));
770 }
771
772 void setCurrentDevice(DeviceId device_id) final
773 {
774 Int32 id = device_id.asInt32();
775 if (!device_id.isAccelerator())
776 ARCCORE_FATAL("Device {0} is not an accelerator device", id);
777 ARCCORE_CHECK_CUDA(cudaSetDevice(id));
778 }
779
780 const IDeviceInfoList* deviceInfoList() final { return &m_device_info_list; }
781
782 void startProfiling() override
783 {
784 global_cupti_info.start();
785 }
786
787 void stopProfiling() override
788 {
789 global_cupti_info.stop();
790 }
791
792 bool isProfilingActive() override
793 {
794 return global_cupti_info.isActive();
795 }
796
797 void getPointerAttribute(PointerAttribute& attribute, const void* ptr) override
798 {
799 cudaPointerAttributes ca;
800 ARCCORE_CHECK_CUDA(cudaPointerGetAttributes(&ca, ptr));
801 // NOTE: le type Arcane 'ePointerMemoryType' a normalememt les mêmes valeurs
802 // que le type CUDA correspondant donc on peut faire un cast simple.
803 auto mem_type = static_cast<ePointerMemoryType>(ca.type);
804 _fillPointerAttribute(attribute, mem_type, ca.device,
805 ptr, ca.devicePointer, ca.hostPointer);
806 }
807
808 DeviceMemoryInfo getDeviceMemoryInfo(DeviceId device_id) override
809 {
810 int d = 0;
811 int wanted_d = device_id.asInt32();
812 ARCCORE_CHECK_CUDA(cudaGetDevice(&d));
813 if (d != wanted_d)
814 ARCCORE_CHECK_CUDA(cudaSetDevice(wanted_d));
815 size_t free_mem = 0;
816 size_t total_mem = 0;
817 ARCCORE_CHECK_CUDA(cudaMemGetInfo(&free_mem, &total_mem));
818 if (d != wanted_d)
819 ARCCORE_CHECK_CUDA(cudaSetDevice(d));
821 dmi.setFreeMemory(free_mem);
822 dmi.setTotalMemory(total_mem);
823 return dmi;
824 }
825
826 void pushProfilerRange(const String& name, Int32 color_rgb) override
827 {
828#ifdef ARCCORE_HAS_CUDA_NVTOOLSEXT
829 if (color_rgb >= 0) {
830 // NOTE: Il faudrait faire: nvtxEventAttributes_t eventAttrib = { 0 };
831 // mais cela provoque pleins d'avertissement de type 'missing initializer for member'
832 nvtxEventAttributes_t eventAttrib;
833 std::memset(&eventAttrib, 0, sizeof(nvtxEventAttributes_t));
834 eventAttrib.version = NVTX_VERSION;
835 eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE;
836 eventAttrib.colorType = NVTX_COLOR_ARGB;
837 eventAttrib.color = color_rgb;
838 eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII;
839 eventAttrib.message.ascii = name.localstr();
840 nvtxRangePushEx(&eventAttrib);
841 }
842 else
843 nvtxRangePush(name.localstr());
844#endif
845 }
846 void popProfilerRange() override
847 {
848#ifdef ARCCORE_HAS_CUDA_NVTOOLSEXT
849 nvtxRangePop();
850#endif
851 }
852
853 void finalize(ITraceMng* tm) override
854 {
855 finalizeCudaMemoryAllocators(tm);
856 }
857
858 KernelLaunchArgs computeKernalLaunchArgs(const KernelLaunchArgs& orig_args,
859 const void* kernel_ptr,
860 Int64 total_loop_size) override
861 {
862 Int32 shared_memory = orig_args.sharedMemorySize();
863 if (orig_args.isCooperative()) {
864 // En mode coopératif, s'assure qu'on ne lance pas plus de blocs
865 // que le maximum qui peut résider sur le GPU.
866 Int32 nb_thread = orig_args.nbThreadPerBlock();
867 Int32 nb_block = orig_args.nbBlockPerGrid();
868 int nb_block_per_sm = 0;
869 ARCCORE_CHECK_CUDA(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&nb_block_per_sm, kernel_ptr, nb_thread, shared_memory));
870
871 int max_block = static_cast<int>((nb_block_per_sm * m_multi_processor_count) * m_cooperative_ratio);
872 max_block = std::max(max_block, 1);
873 if (nb_block > max_block) {
874 KernelLaunchArgs modified_args(orig_args);
875 modified_args.setNbBlockPerGrid(max_block);
876 return modified_args;
877 }
878 return orig_args;
879 }
880
881 if (!m_use_computed_occupancy)
882 return orig_args;
883 if (shared_memory < 0)
884 shared_memory = 0;
885 // Pour l'instant, on ne fait pas de calcul si la mémoire partagée est non nulle.
886 if (shared_memory != 0)
887 return orig_args;
888 Int32 computed_block_size = m_occupancy_map.getNbThreadPerBlock(kernel_ptr);
889 if (computed_block_size == 0)
890 return orig_args;
891
892 // Ici, on utilise le nombre de threads par bloc pour avoir une
893 // occupation maximale.
894 KernelLaunchArgs modified_args(orig_args);
895 Int64 big_b = (total_loop_size + computed_block_size - 1) / computed_block_size;
896 int blocks_per_grid = CheckedConvert::toInt32(big_b);
897 modified_args.setNbBlockPerGrid(blocks_per_grid);
898 modified_args.setNbThreadPerBlock(computed_block_size);
899 return modified_args;
900 }
901
902 public:
903
904 void fillDevices(bool is_verbose);
905 void build()
906 {
907 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_USE_COMPUTED_OCCUPANCY", true))
908 m_use_computed_occupancy = v.value();
909 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_ACCELERATOR_COOPERATIVE_RATIO", true)) {
910 Int32 x = v.value();
911 x = std::clamp(x, 10, 100);
912 m_cooperative_ratio = x / 100.0;
913 }
914 }
915
916 private:
917
918 Int64 m_nb_kernel_launched = 0;
919 bool m_is_verbose = false;
920 bool m_use_computed_occupancy = false;
921 Int32 m_multi_processor_count = 0;
922 double m_cooperative_ratio = 1.0;
923 Impl::DeviceInfoList m_device_info_list;
924 OccupancyMap m_occupancy_map;
925};
926
927/*---------------------------------------------------------------------------*/
928/*---------------------------------------------------------------------------*/
929
930void CudaRunnerRuntime::
931fillDevices(bool is_verbose)
932{
933 int nb_device = 0;
934 ARCCORE_CHECK_CUDA(cudaGetDeviceCount(&nb_device));
935 std::ostream& omain = std::cout;
936 if (is_verbose)
937 omain << "ArcaneCUDA: Initialize Arcane CUDA runtime nb_available_device=" << nb_device << "\n";
938 for (int i = 0; i < nb_device; ++i) {
939 cudaDeviceProp dp;
940 cudaGetDeviceProperties(&dp, i);
941 int runtime_version = 0;
942 cudaRuntimeGetVersion(&runtime_version);
943 int driver_version = 0;
944 cudaDriverGetVersion(&driver_version);
945 std::ostringstream ostr;
946 std::ostream& o = ostr;
947 o << "Device " << i << " name=" << dp.name << "\n";
948 o << " Driver version = " << (driver_version / 1000) << "." << (driver_version % 1000) << "\n";
949 o << " Runtime version = " << (runtime_version / 1000) << "." << (runtime_version % 1000) << "\n";
950 o << " computeCapability = " << dp.major << "." << dp.minor << "\n";
951 o << " totalGlobalMem = " << dp.totalGlobalMem << "\n";
952 o << " sharedMemPerBlock = " << dp.sharedMemPerBlock << "\n";
953 o << " sharedMemPerMultiprocessor = " << dp.sharedMemPerMultiprocessor << "\n";
954 o << " sharedMemPerBlockOptin = " << dp.sharedMemPerBlockOptin << "\n";
955 o << " regsPerBlock = " << dp.regsPerBlock << "\n";
956 o << " warpSize = " << dp.warpSize << "\n";
957 o << " memPitch = " << dp.memPitch << "\n";
958 o << " maxThreadsPerBlock = " << dp.maxThreadsPerBlock << "\n";
959 o << " maxBlocksPerMultiProcessor = " << dp.maxBlocksPerMultiProcessor << "\n";
960 o << " maxThreadsPerMultiProcessor = " << dp.maxThreadsPerMultiProcessor << "\n";
961 o << " totalConstMem = " << dp.totalConstMem << "\n";
962 o << " cooperativeLaunch = " << dp.cooperativeLaunch << "\n";
963 o << " multiProcessorCount = " << dp.multiProcessorCount << "\n";
964 o << " integrated = " << dp.integrated << "\n";
965 o << " canMapHostMemory = " << dp.canMapHostMemory << "\n";
966 o << " directManagedMemAccessFromHost = " << dp.directManagedMemAccessFromHost << "\n";
967 o << " hostNativeAtomicSupported = " << dp.hostNativeAtomicSupported << "\n";
968 o << " pageableMemoryAccess = " << dp.pageableMemoryAccess << "\n";
969 o << " concurrentManagedAccess = " << dp.concurrentManagedAccess << "\n";
970 o << " pageableMemoryAccessUsesHostPageTables = " << dp.pageableMemoryAccessUsesHostPageTables << "\n";
971 o << " hostNativeAtomicSupported = " << dp.hostNativeAtomicSupported << "\n";
972 o << " maxThreadsDim = " << dp.maxThreadsDim[0] << " " << dp.maxThreadsDim[1]
973 << " " << dp.maxThreadsDim[2] << "\n";
974 o << " maxGridSize = " << dp.maxGridSize[0] << " " << dp.maxGridSize[1]
975 << " " << dp.maxGridSize[2] << "\n";
976 o << " pciInfo = " << dp.pciDomainID << " " << dp.pciBusID << " " << dp.pciDeviceID << "\n";
977 o << " memoryBusWitdh = " << dp.memoryBusWidth << " bits\n";
978
979 int clock_rate = 0;
980 ARCCORE_CHECK_CUDA(cudaDeviceGetAttribute(&clock_rate, cudaDevAttrClockRate, i));
981 o << " clockRate = " << (clock_rate / 1000) << " MHz\n";
982
983 int memory_clock_rate = 0;
984 ARCCORE_CHECK_CUDA(cudaDeviceGetAttribute(&memory_clock_rate, cudaDevAttrMemoryClockRate, i));
985 o << " memoryClockRate = " << (memory_clock_rate / 1000) << " MHz\n";
986
987 Real memory_bandwith = ((dp.memoryBusWidth * memory_clock_rate * 2.0) / 8.0) / 1.0e6;
988 o << " MemoryBandwith = " << memory_bandwith << " GB/s\n";
989
990#if !defined(ARCCORE_USING_CUDA13_OR_GREATER)
991 o << " deviceOverlap = " << dp.deviceOverlap << "\n";
992 o << " computeMode = " << dp.computeMode << "\n";
993 o << " kernelExecTimeoutEnabled = " << dp.kernelExecTimeoutEnabled << "\n";
994#endif
995
996 // TODO: On suppose que tous les GPUs sont les mêmes et donc
997 // que le nombre de SM par GPU est le même. Cela est utilisé pour
998 // calculer le nombre de blocs en mode coopératif.
999 m_multi_processor_count = dp.multiProcessorCount;
1000
1001 {
1002 int least_val = 0;
1003 int greatest_val = 0;
1004 ARCCORE_CHECK_CUDA(cudaDeviceGetStreamPriorityRange(&least_val, &greatest_val));
1005 o << " leastPriority = " << least_val << " greatestPriority = " << greatest_val << "\n";
1006 }
1007 std::ostringstream device_uuid_ostr;
1008 {
1009 CUdevice device;
1010 ARCCORE_CHECK_CUDA(cuDeviceGet(&device, i));
1011 CUuuid device_uuid;
1012 ARCCORE_CHECK_CUDA(cuDeviceGetUuid(&device_uuid, device));
1013 o << " deviceUuid=";
1014 Impl::printUUID(device_uuid_ostr, device_uuid.bytes);
1015 o << device_uuid_ostr.str();
1016 o << "\n";
1017 }
1018 String description(ostr.str());
1019 if (is_verbose)
1020 omain << description;
1021
1022 DeviceInfo device_info;
1023 device_info.setDescription(description);
1024 device_info.setDeviceId(DeviceId(i));
1025 device_info.setName(dp.name);
1026 device_info.setWarpSize(dp.warpSize);
1027 device_info.setUUIDAsString(device_uuid_ostr.str());
1028 device_info.setSharedMemoryPerBlock(static_cast<Int32>(dp.sharedMemPerBlock));
1029 device_info.setSharedMemoryPerMultiprocessor(static_cast<Int32>(dp.sharedMemPerMultiprocessor));
1030 device_info.setSharedMemoryPerBlockOptin(static_cast<Int32>(dp.sharedMemPerBlockOptin));
1031 device_info.setTotalConstMemory(static_cast<Int32>(dp.totalConstMem));
1032 device_info.setPCIDomainID(dp.pciDomainID);
1033 device_info.setPCIBusID(dp.pciBusID);
1034 device_info.setPCIDeviceID(dp.pciDeviceID);
1035 m_device_info_list.addDevice(device_info);
1036 }
1037
1038 Int32 global_cupti_level = 0;
1039
1040 // Regarde si on active Cupti
1041 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CUPTI_LEVEL", true))
1042 global_cupti_level = v.value();
1043 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CUPTI_FLUSH", true))
1044 global_cupti_flush = v.value();
1045 bool do_print_cupti = true;
1046 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CUPTI_PRINT", true))
1047 do_print_cupti = (v.value() != 0);
1048
1049 if (global_cupti_level > 0) {
1050#ifndef ARCCORE_HAS_CUDA_CUPTI
1051 ARCCORE_FATAL("Trying to enable CUPTI but Arcane is not compiled with cupti support");
1052#endif
1053 global_cupti_info.init(global_cupti_level, do_print_cupti);
1054 global_cupti_info.start();
1055 }
1056}
1057
1058/*---------------------------------------------------------------------------*/
1059/*---------------------------------------------------------------------------*/
1060
1062: public IMemoryCopier
1063{
1064 void copy(ConstMemoryView from, [[maybe_unused]] eMemoryResource from_mem,
1065 MutableMemoryView to, [[maybe_unused]] eMemoryResource to_mem,
1066 const RunQueue* queue) override
1067 {
1068 if (queue) {
1069 queue->copyMemory(MemoryCopyArgs(to.bytes(), from.bytes()).addAsync(queue->isAsync()));
1070 return;
1071 }
1072 // 'cudaMemcpyDefault' sait automatiquement ce qu'il faut faire en tenant
1073 // uniquement compte de la valeur des pointeurs. Il faudrait voir si
1074 // utiliser \a from_mem et \a to_mem peut améliorer les performances.
1075 ARCCORE_CHECK_CUDA(cudaMemcpy(to.data(), from.data(), from.bytes().size(), cudaMemcpyDefault));
1076 }
1077};
1078
1079/*---------------------------------------------------------------------------*/
1080/*---------------------------------------------------------------------------*/
1081
1082} // End namespace Arcane::Accelerator::Cuda
1083
1084using namespace Arcane;
1085
1086namespace
1087{
1088Accelerator::Cuda::CudaRunnerRuntime global_cuda_runtime;
1089Accelerator::Cuda::CudaMemoryCopier global_cuda_memory_copier;
1090
1091void _setAllocator(Accelerator::AcceleratorMemoryAllocatorBase* allocator)
1092{
1094 eMemoryResource mem = allocator->memoryResource();
1095 mrm->setAllocator(mem, allocator);
1096 mrm->setMemoryPool(mem, allocator->memoryPool());
1097}
1098
1099} // namespace
1100
1101/*---------------------------------------------------------------------------*/
1102/*---------------------------------------------------------------------------*/
1103
1104// Cette fonction est le point d'entrée utilisé lors du chargement
1105// dynamique de cette bibliothèque
1106extern "C" ARCCORE_EXPORT void
1107arcaneRegisterAcceleratorRuntimecuda(Arcane::Accelerator::RegisterRuntimeInfo& init_info)
1108{
1109 using namespace Arcane::Accelerator::Cuda;
1110 global_cuda_runtime.build();
1111 Accelerator::Impl::setUsingCUDARuntime(true);
1112 Accelerator::Impl::setCUDARunQueueRuntime(&global_cuda_runtime);
1113 initializeCudaMemoryAllocators();
1115 MemoryUtils::setAcceleratorHostMemoryAllocator(&unified_memory_cuda_memory_allocator);
1116 IMemoryResourceMngInternal* mrm = MemoryUtils::getDataMemoryResourceMng()->_internal();
1117 mrm->setIsAccelerator(true);
1118 _setAllocator(&unified_memory_cuda_memory_allocator);
1119 _setAllocator(&host_pinned_cuda_memory_allocator);
1120 _setAllocator(&device_cuda_memory_allocator);
1121 mrm->setCopier(&global_cuda_memory_copier);
1122 global_cuda_runtime.fillDevices(init_info.isVerbose());
1123}
1124
1125/*---------------------------------------------------------------------------*/
1126/*---------------------------------------------------------------------------*/
#define ARCCORE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCCORE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
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.
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.
void notifyBeginLaunchKernel(Impl::RunCommandImpl &c) override
Notification avant le lancement de la commande.
bool _barrierNoException() override
Barrière sans exception. Retourne true en cas d'erreur.
Impl::NativeStream nativeStream() override
Pointeur sur la structure interne dépendante de l'implémentation.
void prefetchMemory(const MemoryPrefetchArgs &args) override
Effectue un pré-chargement d'une zone mémoire.
void notifyEndLaunchKernel(Impl::RunCommandImpl &) override
Notification de fin de lancement de la commande.
void copyMemory(const MemoryCopyArgs &args) override
Effectue une copie entre deux zones mémoire.
Classe singleton pour gérer CUPTI.
Definition Cupti.h:38
Map contenant l'occupation idéale pour un kernel donné.
void * allocateMemory(Int64 size) final
Alloue un bloc pour size octets.
void freeMemory(void *ptr, Int64 size) final
Libère le bloc situé à l'adresse address contenant size octets.
bool m_use_hint_as_mainly_device
Si vrai, par défaut on considère toutes les allocations comme eMemoryLocationHint::MainlyDevice.
void notifyMemoryArgsChanged(MemoryAllocationArgs old_args, MemoryAllocationArgs new_args, AllocatedMemoryInfo ptr) final
Notifie du changement des arguments spécifiques à l'instance.
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.
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
Informations sur une zone mémoire allouée.
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.
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.
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.
ePointerMemoryType
Type de mémoire pour un pointeur.
eExecutionPolicy
Politique d'exécution pour un Runner.
@ CUDA
Politique d'exécution utilisant l'environnement CUDA.
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.
eMemoryLocationHint
Indices sur la localisation mémoire attendue.
@ MainlyHost
Indique que la donnée sera plutôt utilisée sur CPU.
@ HostAndDeviceMostlyRead
Indique que la donnée sera utilisée à la fois sur accélérateur et sur CPU et qu'elle ne sera pas souv...
@ MainlyDevice
Indique que la donnée sera plutôt utilisée sur accélérateur.
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.