18# ifndef ALPAKA_SYCL_NUM_MAX_SHARED_MEMORY_ALLOCATIONS
19# define ALPAKA_SYCL_NUM_MAX_SHARED_MEMORY_ALLOCATIONS 32u
22# ifndef SYCL_EXT_ONEAPI_MEMCPY2D
24 "SYCL_EXT_ONEAPI_MEMCPY2D is not defined. Extension https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/supported/sycl_ext_oneapi_memcpy2d.asciidoc is required!"
27namespace alpaka::onHost::internal
29 template<
typename T_Device,
typename T_Dest,
typename T_Extents>
31 struct Memset::Op<syclGeneric::Queue<T_Device>, T_Dest, T_Extents>
33 void operator()(syclGeneric::Queue<T_Device>& queue,
auto&& dest, uint8_t byteValue, T_Extents
const& extents)
36 sycl::queue sycl_queue =
queue.getNativeHandle();
40 if(extentMd.product() ==
size_t{0u})
44 auto* destPtr =
data(dest);
50 if constexpr(dim == 2u)
52 ev = sycl_queue.ext_oneapi_memset2d(
59 else if constexpr(dim >= 3u)
62 bool isContiguous =
true;
68 for(uint32_t d = dim - 2u; d >= 1u; --d)
69 isContiguous = isContiguous && (extentMd[d] * destPitch[d] == destPitch[d - 1u]);
77 alpaka::concepts::Vector<size_t, 2u>
auto mappedExtentMd = extentMd.template rshrink<2u>();
79 mappedExtentMd.y() = extentMd.eraseBack().product();
81 ev = memset2D<alpaka::trait::GetValueType_t<T_Dest>>(
89 destPitch.template rshrink<2u>());
94 auto repetitions = extentMd.template rshrink<dim - 2u>(dim - 3u);
95 auto destPitchJump = destPitch.template rshrink<dim - 2u>(dim - 3u);
97 ev = memset2D<alpaka::trait::GetValueType_t<T_Dest>>(
108 queue.setLastEvent(ev);
109 if(
queue.isBlocking())
126 template<
typename T_ValueType>
127 sycl::event memset2D(
128 sycl::queue& sycl_queue,
130 alpaka::concepts::Vector<size_t>
auto const& repetitions,
131 alpaka::concepts::Vector<size_t>
auto const& destPitchJump,
132 alpaka::concepts::Vector<size_t>
auto const& extentMd,
134 alpaka::concepts::Vector<size_t>
auto const& destPitchesOriginal)
const
147 sycl_queue.ext_oneapi_memset2d(
148 reinterpret_cast<uint8_t*
>(destPtr) + (idx * destPitchJump).sum(),
149 destPitchesOriginal.y(),
151 extentMd.x() *
sizeof(T_ValueType),
157 ev = sycl_queue.ext_oneapi_memset2d(
158 reinterpret_cast<uint8_t*
>(destPtr) + (idx * destPitchJump).sum(),
159 destPitchesOriginal.y(),
161 extentMd.x() *
sizeof(T_ValueType),
169 template<
typename T_Device,
typename T_Dest,
typename T_Source,
typename T_Extents>
171 struct internal::Memcpy::Op<syclGeneric::Queue<T_Device>, T_Dest, T_Source, T_Extents>
179 syclGeneric::Queue<T_Device>& queue,
182 T_Extents
const& extents)
const requires std::same_as<
ALPAKA_TYPEOF(dest), T_Dest>
184 sycl::queue sycl_queue =
queue.getNativeHandle();
188 if(extentMd.product() ==
size_t{0u})
191 auto* destPtr =
data(dest);
193 auto const* srcPtr =
data(src);
200 if constexpr(dim == 2u)
202 ev = sycl_queue.ext_oneapi_memcpy2d(
210 else if constexpr(dim >= 3u)
213 bool isContiguous =
true;
219 for(uint32_t d = dim - 2u; d >= 1u; --d)
221 isContiguous = isContiguous && (extentMd[d] * destPitch[d] == destPitch[d - 1u])
222 && (extentMd[d] * srcPitch[d] == srcPitch[d - 1u]);
231 alpaka::concepts::Vector<size_t, 2u>
auto mappedExtentMd = extentMd.template rshrink<2u>();
233 mappedExtentMd.y() = extentMd.eraseBack().product();
236 ev = memcopy2D<alpaka::trait::GetValueType_t<T_Dest>>(
239 VecIdxType::fill(1u),
240 VecIdxType::fill(0u),
241 VecIdxType::fill(0u),
244 destPitch.template rshrink<2u>(),
246 srcPitch.template rshrink<2u>());
251 auto repetitions = extentMd.template rshrink<dim - 2u>(dim - 3u);
252 auto srcPitchJump = srcPitch.template rshrink<dim - 2u>(dim - 3u);
253 auto destPitchJump = destPitch.template rshrink<dim - 2u>(dim - 3u);
255 ev = memcopy2D<alpaka::trait::GetValueType_t<T_Dest>>(
268 queue.setLastEvent(ev);
269 if(
queue.isBlocking())
290 template<
typename T_ValueType>
291 sycl::event memcopy2D(
292 sycl::queue& sycl_queue,
293 alpaka::concepts::Vector<size_t>
auto const& repetitions,
294 alpaka::concepts::Vector<size_t>
auto const& destPitchJump,
295 alpaka::concepts::Vector<size_t>
auto const& srcPitchJump,
296 alpaka::concepts::Vector<size_t>
auto const& extentMd,
298 alpaka::concepts::Vector<size_t>
auto const& destPitchesOriginal,
300 alpaka::concepts::Vector<size_t>
auto const& srcPitchesOriginal)
const
317 sycl_queue.ext_oneapi_memcpy2d(
318 reinterpret_cast<uint8_t*
>(destPtr) + (idx * destPitchJump).sum(),
319 destPitchesOriginal.y(),
320 reinterpret_cast<uint8_t const*
>(srcPtr) + (idx * srcPitchJump).sum(),
321 srcPitchesOriginal.y(),
322 extentMd.x() *
sizeof(T_ValueType),
328 ev = sycl_queue.ext_oneapi_memcpy2d(
329 reinterpret_cast<uint8_t*
>(destPtr) + (idx * destPitchJump).sum(),
330 destPitchesOriginal.y(),
331 reinterpret_cast<uint8_t const*
>(srcPtr) + (idx * srcPitchJump).sum(),
332 srcPitchesOriginal.y(),
333 extentMd.x() *
sizeof(T_ValueType),
343 template<
typename T_Device,
typename T_Source,
typename T_Storage,
typename T>
344 struct internal::MemcpyDeviceGlobal::
345 Op<syclGeneric::Queue<T_Device>, onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T>, T_Source>
348 syclGeneric::Queue<T_Device>& queue,
349 onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T> dest,
353 sycl::queue sycl_queue =
queue.getNativeHandle();
354 void const* srcPtr{
nullptr};
360 queue.setLastEvent(ev);
361 if(
queue.isBlocking())
367 template<
typename T_Device,
typename T_Dest,
typename T_Storage,
typename T>
368 struct internal::MemcpyDeviceGlobal::
369 Op<syclGeneric::Queue<T_Device>, T_Dest, onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T>>
372 syclGeneric::Queue<T_Device>& queue,
374 onAcc::internal::GlobalDeviceMemoryWrapper<T_Storage, T> source)
const
377 sycl::queue sycl_queue =
queue.getNativeHandle();
378 void* destPtr{
nullptr};
384 queue.setLastEvent(ev);
385 if(
queue.isBlocking())
390 template<
typename T_Device,
typename T_Dest,
typename T_Value,
typename T_Extents>
392 struct internal::Fill::Op<syclGeneric::Queue<T_Device>, T_Dest, T_Value, T_Extents>
395 syclGeneric::Queue<T_Device>& queue,
397 T_Value elementValue,
398 T_Extents
const& extents)
const
405 alpaka::internal::generic::fill(
408 dataView.getSubView(extents),
415 template<alpaka::concepts::Vector TVec>
416 inline constexpr auto vecToSyclRange(TVec vec)
418 constexpr auto dim = std::decay_t<TVec>::dim();
419 return [&vec]<
auto... I>(std::index_sequence<I...>)
421 {
return sycl::range<dim>(vec[I]...); }(std::make_index_sequence<dim>{});
424 template<alpaka::concepts::Vector T_NumBlocks, alpaka::concepts::Vector T_NumThreads>
425 struct OptimizedThreadSpec
427 using NumBlocksVecType =
typename T_NumBlocks::UniVec;
428 using NumThreadsVecType = T_NumThreads;
430 static consteval uint32_t dim()
432 return T_NumThreads::dim();
435 constexpr OptimizedThreadSpec(T_NumBlocks
const&, T_NumThreads
const&)
445 template<onHost::concepts::ThreadSpec T_ThreadSpec>
446 inline constexpr auto getWorkerDescription(T_ThreadSpec
const& threadSpec)
448 constexpr uint32_t dim = T_ThreadSpec::dim();
450 constexpr uint32_t syclDim = dim >= 4u ? 1u : dim;
452 sycl::nd_range<syclDim> gridRange;
454 if constexpr(T_ThreadSpec::dim() >= 4u)
456 gridRange = sycl::nd_range<syclDim>{
457 (threadSpec.getNumBlocks() * threadSpec.getNumThreads()).product(),
458 threadSpec.getNumThreads().product()};
462 gridRange = sycl::nd_range<T_ThreadSpec::dim()>{
463 detail::vecToSyclRange(threadSpec.getNumBlocks() * threadSpec.getNumThreads()),
464 detail::vecToSyclRange(threadSpec.getNumThreads())};
467 using ThreadSpecType = std::conditional_t<
470 detail::OptimizedThreadSpec<
474 auto optimizedThreadSpec = ThreadSpecType(threadSpec.getNumBlocks(), threadSpec.getNumThreads());
475 return std::make_pair(gridRange, optimizedThreadSpec);
484 template<u
int32_t T_dim, u
int32_t T_warpSize, u
int32_t T_isVal
id>
485 struct EnqueueKernelWithWarpSize
490 auto const& kernelBundle,
491 auto const& st_shared_accessor,
492 auto const& dyn_shared_accessor,
493 auto const& optimizedThreadSpec,
498 [kernelBundle, st_shared_accessor, dyn_shared_accessor, optimizedThreadSpec, args...](
499 sycl::nd_item<T_dim> work_item) [[sycl::reqd_sub_group_size(T_warpSize)]]
501 onAcc::oneApi::StaticSharedMemory ssm(st_shared_accessor);
502 onAcc::syclGeneric::DynamicSharedMemory dsm(dyn_shared_accessor);
504 static_assert(T_dim > 0);
505 static_assert(T_dim <= 3,
"more the 3 dimensions are not supported");
506 auto acc = onAcc::Acc{Dict{
507 DictEntry(layer::block, onAcc::syclGeneric::BlockLayer{work_item, optimizedThreadSpec}),
508 DictEntry(layer::thread, onAcc::syclGeneric::ThreadLayer{work_item, optimizedThreadSpec}),
509 DictEntry(action::threadBlockSync, onAcc::syclGeneric::Sync{work_item}),
510 DictEntry(layer::shared, std::ref(ssm)),
511 DictEntry(layer::dynShared, std::ref(dsm)),
512 DictEntry(object::dynSharedMemBytes, dsm.byte_size()),
520 template<u
int32_t T_dim, u
int32_t T_warpSize>
521 struct EnqueueKernelWithWarpSize<T_dim, T_warpSize, 0u>
524 [[maybe_unused]] sycl::handler& cgh,
525 [[maybe_unused]]
auto gridRange,
526 [[maybe_unused]]
auto const& kernelBundle,
527 [[maybe_unused]]
auto const& st_shared_accessor,
528 [[maybe_unused]]
auto const& dyn_shared_accessor,
529 [[maybe_unused]]
auto const& optimizedThreadSpec,
530 [[maybe_unused]]
auto... args)
533 "Dynamic evaluated warp size on host does not match the compile time warp size ( macro "
534 "ALPAKA_SYCL_SUBGROUP_SIZE) evaluated in the "
535 "kernel. Update the definition of ALPAKA_SYCL_SUBGROUP_SIZE section and check the trait "
536 "Warpsize::Dispatch<>.");
549 Kernel<syclGeneric::Queue<T_Device>, ThreadSpec<T_NumBlocks, T_NumThreads, T_Executor>, T_KernelBundle>
552 syclGeneric::Queue<T_Device>& queue,
553 ThreadSpec<T_NumBlocks, T_NumThreads, T_Executor>
const& threadSpec,
554 T_KernelBundle
const& kernelBundle)
const
558 "'exec::anyExecutor' can not be used to enqueue an kernel.");
561 constexpr auto st_shared_mem_bytes = onAcc::oneApi::StaticSharedMemory::sizeLookupBufferInBytes(
562 ALPAKA_SYCL_NUM_MAX_SHARED_MEMORY_ALLOCATIONS);
564 u_int32_t blockDynSharedMemBytes
565 = std::max(u_int32_t(1), onHost::getDynSharedMemBytes(threadSpec, kernelBundle));
567 st_shared_mem_bytes + blockDynSharedMemBytes
568 <=
queue.m_device->getNativeHandle().first.template get_info<sycl::info::device::local_mem_size>());
570 sycl::event ev =
queue.dispatchWarpSize(
571 [&](
auto warpSize)
requires std::same_as<
572 std::integral_constant<
577 return queue.m_queue.submit(
578 [warpSize, threadSpec, kernelBundle, blockDynSharedMemBytes](sycl::handler& cgh)
580 using ApiType =
decltype(
getApi(queue));
583 auto st_shared_accessor
584 = sycl::local_accessor<std::byte>{sycl::range<1>{st_shared_mem_bytes}, cgh};
586 auto dyn_shared_accessor
587 = sycl::local_accessor<std::byte>{sycl::range<1>{blockDynSharedMemBytes}, cgh};
589 auto workerDesc = detail::getWorkerDescription(threadSpec);
590 auto optimizedThreadSpec = workerDesc.second;
591 constexpr uint32_t syclDim = workerDesc.first.dimensions;
594 detail::EnqueueKernelWithWarpSize<syclDim, w, ALPAKA_SYCL_SUBGROUP_SIZE & w>::call(
601 DictEntry(object::api, ApiType{}),
602 DictEntry(object::deviceKind, DeviceKindType{}),
603 DictEntry(object::exec, T_Executor{}),
604 DictEntry(object::launchedWidthFrameSpec, std::bool_constant<false>{}),
605 DictEntry(object::warpSize, warpSize));
609 queue.setLastEvent(ev);
610 if(
queue.isBlocking())
622 Kernel<syclGeneric::Queue<T_Device>, FrameSpec<T_NumFrames, T_FrameExtents, T_Executor>, T_KernelBundle>
625 syclGeneric::Queue<T_Device>& queue,
626 FrameSpec<T_NumFrames, T_FrameExtents, T_Executor>
const& frameSpec,
627 T_KernelBundle
const& kernelBundle)
const
631 "'exec::anyExecutor' can not be used to enqueue an kernel.");
634 auto const threadBlocking = internal::adjustThreadSpec(*
queue.m_device.get(), frameSpec, kernelBundle);
636 constexpr auto st_shared_mem_bytes = onAcc::oneApi::StaticSharedMemory::sizeLookupBufferInBytes(
637 ALPAKA_SYCL_NUM_MAX_SHARED_MEMORY_ALLOCATIONS);
640 u_int32_t blockDynSharedMemBytes
641 = std::max(u_int32_t(1), onHost::getDynSharedMemBytes(threadBlocking, kernelBundle));
644 st_shared_mem_bytes + blockDynSharedMemBytes
645 <=
queue.m_device->getNativeHandle().first.template get_info<sycl::info::device::local_mem_size>());
647 sycl::event ev =
queue.dispatchWarpSize(
648 [&](
auto warpSize)
requires std::same_as<
649 std::integral_constant<
654 return queue.m_queue.submit(
655 [warpSize, threadBlocking, kernelBundle, blockDynSharedMemBytes](sycl::handler& cgh)
657 using ApiType =
decltype(
getApi(queue));
659 auto st_shared_accessor
660 = sycl::local_accessor<std::byte>{sycl::range<1>{st_shared_mem_bytes}, cgh};
661 auto dyn_shared_accessor
662 = sycl::local_accessor<std::byte>{sycl::range<1>{blockDynSharedMemBytes}, cgh};
664 auto workerDesc = detail::getWorkerDescription(threadBlocking);
665 auto optimizedThreadSpec = workerDesc.second;
666 constexpr uint32_t syclDim = workerDesc.first.dimensions;
670 detail::EnqueueKernelWithWarpSize<syclDim, w, ALPAKA_SYCL_SUBGROUP_SIZE & w>::call(
677 DictEntry(object::api, ApiType{}),
678 DictEntry(object::deviceKind, DeviceKindType{}),
679 DictEntry(object::exec, T_Executor{}),
680 DictEntry(object::launchedWidthFrameSpec, std::bool_constant<true>{}),
681 DictEntry(object::warpSize, warpSize));
684 if(
queue.isBlocking())
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Concept to check for an executor.
Concept to check if a type is a KernelBundle.
Concept to check if a type is a vector.
#define ALPAKA_LOG_FUNCTION(logLvl)
Log the entry and exit of a scope.
constexpr AnyExecutor anyExecutor
Automatic executor selection.
constexpr auto defaultExecutor(internal::concepts::DeviceHandle auto deviceHandle)
Select a default executor for the given device.
void fill(Queue< T_Device, T_QueueKind > const &queue, auto &&dest, T_Value elementValue)
fill memory element wise
decltype(auto) data(auto &&any)
pointer to data of an object
decltype(auto) getPitches(auto &&any)
Object pitches.
typename GetValueType< T >::type GetValueType_t
constexpr uint32_t getDim_v
constexpr decltype(auto) getExecutor(auto &&any)
Get the executor associated with an object.
auto * toVoidPtr(T inPtr)
Cast a pointer that may or may not point to volatile memory to a (void*) or (void const*).
constexpr decltype(auto) getDeviceKind(auto &&any)
Get the device type of an object.
constexpr decltype(auto) getApi(auto &&any)
Get the API an object depends on.
constexpr auto makeView(auto &&anyWithApi, T_ValueType *pointer, concepts::Vector auto const &extents, T_MemAlignment const memAlignment=T_MemAlignment{})
constexpr decltype(auto) pCast(auto &&input)
Performs a static_cast on the storage type of combined data type.